Shell: enforce the maximum number of operation per block
This commit is contained in:
parent
3c06879deb
commit
84a2f1ee29
@ -392,6 +392,7 @@ go_alpha_go() {
|
||||
activate \
|
||||
protocol ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK \
|
||||
with fitness 1 \
|
||||
and passes 1 \
|
||||
and key dictator
|
||||
}
|
||||
|
||||
|
@ -207,6 +207,7 @@ activate_alpha() {
|
||||
-block genesis \
|
||||
activate protocol ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK \
|
||||
with fitness 1 \
|
||||
and passes 1 \
|
||||
and key dictator
|
||||
|
||||
}
|
||||
|
@ -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 ;
|
||||
|
@ -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 ()
|
||||
|
@ -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 ->
|
||||
|
@ -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
|
||||
|
@ -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 =
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 () =
|
||||
|
@ -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 ()
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -80,6 +80,7 @@ activate_alpha() {
|
||||
activate \
|
||||
protocol ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK \
|
||||
with fitness 1 \
|
||||
and passes 1 \
|
||||
and key edskRhxswacLW6jF6ULavDdzwqnKJVS4UcDTNiCyiH6H8ZNnn2pmNviL7pRNz9kRxxaWQFzEQEcZExGHKbwmuaAcoMegj5T99z \
|
||||
> /dev/stderr
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user