Shell: enforce the maximum number of operation per block

This commit is contained in:
Grégoire Henry 2017-11-19 15:07:59 +01:00 committed by Grégoire
parent 3c06879deb
commit 84a2f1ee29
15 changed files with 129 additions and 51 deletions

View File

@ -392,6 +392,7 @@ go_alpha_go() {
activate \
protocol ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK \
with fitness 1 \
and passes 1 \
and key dictator
}

View File

@ -207,6 +207,7 @@ activate_alpha() {
-block genesis \
activate protocol ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK \
with fitness 1 \
and passes 1 \
and key dictator
}

View File

@ -27,7 +27,7 @@ add_sandboxed_bootstrap_identities | sed -e 's/^/## /' 1>&2
cat <<EOF
if type tezos-client-reset >/dev/null 2>&1 ; then tezos-client-reset; fi ;
alias tezos-client="$client" ;
alias tezos-activate-alpha="$client -block genesis activate protocol ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK with fitness 1 and key dictator" ;
alias tezos-activate-alpha="$client -block genesis activate protocol ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK with fitness 1 and passes 1 and key dictator" ;
alias tezos-client-reset="rm -rf \"$client_dir\"; unalias tezos-client tezos-activate-alpha tezos-client-reset" ;
alias tezos-autocomplete="source \"$script_dir/bash-completion.sh\"" ;
trap tezos-client-reset EXIT ;

View File

@ -31,7 +31,7 @@ let forge_block
let proto_level =
match command with
| Data.Command.Activate _ -> 1
| Data.Command.Activate_testnet (_,_) -> 0 in
| Data.Command.Activate_testnet _ -> 0 in
call_service1 rpc_config
Services.Forge.block block
((net_id, Int32.succ pred.level, proto_level,
@ -43,13 +43,18 @@ let bake rpc_config ?timestamp block command fitness seckey =
forge_block
rpc_config ?timestamp block bi.net_id command fitness >>=? fun blk ->
let signed_blk = Environment.Ed25519.Signature.append seckey blk in
Client_node_rpcs.inject_block rpc_config signed_blk [[]]
Client_node_rpcs.inject_block rpc_config signed_blk []
let int64_parameter =
(Cli_entries.parameter (fun _ p ->
try return (Int64.of_string p)
with _ -> failwith "Cannot read int64"))
let int_parameter =
(Cli_entries.parameter (fun _ p ->
try return (int_of_string p)
with _ -> failwith "Cannot read int"))
let commands () =
let open Cli_entries in
let args =
@ -71,15 +76,20 @@ let commands () =
@@ param ~name:"fitness"
~desc:"Hardcoded fitness of the first block (integer)"
int64_parameter
@@ prefixes [ "and" ; "passes" ]
@@ param ~name:"passes"
~desc:"Hardcoded number of validation passes (integer)"
int_parameter
@@ prefixes [ "and" ; "key" ]
@@ Client_keys.Secret_key.source_param
~name:"password" ~desc:"Dictator's key"
@@ stop)
begin fun timestamp hash fitness seckey cctxt ->
begin fun timestamp hash fitness validation_passes seckey cctxt ->
let fitness =
Tezos_embedded_raw_protocol_alpha.Fitness_repr.from_int64 fitness in
bake cctxt.rpc_config ?timestamp cctxt.config.block
(Activate hash) fitness seckey >>=? fun hash ->
(Activate { protocol = hash ; validation_passes })
fitness seckey >>=? fun hash ->
cctxt.answer "Injected %a" Block_hash.pp_short hash >>= fun () ->
return ()
end ;
@ -92,15 +102,21 @@ let commands () =
@@ param ~name:"fitness"
~desc:"Hardcoded fitness of the first block (integer)"
int64_parameter
@@ prefixes [ "and" ; "passes" ]
@@ param ~name:"passes"
~desc:"Hardcoded number of validation passes (integer)"
int_parameter
@@ prefixes [ "and" ; "key" ]
@@ Environment.Ed25519.Secret_key.param
~name:"password" ~desc:"Dictator's key"
@@ stop)
begin fun timestamp hash fitness seckey cctxt ->
begin fun timestamp hash fitness validation_passes seckey cctxt ->
let fitness =
Tezos_embedded_raw_protocol_alpha.Fitness_repr.from_int64 fitness in
bake cctxt.rpc_config ?timestamp cctxt.config.block
(Activate_testnet (hash, Int64.mul 24L 3600L))
(Activate_testnet { protocol = hash ;
validation_passes ;
delay = Int64.mul 24L 3600L })
fitness seckey >>=? fun hash ->
cctxt.answer "Injected %a" Block_hash.pp_short hash >>= fun () ->
return ()

