Shell: Liveness of operations
Operations now include a block hash in their header. Such an operation could only be included in a successor of this block. Furthermore, when validating a block, the economic protocol now returns---together with the context---an integer `max_operations_ttl`. Then, when validating a successor, the shell will fail if it contains an operation whose header's block hash is not one the `max_operations_ttl` predecessors of the block. As a bonus, the shell is now able to detect and forbid replayed operations. Then, we might decide to remove some replay detection-mechanism that we previously implemented in the economic protocol.
This commit is contained in:
parent
329c8b185a
commit
2bc63854a8
@ -53,12 +53,7 @@ val inject_protocol:
|
||||
|
||||
module Blocks : sig
|
||||
|
||||
type block = [
|
||||
| `Genesis
|
||||
| `Head of int | `Prevalidation
|
||||
| `Test_head of int | `Test_prevalidation
|
||||
| `Hash of Block_hash.t
|
||||
]
|
||||
type block = Node_rpc_services.Blocks.block
|
||||
|
||||
val net_id:
|
||||
config ->
|
||||
|
@ -124,6 +124,7 @@ let inject_endorsement cctxt
|
||||
Client_proto_rpcs.Helpers.Forge.Delegate.endorsement cctxt.rpc_config
|
||||
block
|
||||
~net_id:bi.net_id
|
||||
~branch:bi.hash
|
||||
~source
|
||||
~block:bi.hash
|
||||
~slot:slot
|
||||
|
@ -11,15 +11,16 @@ open Cli_entries
|
||||
open Tezos_context
|
||||
open Logging.Client.Revelation
|
||||
|
||||
let inject_seed_nonce_revelation cctxt block ?force ?async nonces =
|
||||
let inject_seed_nonce_revelation rpc_config block ?force ?async nonces =
|
||||
let operations =
|
||||
List.map
|
||||
(fun (level, nonce) ->
|
||||
Seed_nonce_revelation { level ; nonce }) nonces in
|
||||
Client_node_rpcs.Blocks.net_id cctxt block >>=? fun net_id ->
|
||||
Client_proto_rpcs.Helpers.Forge.Anonymous.operations cctxt
|
||||
block ~net_id operations >>=? fun bytes ->
|
||||
Client_node_rpcs.inject_operation cctxt ?force ?async bytes >>=? fun oph ->
|
||||
let block = Client_rpcs.last_mined_block block in
|
||||
Client_node_rpcs.Blocks.info rpc_config block >>=? fun bi ->
|
||||
Client_proto_rpcs.Helpers.Forge.Anonymous.operations rpc_config
|
||||
block ~net_id:bi.net_id ~branch:bi.hash operations >>=? fun bytes ->
|
||||
Client_node_rpcs.inject_operation rpc_config ?force ?async bytes >>=? fun oph ->
|
||||
return oph
|
||||
|
||||
type Error_monad.error += Bad_revelation
|
||||
|
@ -17,11 +17,31 @@ module Ed25519 = Environment.Ed25519
|
||||
let get_balance cctxt block contract =
|
||||
Client_proto_rpcs.Context.Contract.balance cctxt block contract
|
||||
|
||||
let rec find_predecessor rpc_config h n =
|
||||
if n <= 0 then
|
||||
return (`Hash h)
|
||||
else
|
||||
Client_node_rpcs.Blocks.predecessor rpc_config (`Hash h) >>=? fun h ->
|
||||
find_predecessor rpc_config h (n-1)
|
||||
|
||||
let get_branch rpc_config block branch =
|
||||
let branch = Utils.unopt ~default:0 branch in (* TODO export parameter *)
|
||||
let block = Client_rpcs.last_mined_block block in
|
||||
begin
|
||||
match block with
|
||||
| `Head n -> return (`Head (n+branch))
|
||||
| `Test_head n -> return (`Test_head (n+branch))
|
||||
| `Hash h -> find_predecessor rpc_config h branch
|
||||
| `Genesis -> return `Genesis
|
||||
end >>=? fun block ->
|
||||
Client_node_rpcs.Blocks.info rpc_config block >>=? fun { net_id ; hash } ->
|
||||
return (net_id, hash)
|
||||
|
||||
let transfer rpc_config
|
||||
block ?force
|
||||
block ?force ?branch
|
||||
~source ~src_pk ~src_sk ~destination ?arg ~amount ~fee () =
|
||||
let open Cli_entries in
|
||||
Client_node_rpcs.Blocks.net_id rpc_config block >>=? fun net_id ->
|
||||
get_branch rpc_config block branch >>=? fun (net_id, branch) ->
|
||||
begin match arg with
|
||||
| Some arg ->
|
||||
Client_proto_programs.parse_data arg >>=? fun arg ->
|
||||
@ -33,7 +53,7 @@ let transfer rpc_config
|
||||
let counter = Int32.succ pcounter in
|
||||
Client_proto_rpcs.Helpers.Forge.Manager.transaction
|
||||
rpc_config block
|
||||
~net_id ~source ~sourcePubKey:src_pk ~counter ~amount
|
||||
~net_id ~branch ~source ~sourcePubKey:src_pk ~counter ~amount
|
||||
~destination ?parameters ~fee () >>=? fun bytes ->
|
||||
Client_node_rpcs.Blocks.predecessor rpc_config block >>=? fun predecessor ->
|
||||
let signature = Ed25519.sign src_sk bytes in
|
||||
@ -66,22 +86,22 @@ let originate rpc_config ?force ~block ?signature bytes =
|
||||
(List.length contracts)
|
||||
|
||||
let originate_account rpc_config
|
||||
block ?force
|
||||
block ?force ?branch
|
||||
~source ~src_pk ~src_sk ~manager_pkh
|
||||
?delegatable ?spendable ?delegate ~balance ~fee () =
|
||||
Client_node_rpcs.Blocks.net_id rpc_config block >>=? fun net_id ->
|
||||
get_branch rpc_config block branch >>=? fun (net_id, branch) ->
|
||||
Client_proto_rpcs.Context.Contract.counter
|
||||
rpc_config block source >>=? fun pcounter ->
|
||||
let counter = Int32.succ pcounter in
|
||||
Client_proto_rpcs.Helpers.Forge.Manager.origination rpc_config block
|
||||
~net_id ~source ~sourcePubKey:src_pk ~managerPubKey:manager_pkh
|
||||
~net_id ~branch ~source ~sourcePubKey:src_pk ~managerPubKey:manager_pkh
|
||||
~counter ~balance ?spendable
|
||||
?delegatable ?delegatePubKey:delegate ~fee () >>=? fun bytes ->
|
||||
let signature = Ed25519.sign src_sk bytes in
|
||||
originate rpc_config ?force ~block ~signature bytes
|
||||
|
||||
let originate_contract rpc_config
|
||||
block ?force
|
||||
block ?force ?branch
|
||||
~source ~src_pk ~src_sk ~manager_pkh ~balance ?delegatable ?delegatePubKey
|
||||
~(code:Script.code) ~init ~fee () =
|
||||
Client_proto_programs.parse_data init >>=? fun storage ->
|
||||
@ -89,33 +109,33 @@ let originate_contract rpc_config
|
||||
Client_proto_rpcs.Context.Contract.counter
|
||||
rpc_config block source >>=? fun pcounter ->
|
||||
let counter = Int32.succ pcounter in
|
||||
Client_node_rpcs.Blocks.net_id rpc_config block >>=? fun net_id ->
|
||||
get_branch rpc_config block branch >>=? fun (net_id, branch) ->
|
||||
Client_proto_rpcs.Helpers.Forge.Manager.origination rpc_config block
|
||||
~net_id ~source ~sourcePubKey:src_pk ~managerPubKey:manager_pkh
|
||||
~net_id ~branch ~source ~sourcePubKey:src_pk ~managerPubKey:manager_pkh
|
||||
~counter ~balance ~spendable:!spendable
|
||||
?delegatable ?delegatePubKey
|
||||
~script:{ code ; storage } ~fee () >>=? fun bytes ->
|
||||
let signature = Ed25519.sign src_sk bytes in
|
||||
originate rpc_config ?force ~block ~signature bytes
|
||||
|
||||
let faucet rpc_config block ?force ~manager_pkh () =
|
||||
Client_node_rpcs.Blocks.net_id rpc_config block >>=? fun net_id ->
|
||||
let faucet rpc_config block ?force ?branch ~manager_pkh () =
|
||||
get_branch rpc_config block branch >>=? fun (net_id, branch) ->
|
||||
Client_proto_rpcs.Context.faucet_counter rpc_config block >>=? fun pcounter ->
|
||||
let counter = Int32.succ pcounter in
|
||||
Client_proto_rpcs.Helpers.Forge.Anonymous.faucet
|
||||
rpc_config block ~net_id ~id:manager_pkh counter >>=? fun bytes ->
|
||||
rpc_config block ~net_id ~branch ~id:manager_pkh counter >>=? fun bytes ->
|
||||
originate rpc_config ?force ~block bytes
|
||||
|
||||
let delegate_contract rpc_config
|
||||
block ?force
|
||||
block ?force ?branch
|
||||
~source ?src_pk ~manager_sk
|
||||
~fee delegate_opt =
|
||||
Client_node_rpcs.Blocks.net_id rpc_config block >>=? fun net_id ->
|
||||
get_branch rpc_config block branch >>=? fun (net_id, branch) ->
|
||||
Client_proto_rpcs.Context.Contract.counter
|
||||
rpc_config block source >>=? fun pcounter ->
|
||||
let counter = Int32.succ pcounter in
|
||||
Client_proto_rpcs.Helpers.Forge.Manager.delegation rpc_config block
|
||||
~net_id ~source ?sourcePubKey:src_pk ~counter ~fee delegate_opt
|
||||
~net_id ~branch ~source ?sourcePubKey:src_pk ~counter ~fee delegate_opt
|
||||
>>=? fun bytes ->
|
||||
let signature = Environment.Ed25519.sign manager_sk bytes in
|
||||
let signed_bytes = MBytes.concat bytes signature in
|
||||
@ -125,18 +145,6 @@ let delegate_contract rpc_config
|
||||
assert (Operation_hash.equal oph injected_oph) ;
|
||||
return oph
|
||||
|
||||
let dictate rpc_config block command seckey =
|
||||
Client_node_rpcs.Blocks.net_id rpc_config block >>=? fun net_id ->
|
||||
Client_proto_rpcs.Helpers.Forge.Dictator.operation
|
||||
rpc_config block ~net_id command >>=? fun bytes ->
|
||||
let signature = Ed25519.sign seckey bytes in
|
||||
let signed_bytes = MBytes.concat bytes signature in
|
||||
let oph = Operation_hash.hash_bytes [ signed_bytes ] in
|
||||
Client_node_rpcs.inject_operation
|
||||
rpc_config signed_bytes >>=? fun injected_oph ->
|
||||
assert (Operation_hash.equal oph injected_oph) ;
|
||||
return oph
|
||||
|
||||
let list_contract_labels cctxt block =
|
||||
Client_proto_rpcs.Context.Contract.list
|
||||
cctxt.rpc_config block >>=? fun contracts ->
|
||||
@ -207,9 +215,11 @@ let group =
|
||||
title = "Block contextual commands (see option -block)" }
|
||||
|
||||
let dictate rpc_config block command seckey =
|
||||
Client_node_rpcs.Blocks.net_id rpc_config block >>=? fun net_id ->
|
||||
let block = Client_rpcs.last_mined_block block in
|
||||
Client_node_rpcs.Blocks.info
|
||||
rpc_config block >>=? fun { net_id ; hash = branch } ->
|
||||
Client_proto_rpcs.Helpers.Forge.Dictator.operation
|
||||
rpc_config block ~net_id command >>=? fun bytes ->
|
||||
rpc_config block ~net_id ~branch command >>=? fun bytes ->
|
||||
let signature = Ed25519.sign seckey bytes in
|
||||
let signed_bytes = MBytes.concat bytes signature in
|
||||
let oph = Operation_hash.hash_bytes [ signed_bytes ] in
|
||||
|
@ -19,6 +19,7 @@ val transfer:
|
||||
Client_rpcs.config ->
|
||||
Client_proto_rpcs.block ->
|
||||
?force:bool ->
|
||||
?branch:int ->
|
||||
source:Contract.t ->
|
||||
src_pk:public_key ->
|
||||
src_sk:secret_key ->
|
||||
@ -32,6 +33,7 @@ val originate_account:
|
||||
Client_rpcs.config ->
|
||||
Client_proto_rpcs.block ->
|
||||
?force:bool ->
|
||||
?branch:int ->
|
||||
source:Contract.t ->
|
||||
src_pk:public_key ->
|
||||
src_sk:secret_key ->
|
||||
@ -47,6 +49,7 @@ val originate_contract:
|
||||
Client_rpcs.config ->
|
||||
Client_proto_rpcs.block ->
|
||||
?force:bool ->
|
||||
?branch:int ->
|
||||
source:Contract.t ->
|
||||
src_pk:public_key ->
|
||||
src_sk:secret_key ->
|
||||
@ -63,6 +66,7 @@ val delegate_contract:
|
||||
Client_rpcs.config ->
|
||||
Client_proto_rpcs.block ->
|
||||
?force:bool ->
|
||||
?branch:int ->
|
||||
source:Contract.t ->
|
||||
?src_pk:public_key ->
|
||||
manager_sk:secret_key ->
|
||||
|
@ -190,25 +190,25 @@ module Helpers = struct
|
||||
|
||||
module Manager = struct
|
||||
let operations cctxt
|
||||
block ~net_id ~source ?sourcePubKey ~counter ~fee operations =
|
||||
block ~net_id ~branch ~source ?sourcePubKey ~counter ~fee operations =
|
||||
let ops =
|
||||
Manager_operations { source ; public_key = sourcePubKey ;
|
||||
counter ; operations ; fee } in
|
||||
(call_error_service1 cctxt Services.Helpers.Forge.operations block
|
||||
({net_id}, Sourced_operations ops))
|
||||
({net_id ; branch }, Sourced_operations ops))
|
||||
let transaction cctxt
|
||||
block ~net_id ~source ?sourcePubKey ~counter
|
||||
block ~net_id ~branch ~source ?sourcePubKey ~counter
|
||||
~amount ~destination ?parameters ~fee ()=
|
||||
operations cctxt block ~net_id ~source ?sourcePubKey ~counter ~fee
|
||||
operations cctxt block ~net_id ~branch ~source ?sourcePubKey ~counter ~fee
|
||||
Tezos_context.[Transaction { amount ; parameters ; destination }]
|
||||
let origination cctxt
|
||||
block ~net_id
|
||||
block ~net_id ~branch
|
||||
~source ?sourcePubKey ~counter
|
||||
~managerPubKey ~balance
|
||||
?(spendable = true)
|
||||
?(delegatable = true)
|
||||
?delegatePubKey ?script ~fee () =
|
||||
operations cctxt block ~net_id ~source ?sourcePubKey ~counter ~fee
|
||||
operations cctxt block ~net_id ~branch ~source ?sourcePubKey ~counter ~fee
|
||||
Tezos_context.[
|
||||
Origination { manager = managerPubKey ;
|
||||
delegate = delegatePubKey ;
|
||||
@ -218,53 +218,53 @@ module Helpers = struct
|
||||
credit = balance }
|
||||
]
|
||||
let delegation cctxt
|
||||
block ~net_id ~source ?sourcePubKey ~counter ~fee delegate =
|
||||
operations cctxt block ~net_id ~source ?sourcePubKey ~counter ~fee
|
||||
block ~net_id ~branch ~source ?sourcePubKey ~counter ~fee delegate =
|
||||
operations cctxt block ~net_id ~branch ~source ?sourcePubKey ~counter ~fee
|
||||
Tezos_context.[Delegation delegate]
|
||||
end
|
||||
module Delegate = struct
|
||||
let operations cctxt
|
||||
block ~net_id ~source operations =
|
||||
block ~net_id ~branch ~source operations =
|
||||
let ops = Delegate_operations { source ; operations } in
|
||||
(call_error_service1 cctxt Services.Helpers.Forge.operations block
|
||||
({net_id}, Sourced_operations ops))
|
||||
({net_id ; branch}, Sourced_operations ops))
|
||||
let endorsement cctxt
|
||||
b ~net_id ~source ~block ~slot () =
|
||||
operations cctxt b ~net_id ~source
|
||||
b ~net_id ~branch ~source ~block ~slot () =
|
||||
operations cctxt b ~net_id ~branch ~source
|
||||
Tezos_context.[Endorsement { block ; slot }]
|
||||
let proposals cctxt
|
||||
b ~net_id ~source ~period ~proposals () =
|
||||
operations cctxt b ~net_id ~source
|
||||
b ~net_id ~branch ~source ~period ~proposals () =
|
||||
operations cctxt b ~net_id ~branch ~source
|
||||
Tezos_context.[Proposals { period ; proposals }]
|
||||
let ballot cctxt
|
||||
b ~net_id ~source ~period ~proposal ~ballot () =
|
||||
operations cctxt b ~net_id ~source
|
||||
b ~net_id ~branch ~source ~period ~proposal ~ballot () =
|
||||
operations cctxt b ~net_id ~branch ~source
|
||||
Tezos_context.[Ballot { period ; proposal ; ballot }]
|
||||
end
|
||||
module Dictator = struct
|
||||
let operation cctxt
|
||||
block ~net_id operation =
|
||||
block ~net_id ~branch operation =
|
||||
let op = Dictator_operation operation in
|
||||
(call_error_service1 cctxt Services.Helpers.Forge.operations block
|
||||
({net_id}, Sourced_operations op))
|
||||
({net_id ; branch}, Sourced_operations op))
|
||||
let activate cctxt
|
||||
b ~net_id hash =
|
||||
operation cctxt b ~net_id (Activate hash)
|
||||
b ~net_id ~branch hash =
|
||||
operation cctxt b ~net_id ~branch (Activate hash)
|
||||
let activate_testnet cctxt
|
||||
b ~net_id hash =
|
||||
operation cctxt b ~net_id (Activate_testnet hash)
|
||||
b ~net_id ~branch hash =
|
||||
operation cctxt b ~net_id ~branch (Activate_testnet hash)
|
||||
end
|
||||
module Anonymous = struct
|
||||
let operations cctxt block ~net_id operations =
|
||||
let operations cctxt block ~net_id ~branch operations =
|
||||
(call_error_service1 cctxt Services.Helpers.Forge.operations block
|
||||
({net_id}, Anonymous_operations operations))
|
||||
({net_id ; branch}, Anonymous_operations operations))
|
||||
let seed_nonce_revelation cctxt
|
||||
block ~net_id ~level ~nonce () =
|
||||
operations cctxt block ~net_id [Seed_nonce_revelation { level ; nonce }]
|
||||
block ~net_id ~branch ~level ~nonce () =
|
||||
operations cctxt block ~net_id ~branch [Seed_nonce_revelation { level ; nonce }]
|
||||
let faucet cctxt
|
||||
block ~net_id ~id counter =
|
||||
block ~net_id ~branch ~id counter =
|
||||
let nonce = Sodium.Random.Bigbytes.generate 16 in
|
||||
operations cctxt block ~net_id [Faucet { id ; counter ; nonce }]
|
||||
operations cctxt block ~net_id ~branch [Faucet { id ; counter ; nonce }]
|
||||
end
|
||||
let empty_proof_of_work_nonce =
|
||||
MBytes.of_string
|
||||
|
@ -10,12 +10,7 @@
|
||||
val string_of_errors: error list -> string
|
||||
val handle_error: Client_commands.context -> 'a tzresult -> 'a Lwt.t
|
||||
|
||||
type block = [
|
||||
| `Genesis
|
||||
| `Head of int | `Prevalidation
|
||||
| `Test_head of int | `Test_prevalidation
|
||||
| `Hash of Block_hash.t
|
||||
]
|
||||
type block = Node_rpc_services.Blocks.block
|
||||
|
||||
val header:
|
||||
Client_rpcs.config -> block -> Block_header.t tzresult Lwt.t
|
||||
@ -208,6 +203,7 @@ module Helpers : sig
|
||||
Client_rpcs.config ->
|
||||
block ->
|
||||
net_id:Net_id.t ->
|
||||
branch:Block_hash.t ->
|
||||
source:Contract.t ->
|
||||
?sourcePubKey:public_key ->
|
||||
counter:int32 ->
|
||||
@ -218,6 +214,7 @@ module Helpers : sig
|
||||
Client_rpcs.config ->
|
||||
block ->
|
||||
net_id:Net_id.t ->
|
||||
branch:Block_hash.t ->
|
||||
source:Contract.t ->
|
||||
?sourcePubKey:public_key ->
|
||||
counter:int32 ->
|
||||
@ -230,6 +227,7 @@ module Helpers : sig
|
||||
Client_rpcs.config ->
|
||||
block ->
|
||||
net_id:Net_id.t ->
|
||||
branch:Block_hash.t ->
|
||||
source:Contract.t ->
|
||||
?sourcePubKey:public_key ->
|
||||
counter:int32 ->
|
||||
@ -246,6 +244,7 @@ module Helpers : sig
|
||||
Client_rpcs.config ->
|
||||
block ->
|
||||
net_id:Net_id.t ->
|
||||
branch:Block_hash.t ->
|
||||
source:Contract.t ->
|
||||
?sourcePubKey:public_key ->
|
||||
counter:int32 ->
|
||||
@ -258,18 +257,21 @@ module Helpers : sig
|
||||
Client_rpcs.config ->
|
||||
block ->
|
||||
net_id:Net_id.t ->
|
||||
branch:Block_hash.t ->
|
||||
dictator_operation ->
|
||||
MBytes.t tzresult Lwt.t
|
||||
val activate:
|
||||
Client_rpcs.config ->
|
||||
block ->
|
||||
net_id:Net_id.t ->
|
||||
branch:Block_hash.t ->
|
||||
Protocol_hash.t ->
|
||||
MBytes.t tzresult Lwt.t
|
||||
val activate_testnet:
|
||||
Client_rpcs.config ->
|
||||
block ->
|
||||
net_id:Net_id.t ->
|
||||
branch:Block_hash.t ->
|
||||
Protocol_hash.t ->
|
||||
MBytes.t tzresult Lwt.t
|
||||
end
|
||||
@ -278,6 +280,7 @@ module Helpers : sig
|
||||
Client_rpcs.config ->
|
||||
block ->
|
||||
net_id:Net_id.t ->
|
||||
branch:Block_hash.t ->
|
||||
source:public_key ->
|
||||
delegate_operation list ->
|
||||
MBytes.t tzresult Lwt.t
|
||||
@ -285,6 +288,7 @@ module Helpers : sig
|
||||
Client_rpcs.config ->
|
||||
block ->
|
||||
net_id:Net_id.t ->
|
||||
branch:Block_hash.t ->
|
||||
source:public_key ->
|
||||
block:Block_hash.t ->
|
||||
slot:int ->
|
||||
@ -293,6 +297,7 @@ module Helpers : sig
|
||||
Client_rpcs.config ->
|
||||
block ->
|
||||
net_id:Net_id.t ->
|
||||
branch:Block_hash.t ->
|
||||
source:public_key ->
|
||||
period:Voting_period.t ->
|
||||
proposals:Hash.Protocol_hash.t list ->
|
||||
@ -301,6 +306,7 @@ module Helpers : sig
|
||||
Client_rpcs.config ->
|
||||
block ->
|
||||
net_id:Net_id.t ->
|
||||
branch:Block_hash.t ->
|
||||
source:public_key ->
|
||||
period:Voting_period.t ->
|
||||
proposal:Hash.Protocol_hash.t ->
|
||||
@ -312,12 +318,14 @@ module Helpers : sig
|
||||
Client_rpcs.config ->
|
||||
block ->
|
||||
net_id:Net_id.t ->
|
||||
branch:Block_hash.t ->
|
||||
anonymous_operation list ->
|
||||
MBytes.t tzresult Lwt.t
|
||||
val seed_nonce_revelation:
|
||||
Client_rpcs.config ->
|
||||
block ->
|
||||
net_id:Net_id.t ->
|
||||
branch:Block_hash.t ->
|
||||
level:Raw_level.t ->
|
||||
nonce:Nonce.t ->
|
||||
unit -> MBytes.t tzresult Lwt.t
|
||||
@ -325,6 +333,7 @@ module Helpers : sig
|
||||
Client_rpcs.config ->
|
||||
block ->
|
||||
net_id:Net_id.t ->
|
||||
branch:Block_hash.t ->
|
||||
id:public_key_hash ->
|
||||
int32 -> MBytes.t tzresult Lwt.t
|
||||
end
|
||||
@ -335,17 +344,6 @@ module Helpers : sig
|
||||
seed_nonce_hash: Nonce_hash.t ->
|
||||
?proof_of_work_nonce: MBytes.t ->
|
||||
unit -> MBytes.t tzresult Lwt.t
|
||||
(** [block cctxt root ~net ~predecessor ~timestamp ~fitness
|
||||
~operations ~level ~priority ~seed_nonce_hash
|
||||
~proof_of_work_nonce ()] returns the binary serialization of
|
||||
a block header (comprising the shell and protocol-specific
|
||||
part), rooted at [root], belonging to [net], with
|
||||
predecessor [predecessor], [timestamp], [fitness],
|
||||
associated operations [operations], level [level] (the
|
||||
protocol cannot deduce it from [predecessor] on its own),
|
||||
priority [priority] (the priority of this miner in the
|
||||
mining queue associated to [level]), [seed_nonce_hash] (the
|
||||
chosen seed that we will reveal in the next cycle). *)
|
||||
end
|
||||
|
||||
module Parse : sig
|
||||
|
@ -230,7 +230,7 @@ module RPC = struct
|
||||
Lwt.return v
|
||||
else
|
||||
State.Block.predecessor v >>= function
|
||||
| None -> Lwt.fail Not_found
|
||||
| None -> Lwt.return v
|
||||
| Some v -> predecessor net_db (n-1) v
|
||||
|
||||
let block_info node (block: block) =
|
||||
|
@ -77,6 +77,12 @@ let create net_db =
|
||||
let pending = Operation_hash.Table.create 53 in
|
||||
let head = ref head in
|
||||
let operations = ref empty_result in
|
||||
Chain_traversal.live_blocks
|
||||
!head
|
||||
(State.Block.max_operations_ttl !head)
|
||||
>>= fun (live_blocks, live_operations) ->
|
||||
let live_blocks = ref live_blocks in
|
||||
let live_operations = ref live_operations in
|
||||
let running_validation = ref Lwt.return_unit in
|
||||
let unprocessed = ref Operation_hash.Set.empty in
|
||||
let broadcast_unprocessed = ref false in
|
||||
@ -98,22 +104,24 @@ let create net_db =
|
||||
if Operation_hash.Set.is_empty !unprocessed then
|
||||
Lwt.return ()
|
||||
else
|
||||
(* We assume that `!unprocessed` does not contain any operations
|
||||
from `!operations`. *)
|
||||
let ops = !unprocessed in
|
||||
let broadcast = !broadcast_unprocessed in
|
||||
unprocessed := Operation_hash.Set.empty ;
|
||||
broadcast_unprocessed := false ;
|
||||
let ops = Operation_hash.Set.diff ops !live_operations in
|
||||
live_operations := Operation_hash.Set.(fold add) !live_operations ops ;
|
||||
running_validation := begin
|
||||
begin
|
||||
Lwt_list.map_p
|
||||
Lwt_list.filter_map_p
|
||||
(fun h ->
|
||||
Distributed_db.Operation.read_opt net_db h >>= function
|
||||
| Some po ->
|
||||
| Some po when Block_hash.Set.mem po.shell.branch !live_blocks ->
|
||||
(* FIXME add the operation on a bounded set of
|
||||
to-be-ignored operations.*)
|
||||
Distributed_db.Operation.clear net_db h ;
|
||||
Lwt.return_some (h, po)
|
||||
| None -> Lwt.return_none)
|
||||
| Some _ | None -> Lwt.return_none)
|
||||
(Operation_hash.Set.elements ops) >>= fun rops ->
|
||||
let rops = Utils.unopt_list rops in
|
||||
(Lwt.return !validation_state >>=? fun validation_state ->
|
||||
(prevalidate validation_state ~sort:true rops >>= return)) >>= function
|
||||
| Ok (state, r) -> Lwt.return (Ok state, r)
|
||||
@ -165,9 +173,6 @@ let create net_db =
|
||||
let prevalidation_worker =
|
||||
|
||||
let rec worker_loop () =
|
||||
(* TODO cleanup the mempool from outdated operation (1h like
|
||||
Bitcoin ?). And log the removal in some statistic associated
|
||||
to then peers that informed us of the operation. *)
|
||||
(* TODO lookup in `!pending` for 'outdated' ops and re-add them
|
||||
in `unprocessed` (e.g. if the previous tentative was
|
||||
more 5 seconds ago) *)
|
||||
@ -229,13 +234,12 @@ let create net_db =
|
||||
Lwt.return_unit
|
||||
end
|
||||
| `Register (gid, ops) ->
|
||||
Lwt_list.filter_p
|
||||
(fun op ->
|
||||
Distributed_db.Operation.known net_db op >|= not)
|
||||
ops >>= fun new_ops ->
|
||||
let known_ops, unknown_ops =
|
||||
List.partition
|
||||
(fun op -> Operation_hash.Table.mem pending op) new_ops in
|
||||
(fun op ->
|
||||
Operation_hash.Table.mem pending op
|
||||
|| Operation_hash.Set.mem op !live_operations)
|
||||
ops in
|
||||
let fetch op =
|
||||
Distributed_db.Operation.fetch
|
||||
net_db ~peer:gid op () >>= fun _op ->
|
||||
@ -260,6 +264,10 @@ let create net_db =
|
||||
| `Flush (new_head : State.Block.t) ->
|
||||
list_pendings ~from_block:!head ~to_block:new_head
|
||||
(preapply_result_operations !operations) >>= fun new_mempool ->
|
||||
Chain_traversal.live_blocks
|
||||
new_head
|
||||
(State.Block.max_operations_ttl new_head)
|
||||
>>= fun (new_live_blocks, new_live_operations) ->
|
||||
lwt_debug "flush %a (mempool: %d)"
|
||||
Block_hash.pp_short (State.Block.hash new_head)
|
||||
(Operation_hash.Set.cardinal new_mempool) >>= fun () ->
|
||||
@ -269,6 +277,8 @@ let create net_db =
|
||||
broadcast_unprocessed := false ;
|
||||
unprocessed := new_mempool ;
|
||||
timestamp := Time.now () ;
|
||||
live_blocks := new_live_blocks ;
|
||||
live_operations := new_live_operations ;
|
||||
(* Reset the prevalidation context. *)
|
||||
reset_validation_state new_head !timestamp)
|
||||
q >>= fun () ->
|
||||
|
@ -296,6 +296,8 @@ module Block = struct
|
||||
let message { contents = { message } } = message
|
||||
let operation_list_count { contents = { operation_list_count } } =
|
||||
operation_list_count
|
||||
let max_operations_ttl { contents = { max_operations_ttl } } =
|
||||
max_operations_ttl
|
||||
|
||||
let known_valid net_state hash =
|
||||
Shared.use net_state.block_store begin fun store ->
|
||||
|
@ -120,6 +120,7 @@ module Block : sig
|
||||
val net_id: t -> Net_id.t
|
||||
val level: t -> Int32.t
|
||||
val message: t -> string
|
||||
val max_operations_ttl: t -> int
|
||||
|
||||
val predecessor: t -> block option Lwt.t
|
||||
|
||||
|
@ -155,6 +155,8 @@ type error +=
|
||||
| Non_increasing_fitness
|
||||
| Wrong_level of Int32.t * Int32.t
|
||||
| Wrong_proto_level of int * int
|
||||
| Replayed_operation of Operation_hash.t
|
||||
| Outdated_operation of Operation_hash.t * Block_hash.t
|
||||
|
||||
let () =
|
||||
Error_monad.register_error_kind
|
||||
@ -204,7 +206,35 @@ let () =
|
||||
(req "expected" uint8)
|
||||
(req "provided" uint8))
|
||||
(function Wrong_proto_level (e, g) -> Some (e, g) | _ -> None)
|
||||
(fun (e, g) -> Wrong_proto_level (e, g))
|
||||
(fun (e, g) -> Wrong_proto_level (e, g)) ;
|
||||
register_error_kind
|
||||
`Permanent
|
||||
~id:"validator.replayed_operation"
|
||||
~title:"Replayed operation"
|
||||
~description:"The block contains an operation that was previously \
|
||||
included in the chain"
|
||||
~pp:(fun ppf oph ->
|
||||
Format.fprintf ppf
|
||||
"The operation %a was previously included in the chain."
|
||||
Operation_hash.pp oph)
|
||||
Data_encoding.(obj1 (req "hash" Operation_hash.encoding))
|
||||
(function Replayed_operation oph -> Some oph | _ -> None)
|
||||
(function oph -> Replayed_operation oph) ;
|
||||
register_error_kind
|
||||
`Permanent
|
||||
~id:"validator.outdated_operations"
|
||||
~title:"Outdated operation"
|
||||
~description:"The block contains an operation which is outdated."
|
||||
~pp:(fun ppf (oph, bh)->
|
||||
Format.fprintf ppf
|
||||
"The operation %a is outdated (%a)"
|
||||
Operation_hash.pp oph
|
||||
Block_hash.pp bh)
|
||||
Data_encoding.(obj2
|
||||
(req "operation" Operation_hash.encoding)
|
||||
(req "block" Block_hash.encoding))
|
||||
(function Outdated_operation (oph, bh) -> Some (oph, bh) | _ -> None)
|
||||
(function (oph, bh) -> Outdated_operation (oph, bh))
|
||||
|
||||
let apply_block net_state db
|
||||
(pred: State.Block.t) hash (block: Block_header.t) =
|
||||
@ -215,8 +245,7 @@ let apply_block net_state db
|
||||
lwt_log_notice "validate block %a (after %a), net %a"
|
||||
Block_hash.pp_short hash
|
||||
Block_hash.pp_short block.shell.predecessor
|
||||
Net_id.pp id
|
||||
>>= fun () ->
|
||||
Net_id.pp id >>= fun () ->
|
||||
fail_unless
|
||||
(Int32.succ pred_header.shell.level = block.shell.level)
|
||||
(Wrong_level (Int32.succ pred_header.shell.level,
|
||||
@ -246,6 +275,29 @@ let apply_block net_state db
|
||||
else
|
||||
return ()
|
||||
end >>=? fun () ->
|
||||
begin
|
||||
Chain_traversal.live_blocks
|
||||
pred (State.Block.max_operations_ttl pred) >>= fun (live_blocks,
|
||||
live_operations) ->
|
||||
let rec assert_no_duplicates live_operations = function
|
||||
| [] -> return ()
|
||||
| oph :: ophs ->
|
||||
if Operation_hash.Set.mem oph live_operations then
|
||||
fail (Replayed_operation oph)
|
||||
else
|
||||
assert_no_duplicates
|
||||
(Operation_hash.Set.add oph live_operations) ophs in
|
||||
let assert_live operations =
|
||||
List.fold_left
|
||||
(fun acc op ->
|
||||
acc >>=? fun () ->
|
||||
fail_unless
|
||||
(Block_hash.Set.mem op.Operation.shell.branch live_blocks)
|
||||
(Outdated_operation (Operation.hash op, op.shell.branch)))
|
||||
(return ()) operations in
|
||||
assert_no_duplicates live_operations operation_hashes >>=? fun () ->
|
||||
assert_live operations
|
||||
end >>=? fun () ->
|
||||
Context.get_protocol pred_context >>= fun pred_protocol_hash ->
|
||||
begin
|
||||
match Updater.get pred_protocol_hash with
|
||||
@ -295,6 +347,13 @@ let apply_block net_state db
|
||||
expected = block.shell.fitness ;
|
||||
found = new_context.fitness ;
|
||||
}) >>=? fun () ->
|
||||
let max_operations_ttl =
|
||||
max 0
|
||||
(min
|
||||
((State.Block.max_operations_ttl pred)+1)
|
||||
new_context.max_operations_ttl) in
|
||||
let new_context =
|
||||
{ new_context with max_operations_ttl } in
|
||||
lwt_log_info "validation of %a: success"
|
||||
Block_hash.pp_short hash >>= fun () ->
|
||||
return new_context
|
||||
|
@ -364,8 +364,7 @@ let parse hash (op: Operation.t) =
|
||||
Encoding.signed_proto_operation_encoding
|
||||
op.proto with
|
||||
| Some (contents, signature) ->
|
||||
let shell = { Operation.net_id = op.shell.net_id } in
|
||||
ok { hash ; shell ; contents ; signature }
|
||||
ok { hash ; shell = op.shell ; contents ; signature }
|
||||
| None -> error Cannot_parse_operation
|
||||
|
||||
type error += Invalid_signature (* `Permanent *)
|
||||
|
@ -40,6 +40,7 @@ module Operation : sig
|
||||
|
||||
type shell_header = {
|
||||
net_id: Net_id.t ;
|
||||
branch: Block_hash.t ;
|
||||
}
|
||||
val shell_header_encoding: shell_header Data_encoding.t
|
||||
|
||||
|
@ -93,14 +93,17 @@ module Operation = struct
|
||||
|
||||
type shell_header = {
|
||||
net_id: Net_id.t ;
|
||||
branch: Block_hash.t ;
|
||||
}
|
||||
|
||||
let shell_header_encoding =
|
||||
let open Data_encoding in
|
||||
conv
|
||||
(fun { net_id } -> net_id)
|
||||
(fun net_id -> { net_id })
|
||||
(obj1 (req "net_id" Net_id.encoding))
|
||||
(fun { net_id ; branch } -> net_id, branch)
|
||||
(fun (net_id, branch) -> { net_id ; branch })
|
||||
(obj2
|
||||
(req "net_id" Net_id.encoding)
|
||||
(req "branch" Block_hash.encoding))
|
||||
|
||||
type t = {
|
||||
shell: shell_header ;
|
||||
|
@ -40,6 +40,7 @@ module Operation : sig
|
||||
|
||||
type shell_header = {
|
||||
net_id: Net_id.t ;
|
||||
branch: Block_hash.t ;
|
||||
}
|
||||
val shell_header_encoding: shell_header Data_encoding.t
|
||||
|
||||
|
@ -17,6 +17,8 @@ S ../../src/proto
|
||||
B ../../src/proto
|
||||
S ../../src/client
|
||||
B ../../src/client
|
||||
S ../../src/client/embedded
|
||||
B ../../src/client/embedded
|
||||
S ../../src/client/embedded/alpha
|
||||
B ../../src/client/embedded/alpha
|
||||
S ../../src/client/embedded/alpha/baker
|
||||
|
@ -250,6 +250,7 @@ module Protocol = struct
|
||||
Client_proto_rpcs.Context.next_level rpc_config block >>=? fun next_level ->
|
||||
Client_proto_rpcs.Helpers.Forge.Delegate.proposals rpc_config block
|
||||
~net_id:block_info.net_id
|
||||
~branch:block_info.hash
|
||||
~source:pk
|
||||
~period:next_level.voting_period
|
||||
~proposals
|
||||
@ -262,6 +263,7 @@ module Protocol = struct
|
||||
Client_proto_rpcs.Context.next_level rpc_config block >>=? fun next_level ->
|
||||
Client_proto_rpcs.Helpers.Forge.Delegate.ballot rpc_config block
|
||||
~net_id:block_info.net_id
|
||||
~branch:block_info.hash
|
||||
~source:pk
|
||||
~period:next_level.voting_period
|
||||
~proposal
|
||||
@ -440,6 +442,7 @@ module Endorse = struct
|
||||
Client_proto_rpcs.Helpers.Forge.Delegate.endorsement rpc_config
|
||||
block
|
||||
~net_id:net_id
|
||||
~branch:hash
|
||||
~source
|
||||
~block:hash
|
||||
~slot:slot
|
||||
@ -480,7 +483,7 @@ module Endorse = struct
|
||||
forge_endorsement block contract.sk contract.pk slot
|
||||
|
||||
(* FIXME @vb: I don't understand this function, copied from @cago. *)
|
||||
let endorsers_list block { Account.b1 ; b2 ; b3 ; b4 ; b5 } =
|
||||
let endorsers_list block =
|
||||
let get_endorser_list result (account : Account.t) level block =
|
||||
Client_proto_rpcs.Helpers.Rights.endorsement_rights_for_delegate
|
||||
rpc_config block account.pkh
|
||||
@ -489,6 +492,7 @@ module Endorse = struct
|
||||
~last_level:level () >>|? fun slots ->
|
||||
List.iter (fun (_,slot) -> result.(slot) <- account) slots
|
||||
in
|
||||
let { Account.b1 ; b2 ; b3 ; b4 ; b5 } = Account.bootstrap_accounts in
|
||||
let result = Array.make 16 b1 in
|
||||
Client_proto_rpcs.Context.level rpc_config block >>=? fun level ->
|
||||
let level = Raw_level.succ @@ level.level in
|
||||
|
@ -114,7 +114,6 @@ module Endorse : sig
|
||||
|
||||
val endorsers_list :
|
||||
Client_alpha.Client_proto_rpcs.block ->
|
||||
Account.bootstrap_accounts ->
|
||||
Account.t array tzresult Lwt.t
|
||||
|
||||
val endorsement_rights :
|
||||
|
@ -14,6 +14,12 @@ open Client_alpha
|
||||
module Helpers = Proto_alpha_helpers
|
||||
module Assert = Helpers.Assert
|
||||
|
||||
let { Helpers.Account.b1 ; b2 ; b3 ; b4 ; b5 } =
|
||||
Helpers.Account.bootstrap_accounts
|
||||
|
||||
let default_account =
|
||||
Helpers.Account.create "default_account"
|
||||
|
||||
let test_double_endorsement contract block =
|
||||
|
||||
(* Double endorsement for the same level *)
|
||||
@ -59,8 +65,7 @@ let contain_tzerror ?(msg="") ~f t =
|
||||
failwith "@[<v 2>Unexpected error@ %a@]" pp_print_error error
|
||||
| _ -> return ()
|
||||
|
||||
let test_wrong_delegate ~miner contract head =
|
||||
let block = `Hash head in
|
||||
let test_wrong_delegate ~miner contract block =
|
||||
begin
|
||||
Helpers.Endorse.endorse ~slot:1 contract block >>=? fun op ->
|
||||
Helpers.Mining.mine block miner [ op ] >>=? fun _ ->
|
||||
@ -95,8 +100,8 @@ let test_invalid_endorsement_slot contract block =
|
||||
end res ;
|
||||
return ()
|
||||
|
||||
let test_endorsement_rewards
|
||||
block ({ Helpers.Account.b5 = b1 ; _ } as baccounts) =
|
||||
let test_endorsement_rewards block0 =
|
||||
|
||||
let get_endorser_except bs accounts =
|
||||
let account, cpt = ref accounts.(0), ref 0 in
|
||||
while List.mem !account bs do
|
||||
@ -109,75 +114,74 @@ let test_endorsement_rewards
|
||||
|
||||
(* Endorsement Rights *)
|
||||
(* #1 endorse & inject in a block *)
|
||||
Helpers.Endorse.endorsers_list block baccounts >>=? fun accounts ->
|
||||
Helpers.Endorse.endorsers_list block0 >>=? fun accounts ->
|
||||
get_endorser_except [ b1 ] accounts >>=? fun (account0, slot0) ->
|
||||
Helpers.Account.balance ~block account0 >>=? fun balance0 ->
|
||||
Helpers.Endorse.endorse ~slot:slot0 account0 block >>=? fun ops ->
|
||||
Helpers.Mining.mine block b1 [ ops ] >>=? fun head0 ->
|
||||
Helpers.display_level (`Hash head0) >>=? fun () ->
|
||||
Assert.balance_equal ~block:(`Hash head0) ~msg:__LOC__ account0
|
||||
Helpers.Account.balance ~block:block0 account0 >>=? fun balance0 ->
|
||||
Helpers.Endorse.endorse ~slot:slot0 account0 block0 >>=? fun op ->
|
||||
Helpers.Mining.mine block0 b1 [ op ] >>=? fun hash1 ->
|
||||
Helpers.display_level (`Hash hash1) >>=? fun () ->
|
||||
Assert.balance_equal ~block:(`Hash hash1) ~msg:__LOC__ account0
|
||||
(Int64.sub (Tez.to_cents balance0) bond) >>=? fun () ->
|
||||
|
||||
|
||||
(* #2 endorse & inject in a block *)
|
||||
let block0 = `Hash head0 in
|
||||
Helpers.Endorse.endorsers_list block0 baccounts >>=? fun accounts ->
|
||||
let block1 = `Hash hash1 in
|
||||
Helpers.Endorse.endorsers_list block1 >>=? fun accounts ->
|
||||
get_endorser_except [ b1 ; account0 ] accounts >>=? fun (account1, slot1) ->
|
||||
Helpers.Account.balance ~block:block0 account1 >>=? fun balance1 ->
|
||||
Helpers.Endorse.endorse ~slot:slot1 account1 block0 >>=? fun ops ->
|
||||
Helpers.Mining.mine block0 b1 [ ops ] >>=? fun head1 ->
|
||||
Helpers.display_level (`Hash head1) >>=? fun () ->
|
||||
Assert.balance_equal ~block:(`Hash head1) ~msg:__LOC__ account1
|
||||
Helpers.Account.balance ~block:block1 account1 >>=? fun balance1 ->
|
||||
Helpers.Endorse.endorse ~slot:slot1 account1 block1 >>=? fun op ->
|
||||
Helpers.Mining.mine block1 b1 [ op ] >>=? fun hash2 ->
|
||||
Helpers.display_level (`Hash hash2) >>=? fun () ->
|
||||
Assert.balance_equal ~block:(`Hash hash2) ~msg:__LOC__ account1
|
||||
(Int64.sub (Tez.to_cents balance1) bond) >>=? fun () ->
|
||||
|
||||
(* Check rewards after one cycle for account0 *)
|
||||
Helpers.Mining.mine (`Hash head1) b1 [] >>=? fun head2 ->
|
||||
Helpers.display_level (`Hash head2) >>=? fun () ->
|
||||
Helpers.Mining.mine (`Hash head2) b1 [] >>=? fun head3 ->
|
||||
Helpers.display_level (`Hash head3) >>=? fun () ->
|
||||
Helpers.Mining.mine (`Hash head3) b1 [] >>=? fun head4 ->
|
||||
Helpers.display_level (`Hash head4) >>=? fun () ->
|
||||
Helpers.Mining.endorsement_reward block0 >>=? fun rw0 ->
|
||||
Assert.balance_equal ~block:(`Hash head4) ~msg:__LOC__ account0
|
||||
Helpers.Mining.mine (`Hash hash2) b1 [] >>=? fun hash3 ->
|
||||
Helpers.display_level (`Hash hash3) >>=? fun () ->
|
||||
Helpers.Mining.mine (`Hash hash3) b1 [] >>=? fun hash4 ->
|
||||
Helpers.display_level (`Hash hash4) >>=? fun () ->
|
||||
Helpers.Mining.mine (`Hash hash4) b1 [] >>=? fun hash5 ->
|
||||
Helpers.display_level (`Hash hash5) >>=? fun () ->
|
||||
Helpers.Mining.endorsement_reward block1 >>=? fun rw0 ->
|
||||
Assert.balance_equal ~block:(`Hash hash5) ~msg:__LOC__ account0
|
||||
(Int64.add (Tez.to_cents balance0) rw0) >>=? fun () ->
|
||||
|
||||
(* Check rewards after one cycle for account1 *)
|
||||
Helpers.Mining.endorsement_reward (`Hash head1) >>=? fun rw1 ->
|
||||
Assert.balance_equal ~block:(`Hash head4) ~msg:__LOC__ account1
|
||||
Helpers.Mining.endorsement_reward (`Hash hash2) >>=? fun rw1 ->
|
||||
Assert.balance_equal ~block:(`Hash hash5) ~msg:__LOC__ account1
|
||||
(Int64.add (Tez.to_cents balance1) rw1) >>=? fun () ->
|
||||
|
||||
(* #2 endorse and check reward only on the good chain *)
|
||||
Helpers.Mining.mine (`Hash head4) b1 []>>=? fun head ->
|
||||
Helpers.display_level (`Hash head) >>=? fun () ->
|
||||
Helpers.Mining.mine (`Hash head4) b1 [] >>=? fun fork ->
|
||||
Helpers.display_level (`Hash fork) >>=? fun () ->
|
||||
Helpers.Mining.mine (`Hash hash5) b1 []>>=? fun hash6a ->
|
||||
Helpers.display_level (`Hash hash6a) >>=? fun () ->
|
||||
Helpers.Mining.mine (`Hash hash5) b1 [] >>=? fun hash6b ->
|
||||
Helpers.display_level (`Hash hash6b) >>=? fun () ->
|
||||
|
||||
(* working on head *)
|
||||
Helpers.Endorse.endorsers_list (`Hash head) baccounts >>=? fun accounts ->
|
||||
Helpers.Endorse.endorsers_list (`Hash hash6a) >>=? fun accounts ->
|
||||
get_endorser_except [ b1 ] accounts >>=? fun (account3, slot3) ->
|
||||
Helpers.Account.balance ~block:(`Hash head) account3 >>=? fun balance3 ->
|
||||
Helpers.Account.balance ~block:(`Hash hash6a) account3 >>=? fun balance3 ->
|
||||
Helpers.Endorse.endorse
|
||||
~slot:slot3 account3 (`Hash head) >>=? fun ops ->
|
||||
Helpers.Mining.mine (`Hash head) b1 [ ops ] >>=? fun new_head ->
|
||||
Helpers.display_level (`Hash new_head) >>=? fun () ->
|
||||
~slot:slot3 account3 (`Hash hash6a) >>=? fun ops ->
|
||||
Helpers.Mining.mine (`Hash hash6a) b1 [ ops ] >>=? fun hash7a ->
|
||||
Helpers.display_level (`Hash hash7a) >>=? fun () ->
|
||||
|
||||
(* working on fork *)
|
||||
Helpers.Endorse.endorsers_list (`Hash fork) baccounts >>=? fun accounts ->
|
||||
Helpers.Endorse.endorsers_list (`Hash hash6b) >>=? fun accounts ->
|
||||
get_endorser_except [ b1 ] accounts >>=? fun (account4, slot4) ->
|
||||
Helpers.Account.balance ~block:(`Hash new_head) account4 >>=? fun _balance4 ->
|
||||
Helpers.Endorse.endorse ~slot:slot4 account4 (`Hash fork) >>=? fun ops ->
|
||||
Helpers.Mining.mine (`Hash fork) b1 [ ops ] >>=? fun _new_fork ->
|
||||
Helpers.Account.balance ~block:(`Hash hash7a) account4 >>=? fun _balance4 ->
|
||||
Helpers.Endorse.endorse ~slot:slot4 account4 (`Hash hash6b) >>=? fun ops ->
|
||||
Helpers.Mining.mine (`Hash hash6b) b1 [ ops ] >>=? fun _new_fork ->
|
||||
Helpers.display_level (`Hash _new_fork) >>=? fun () ->
|
||||
Helpers.Account.balance ~block:(`Hash new_head) account4 >>=? fun balance4 ->
|
||||
Helpers.Account.balance ~block:(`Hash hash7a) account4 >>=? fun balance4 ->
|
||||
|
||||
Helpers.Mining.mine (`Hash new_head) b1 [] >>=? fun head ->
|
||||
Helpers.display_level (`Hash head) >>=? fun () ->
|
||||
Helpers.Mining.mine (`Hash head) b1 [] >>=? fun head ->
|
||||
Helpers.display_level (`Hash head) >>=? fun () ->
|
||||
Helpers.Mining.mine (`Hash hash7a) b1 [] >>=? fun hash8a ->
|
||||
Helpers.display_level (`Hash hash8a) >>=? fun () ->
|
||||
Helpers.Mining.mine (`Hash hash8a) b1 [] >>=? fun hash9a ->
|
||||
Helpers.display_level (`Hash hash9a) >>=? fun () ->
|
||||
|
||||
(* Check rewards after one cycle *)
|
||||
Helpers.Mining.endorsement_reward (`Hash new_head) >>=? fun reward ->
|
||||
Assert.balance_equal ~block:(`Hash head) ~msg:__LOC__ account3
|
||||
Helpers.Mining.endorsement_reward (`Hash hash7a) >>=? fun reward ->
|
||||
Assert.balance_equal ~block:(`Hash hash9a) ~msg:__LOC__ account3
|
||||
(Int64.add (Tez.to_cents balance3) reward) >>=? fun () ->
|
||||
|
||||
(* Check no reward for the fork *)
|
||||
@ -185,57 +189,60 @@ let test_endorsement_rewards
|
||||
if account3 = account4 then return ()
|
||||
(* if account4 is different from account3, we need to check that there
|
||||
is no reward for him since the endorsement was in the fork branch *)
|
||||
else Assert.balance_equal ~block:(`Hash head) ~msg:__LOC__ account4 (Tez.to_cents balance4)
|
||||
else Assert.balance_equal ~block:(`Hash hash9a) ~msg:__LOC__ account4 (Tez.to_cents balance4)
|
||||
end >>=? fun () ->
|
||||
return head
|
||||
return ()
|
||||
|
||||
let test_endorsement_rights contract block =
|
||||
Helpers.Endorse.endorsement_rights contract block >>|? fun possibilities ->
|
||||
possibilities <> []
|
||||
|
||||
let run head (({ b1 ; b2 ; b3 ; b4 ; b5 } : Helpers.Account.bootstrap_accounts) as baccounts) =
|
||||
let run genesis =
|
||||
|
||||
let default_account = Helpers.Account.create "default_account" in
|
||||
|
||||
test_endorsement_rights default_account head >>=? fun has_right_to_endorse ->
|
||||
test_endorsement_rights
|
||||
default_account genesis >>=? fun has_right_to_endorse ->
|
||||
Assert.equal_bool ~msg:__LOC__ has_right_to_endorse false ;
|
||||
test_endorsement_rights b1 head >>=? fun has_right_to_endorse ->
|
||||
test_endorsement_rights b1 genesis >>=? fun has_right_to_endorse ->
|
||||
Assert.equal_bool ~msg:__LOC__ has_right_to_endorse true ;
|
||||
test_endorsement_rights b1 head >>=? fun has_right_to_endorse ->
|
||||
test_endorsement_rights b1 genesis >>=? fun has_right_to_endorse ->
|
||||
Assert.equal_bool ~msg:__LOC__ has_right_to_endorse true ;
|
||||
|
||||
Assert.balance_equal ~block:head ~msg:__LOC__ b1 4_000_000_00L >>=? fun () ->
|
||||
Assert.balance_equal ~block:head ~msg:__LOC__ b2 4_000_000_00L >>=? fun () ->
|
||||
Assert.balance_equal ~block:head ~msg:__LOC__ b3 4_000_000_00L >>=? fun () ->
|
||||
Assert.balance_equal ~block:head ~msg:__LOC__ b4 4_000_000_00L >>=? fun () ->
|
||||
Assert.balance_equal ~block:head ~msg:__LOC__ b5 4_000_000_00L >>=? fun () ->
|
||||
Assert.balance_equal
|
||||
~block:genesis ~msg:__LOC__ b1 4_000_000_00L >>=? fun () ->
|
||||
Assert.balance_equal
|
||||
~block:genesis ~msg:__LOC__ b2 4_000_000_00L >>=? fun () ->
|
||||
Assert.balance_equal
|
||||
~block:genesis ~msg:__LOC__ b3 4_000_000_00L >>=? fun () ->
|
||||
Assert.balance_equal
|
||||
~block:genesis ~msg:__LOC__ b4 4_000_000_00L >>=? fun () ->
|
||||
Assert.balance_equal
|
||||
~block:genesis ~msg:__LOC__ b5 4_000_000_00L >>=? fun () ->
|
||||
|
||||
(* Check Rewards *)
|
||||
test_endorsement_rewards head baccounts >>=? fun head ->
|
||||
test_endorsement_rewards genesis >>=? fun () ->
|
||||
|
||||
(* Endorse with a contract with wrong delegate:
|
||||
- contract with no endorsement rights
|
||||
- contract which signs at every available slots *)
|
||||
test_wrong_delegate ~miner:b1 default_account head >>= fun () ->
|
||||
test_wrong_delegate ~miner:b1 b5 head >>= fun () ->
|
||||
test_wrong_delegate ~miner:b1 default_account genesis >>= fun () ->
|
||||
test_wrong_delegate ~miner:b1 b5 genesis >>= fun () ->
|
||||
|
||||
(* Endorse with a wrong slot : -1 and max (16) *)
|
||||
test_invalid_endorsement_slot b3 (`Hash head) >>=? fun () ->
|
||||
test_invalid_endorsement_slot b3 genesis >>=? fun () ->
|
||||
|
||||
(* FIXME: Mining.Invalid_signature is still unclassified *)
|
||||
test_invalid_signature (`Hash head) >>=? fun _ ->
|
||||
test_invalid_signature genesis >>=? fun _ ->
|
||||
|
||||
(* FIXME: cannot inject double endorsement operation yet, but the
|
||||
code is still here
|
||||
Double endorsement *)
|
||||
test_double_endorsement b4 (`Hash head) >>=? fun new_head ->
|
||||
test_double_endorsement b4 genesis >>=? fun _ ->
|
||||
|
||||
return new_head
|
||||
return ()
|
||||
|
||||
let main () =
|
||||
Helpers.init () >>=? fun (_node_pid, hash) ->
|
||||
run (`Hash hash) Helpers.Account.bootstrap_accounts >>=? fun _blkh ->
|
||||
return ()
|
||||
Helpers.init () >>=? fun (_node_pid, genesis) ->
|
||||
run (`Hash genesis)
|
||||
|
||||
|
||||
let tests = [
|
||||
|
@ -54,7 +54,7 @@ let incr_timestamp timestamp =
|
||||
|
||||
let operation op =
|
||||
let op : Operation.t = {
|
||||
shell = { net_id } ;
|
||||
shell = { net_id ; branch = genesis_block } ;
|
||||
proto = MBytes.of_string op ;
|
||||
} in
|
||||
Operation.hash op,
|
||||
|
@ -63,7 +63,7 @@ let net_id = Net_id.of_block_hash genesis_block
|
||||
(** Operation store *)
|
||||
|
||||
let make proto : Tezos_data.Operation.t =
|
||||
{ shell = { net_id } ; proto }
|
||||
{ shell = { net_id ; branch = genesis_block } ; proto }
|
||||
|
||||
let op1 = make (MBytes.of_string "Capadoce")
|
||||
let oph1 = Tezos_data.Operation.hash op1
|
||||
|
Loading…
Reference in New Issue
Block a user