View File

@ -50,6 +50,7 @@ type block_error =
timestamp: Time.t ;
}
| Unexpected_number_of_validation_passes of int (* uint8 *)
| Too_many_operations of { pass: int; found: int; max: int }
let block_error_encoding =
let open Data_encoding in
@ -131,6 +132,18 @@ let block_error_encoding =
| Unexpected_number_of_validation_passes n -> Some ((), n)
| _ -> None)
(fun ((), n) -> Unexpected_number_of_validation_passes n) ;
case
(obj4
(req "error" (constant "too_many_operations"))
(req "validation_pass" uint8)
(req "found" uint16)
(req "max" uint16))
(function
| Too_many_operations { pass ; found ; max } ->
Some ((), pass, found, max)
| _ -> None)
(fun ((), pass, found, max) ->
Too_many_operations { pass ; found ; max }) ;
]
let pp_block_error ppf = function
@ -183,6 +196,10 @@ let pp_block_error ppf = function
Format.fprintf ppf
"Invalid number of validation passes (found: %d)"
n
| Too_many_operations { pass ; found ; max } ->
Format.fprintf ppf
"Too many operations in validation pass %d (found: %d, max: %d)"
pass found max
type error +=
| Invalid_block of
@ -263,7 +280,8 @@ let () =
Inconsistent_operations_hash { block ; expected ; found })
let check_header
(pred_header: Block_header.t) hash (header: Block_header.t) =
(pred: State.Block.t) hash (header: Block_header.t) =
let pred_header = State.Block.header pred in
fail_unless
(Int32.succ pred_header.shell.level = header.shell.level)
(invalid_block hash @@
@ -276,7 +294,8 @@ let check_header
Fitness.(pred_header.shell.fitness < header.shell.fitness)
(invalid_block hash Non_increasing_fitness) >>=? fun () ->
fail_unless
(header.shell.validation_passes <= 1) (* FIXME to be found in Proto *)
(header.shell.validation_passes =
List.length (State.Block.max_number_of_operations pred))
(invalid_block hash
(Unexpected_number_of_validation_passes header.shell.validation_passes)
) >>=? fun () ->
@ -320,7 +339,14 @@ let apply_block
operations =
let pred_header = State.Block.header pred
and pred_hash = State.Block.hash pred in
check_header pred_header hash header >>=? fun () ->
check_header pred hash header >>=? fun () ->
iteri2_p
(fun i ops max ->
fail_unless
(List.length ops <= max)
(invalid_block hash @@
Too_many_operations { pass = i + 1 ; found = List.length ops ; max }))
operations (State.Block.max_number_of_operations pred) >>=? fun () ->
let operation_hashes = List.map (List.map Operation.hash) operations in
check_liveness net_state pred hash operation_hashes operations >>=? fun () ->
map2_s (map2_s begin fun op_hash raw ->

View File

@ -26,6 +26,7 @@ type block_error =
timestamp: Time.t ;
}
| Unexpected_number_of_validation_passes of int (* uint8 *)
| Too_many_operations of { pass: int; found: int; max: int }
type error +=
| Invalid_block of

View File

@ -153,16 +153,17 @@ let create
else
Lwt.return_none)
(Operation_hash.Map.bindings ops) >>= fun rops ->
(Lwt.return !validation_state >>=? fun validation_state ->
(prevalidate validation_state ~sort:true rops >>= return)) >>= function
| Ok (state, r) -> Lwt.return (Ok state, r)
match !validation_state with
| Ok validation_state ->
prevalidate validation_state ~sort:true rops >>= fun (state, r) ->
Lwt.return (Ok state, r)
| Error err ->
let r =
{ empty_result with
branch_delayed =
Operation_hash.Map.fold
(fun h op m -> Operation_hash.Map.add h (op, err) m)
ops Operation_hash.Map.empty ; } in
List.fold_left
(fun m (h, op) -> Operation_hash.Map.add h (op, err) m)
Operation_hash.Map.empty rops ; } in
Lwt.return (!validation_state, r)
end >>= fun (state, r) ->
let filter_out s m =

View File

@ -11,10 +11,17 @@ module Command = struct
type t =
(* Activate a protocol *)
| Activate of Protocol_hash.t
| Activate of {
protocol: Protocol_hash.t ;
validation_passes: int ;
}
(* Activate a protocol as a testnet *)
| Activate_testnet of Protocol_hash.t * Int64.t
| Activate_testnet of {
protocol: Protocol_hash.t ;
validation_passes: int ;
delay: Int64.t ;
}
let mk_case name args =
let open Data_encoding in
@ -30,18 +37,28 @@ module Command = struct
union ~tag_size:`Uint8 [
case ~tag:0
(mk_case "activate"
(obj1
(req "hash" Protocol_hash.encoding)))
(function (Activate hash) -> Some hash | _ -> None)
(fun hash -> Activate hash) ;
case ~tag:1
(mk_case "activate_testnet"
(obj2
(req "hash" Protocol_hash.encoding)
(req "validity_time" int64)))
(function (Activate_testnet (hash, delay)) -> Some (hash, delay)
(req "validation_passes" uint8)
))
(function
| Activate { protocol ; validation_passes } ->
Some (protocol, validation_passes)
| _ -> None)
(fun (hash, delay) -> Activate_testnet (hash, delay)) ;
(fun (protocol, validation_passes) ->
Activate { protocol ; validation_passes }) ;
case ~tag:1
(mk_case "activate_testnet"
(obj3
(req "hash" Protocol_hash.encoding)
(req "validation_passes" uint8)
(req "validity_time" int64)))
(function
| Activate_testnet { protocol ; validation_passes ; delay } ->
Some (protocol, validation_passes, delay)
| _ -> None)
(fun (protocol, validation_passes, delay) ->
Activate_testnet { protocol ; validation_passes ; delay }) ;
]
let signed_encoding =

View File

@ -47,7 +47,9 @@ type block = {
let max_block_length =
Data_encoding.Binary.length
Data.Command.encoding
(Activate_testnet (Protocol_hash.hash_bytes [], 0L))
(Activate_testnet { protocol = Protocol_hash.hash_bytes [] ;
validation_passes = 0 ;
delay = 0L })
+
begin
match Data_encoding.Binary.fixed_length Ed25519.Signature.encoding with
@ -89,22 +91,25 @@ let begin_application
check_signature ctxt block >>=? fun () ->
let fitness = raw_block.shell.fitness in
match block.command with
| Data.Command.Activate hash ->
| Data.Command.Activate { protocol = hash ; validation_passes } ->
let message =
Some (Format.asprintf "activate %a" Protocol_hash.pp_short hash) in
Updater.activate ctxt hash >>= fun ctxt ->
return { Updater.message ; context = ctxt ;
fitness ; max_operations_ttl = 0 ;
max_number_of_operations = [] ;
max_number_of_operations =
Array.to_list (Array.make validation_passes 0) ;
max_operation_data_length = 0 }
| Activate_testnet (hash, delay) ->
| Activate_testnet { protocol = hash ; validation_passes ; delay } ->
let message =
Some (Format.asprintf "activate testnet %a" Protocol_hash.pp_short hash) in
let expiration = Time.add raw_block.shell.timestamp delay in
Updater.fork_test_network ctxt hash expiration >>= fun ctxt ->
Updater.fork_test_network ctxt ~protocol:hash ~expiration >>= fun ctxt ->
return { Updater.message ; context = ctxt ; fitness ;
max_operations_ttl = 0 ; max_operation_data_length = 0 ;
max_number_of_operations = [] }
max_operations_ttl = 0 ;
max_number_of_operations =
Array.to_list (Array.make validation_passes 0) ;
max_operation_data_length = 0 }
let begin_construction
~predecessor_context:context

View File

@ -56,7 +56,7 @@ let int64_to_bytes i =
b
let operations_hash =
Operation_list_list_hash.compute [Operation_list_hash.empty]
Operation_list_list_hash.compute []
let rpc_services : Updater.rpc_context RPC.directory =
let dir = RPC.empty in
@ -67,7 +67,7 @@ let rpc_services : Updater.rpc_context RPC.directory =
(fun _ctxt ((_net_id, level, proto_level, predecessor,
timestamp, fitness), command) ->
let shell = { Block_header.level ; proto_level ; predecessor ;
timestamp ; fitness ; validation_passes = 1 ; operations_hash } in
timestamp ; fitness ; validation_passes = 0 ; operations_hash } in
let bytes = Data.Command.forge shell command in
RPC.Answer.return bytes) in
dir

View File

@ -29,7 +29,7 @@ let activate_alpha () =
let fitness = Fitness_repr.from_int64 0L in
Client_embedded_genesis.Client_proto_main.bake
!rpc_config (`Head 0)
(Activate Client_proto_main.protocol)
(Activate { protocol = Client_proto_main.protocol ; validation_passes = 1})
fitness dictator_sk
let init ?(sandbox = "sandbox.json") ?rpc_port () =

View File

@ -195,44 +195,47 @@ let test_endorsement_rights contract block =
let run genesis =
Helpers.Baking.bake genesis b1 [] >>=? fun blk ->
let block = `Hash blk in
test_endorsement_rights
default_account genesis >>=? fun has_right_to_endorse ->
default_account block >>=? fun has_right_to_endorse ->
Assert.equal_bool ~msg:__LOC__ has_right_to_endorse false ;
test_endorsement_rights b1 genesis >>=? fun has_right_to_endorse ->
test_endorsement_rights b1 block >>=? fun has_right_to_endorse ->
Assert.equal_bool ~msg:__LOC__ has_right_to_endorse true ;
test_endorsement_rights b1 genesis >>=? fun has_right_to_endorse ->
test_endorsement_rights b1 block >>=? fun has_right_to_endorse ->
Assert.equal_bool ~msg:__LOC__ has_right_to_endorse true ;
Assert.balance_equal
~block:genesis ~msg:__LOC__ b1 4_000_000_00L >>=? fun () ->
~block:block ~msg:__LOC__ b1 3_999_000_00L >>=? fun () ->
Assert.balance_equal
~block:genesis ~msg:__LOC__ b2 4_000_000_00L >>=? fun () ->
~block:block ~msg:__LOC__ b2 4_000_000_00L >>=? fun () ->
Assert.balance_equal
~block:genesis ~msg:__LOC__ b3 4_000_000_00L >>=? fun () ->
~block:block ~msg:__LOC__ b3 4_000_000_00L >>=? fun () ->
Assert.balance_equal
~block:genesis ~msg:__LOC__ b4 4_000_000_00L >>=? fun () ->
~block:block ~msg:__LOC__ b4 4_000_000_00L >>=? fun () ->
Assert.balance_equal
~block:genesis ~msg:__LOC__ b5 4_000_000_00L >>=? fun () ->
~block:block ~msg:__LOC__ b5 4_000_000_00L >>=? fun () ->
(* Check Rewards *)
test_endorsement_rewards genesis >>=? fun () ->
test_endorsement_rewards block >>=? fun () ->
(* Endorse with a contract with wrong delegate:
- contract with no endorsement rights
- contract which signs at every available slots *)
test_wrong_delegate ~baker:b1 default_account genesis >>= fun () ->
test_wrong_delegate ~baker:b1 b5 genesis >>= fun () ->
test_wrong_delegate ~baker:b1 default_account block >>= fun () ->
test_wrong_delegate ~baker:b1 b5 block >>= fun () ->
(* Endorse with a wrong slot : -1 and max (16) *)
test_invalid_endorsement_slot b3 genesis >>=? fun () ->
test_invalid_endorsement_slot b3 block >>=? fun () ->
(* FIXME: Baking.Invalid_signature is still unclassified *)
test_invalid_signature genesis >>=? fun _ ->
test_invalid_signature block >>=? fun _ ->
(* FIXME: cannot inject double endorsement operation yet, but the
code is still here
Double endorsement *)
test_double_endorsement b4 genesis >>=? fun _ ->
test_double_endorsement b4 block >>=? fun _ ->
return ()

View File

@ -8,6 +8,9 @@ source $test_dir/lib/test_lib.inc.sh
start_node 1
activate_alpha
sleep 2
$client bake for bootstrap1 -max-priority 512
key1=foo
key2=bar

View File

@ -9,6 +9,9 @@ source $test_dir/lib/test_lib.inc.sh
start_node 1
activate_alpha
sleep 2
$client bake for bootstrap5 -max-priority 512
key1=foo
key2=bar

View File

@ -80,6 +80,7 @@ activate_alpha() {
activate \
protocol ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK \
with fitness 1 \
and passes 1 \
and key edskRhxswacLW6jF6ULavDdzwqnKJVS4UcDTNiCyiH6H8ZNnn2pmNviL7pRNz9kRxxaWQFzEQEcZExGHKbwmuaAcoMegj5T99z \
> /dev/stderr
}