Shell: add context in block header

This commit is contained in:
Grégoire Henry 2017-12-05 15:19:22 +01:00 committed by Grégoire
parent 270dc3e9e8
commit 009d562e08
16 changed files with 92 additions and 59 deletions

View File

@ -15,27 +15,33 @@ type shell_header = {
validation_passes: int ; (* uint8 *) validation_passes: int ; (* uint8 *)
operations_hash: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ; fitness: MBytes.t list ;
context: Context_hash.t ;
} }
let shell_header_encoding = let shell_header_encoding =
let open Data_encoding in let open Data_encoding in
conv conv
(fun { level ; proto_level ; predecessor ; (fun { level ; proto_level ; predecessor ;
timestamp ; validation_passes ; operations_hash ; fitness } -> timestamp ; validation_passes ; operations_hash ; fitness ;
context } ->
(level, proto_level, predecessor, (level, proto_level, predecessor,
timestamp, validation_passes, operations_hash, fitness)) timestamp, validation_passes, operations_hash, fitness,
context))
(fun (level, proto_level, predecessor, (fun (level, proto_level, predecessor,
timestamp, validation_passes, operations_hash, fitness) -> timestamp, validation_passes, operations_hash, fitness,
context) ->
{ level ; proto_level ; predecessor ; { level ; proto_level ; predecessor ;
timestamp ; validation_passes ; operations_hash ; fitness }) timestamp ; validation_passes ; operations_hash ; fitness ;
(obj7 context })
(obj8
(req "level" int32) (req "level" int32)
(req "proto" uint8) (req "proto" uint8)
(req "predecessor" Block_hash.encoding) (req "predecessor" Block_hash.encoding)
(req "timestamp" Time.encoding) (req "timestamp" Time.encoding)
(req "validation_pass" uint8) (req "validation_pass" uint8)
(req "operations_hash" Operation_list_list_hash.encoding) (req "operations_hash" Operation_list_list_hash.encoding)
(req "fitness" Fitness.encoding)) (req "fitness" Fitness.encoding)
(req "context" Context_hash.encoding))
type t = { type t = {
shell: shell_header ; shell: shell_header ;

View File

@ -15,6 +15,7 @@ type shell_header = {
validation_passes: int ; (* uint8 *) validation_passes: int ; (* uint8 *)
operations_hash: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ; fitness: MBytes.t list ;
context: Context_hash.t ;
} }
val shell_header_encoding: shell_header Data_encoding.t val shell_header_encoding: shell_header Data_encoding.t

View File

@ -61,6 +61,7 @@ module Blocks = struct
validation_passes: int ; (* uint8 *) validation_passes: int ; (* uint8 *)
operations_hash: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ; fitness: MBytes.t list ;
context: Context_hash.t ;
data: MBytes.t ; data: MBytes.t ;
operations: (Operation_hash.t * Operation.t) list list option ; operations: (Operation_hash.t * Operation.t) list list option ;
protocol: Protocol_hash.t ; protocol: Protocol_hash.t ;

View File

@ -89,6 +89,7 @@ module Blocks : sig
validation_passes: int ; (* uint8 *) validation_passes: int ; (* uint8 *)
operations_hash: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ; fitness: MBytes.t list ;
context: Context_hash.t ;
data: MBytes.t ; data: MBytes.t ;
operations: (Operation_hash.t * Operation.t) list list option ; operations: (Operation_hash.t * Operation.t) list list option ;
protocol: Protocol_hash.t ; protocol: Protocol_hash.t ;

View File

@ -82,14 +82,16 @@ type error +=
let parse let parse
({ shell = { level ; proto_level ; predecessor ; ({ shell = { level ; proto_level ; predecessor ;
timestamp ; fitness ; validation_passes ; operations_hash } ; timestamp ; fitness ; validation_passes ; operations_hash ;
context } ;
proto } : Block_header.t) : block_header tzresult = proto } : Block_header.t) : block_header tzresult =
match Data_encoding.Binary.of_bytes signed_proto_header_encoding proto with match Data_encoding.Binary.of_bytes signed_proto_header_encoding proto with
| None -> Error [Cant_parse_proto_header] | None -> Error [Cant_parse_proto_header]
| Some (proto, signature) -> | Some (proto, signature) ->
let shell = let shell =
{ Block_header.level ; proto_level ; predecessor ; { Block_header.level ; proto_level ; predecessor ;
timestamp ; fitness ; validation_passes ; operations_hash } in timestamp ; fitness ; validation_passes ; operations_hash ;
context } in
Ok { shell ; proto ; signature } Ok { shell ; proto ; signature }
let parse_unsigned_proto_header bytes = let parse_unsigned_proto_header bytes =

View File

@ -40,12 +40,12 @@ module Forge = struct
~input: ~input:
(merge_objs (merge_objs
(obj6 (obj6
(req "net_id" Net_id.encoding)
(req "level" int32) (req "level" int32)
(req "proto_level" uint8) (req "proto_level" uint8)
(req "predecessor" Block_hash.encoding) (req "predecessor" Block_hash.encoding)
(req "timestamp" Time.encoding) (req "timestamp" Time.encoding)
(req "fitness" Fitness.encoding)) (req "fitness" Fitness.encoding)
(req "context" Context_hash.encoding))
Data.Command.encoding) Data.Command.encoding)
~output: (obj1 (req "payload" bytes)) ~output: (obj1 (req "payload" bytes))
~error: Data_encoding.empty ~error: Data_encoding.empty
@ -66,11 +66,11 @@ let rpc_services : Updater.rpc_context RPC_directory.t =
RPC_directory.register RPC_directory.register
dir dir
(Forge.block RPC_path.open_root) (Forge.block RPC_path.open_root)
(fun _ctxt () ((_net_id, level, proto_level, predecessor, (fun _ctxt () ((level, proto_level, predecessor,
timestamp, fitness), command) -> timestamp, fitness, context), command) ->
let shell = { Block_header.level ; proto_level ; predecessor ; let shell = { Block_header.level ; proto_level ; predecessor ;
timestamp ; fitness ; validation_passes = 0 ; timestamp ; fitness ; validation_passes = 0 ;
operations_hash } in operations_hash ; context } in
let bytes = Data.Command.forge shell command in let bytes = Data.Command.forge shell command in
RPC_answer.return bytes) in RPC_answer.return bytes) in
dir dir

View File

@ -68,6 +68,7 @@ module Blocks = struct
validation_passes: int ; (* uint8 *) validation_passes: int ; (* uint8 *)
operations_hash: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ; fitness: MBytes.t list ;
context: Context_hash.t ;
data: MBytes.t ; data: MBytes.t ;
operations: (Operation_hash.t * Operation.t) list list option ; operations: (Operation_hash.t * Operation.t) list list option ;
protocol: Protocol_hash.t ; protocol: Protocol_hash.t ;
@ -82,21 +83,23 @@ module Blocks = struct
conv conv
(fun { hash ; net_id ; level ; proto_level ; predecessor ; (fun { hash ; net_id ; level ; proto_level ; predecessor ;
fitness ; timestamp ; protocol ; fitness ; timestamp ; protocol ;
validation_passes ; operations_hash ; data ; validation_passes ; operations_hash ; context ; data ;
operations ; test_network } -> operations ; test_network } ->
((hash, net_id, operations, protocol, test_network), ((hash, net_id, operations, protocol, test_network),
{ Block_header.shell = { Block_header.shell =
{ level ; proto_level ; predecessor ; { level ; proto_level ; predecessor ;
timestamp ; validation_passes ; operations_hash ; fitness } ; timestamp ; validation_passes ; operations_hash ; fitness ;
context } ;
proto = data })) proto = data }))
(fun ((hash, net_id, operations, protocol, test_network), (fun ((hash, net_id, operations, protocol, test_network),
{ Block_header.shell = { Block_header.shell =
{ level ; proto_level ; predecessor ; { level ; proto_level ; predecessor ;
timestamp ; validation_passes ; operations_hash ; fitness } ; timestamp ; validation_passes ; operations_hash ; fitness ;
context } ;
proto = data }) -> proto = data }) ->
{ hash ; net_id ; level ; proto_level ; predecessor ; { hash ; net_id ; level ; proto_level ; predecessor ;
fitness ; timestamp ; protocol ; fitness ; timestamp ; protocol ;
validation_passes ; operations_hash ; data ; validation_passes ; operations_hash ; context ; data ;
operations ; test_network }) operations ; test_network })
(dynamic_size (dynamic_size
(merge_objs (merge_objs
@ -214,6 +217,15 @@ module Blocks = struct
~error: Data_encoding.empty ~error: Data_encoding.empty
RPC_path.(block_path / "fitness") RPC_path.(block_path / "fitness")
let context =
RPC_service.post_service
~description:"Returns the hash of the resulting context."
~query: RPC_query.empty
~input: empty
~output: (obj1 (req "context" Context_hash.encoding))
~error: Data_encoding.empty
RPC_path.(block_path / "context")
let timestamp = let timestamp =
RPC_service.post_service RPC_service.post_service
~description:"Returns the block's timestamp." ~description:"Returns the block's timestamp."

View File

@ -37,6 +37,7 @@ module Blocks : sig
validation_passes: int ; (* uint8 *) validation_passes: int ; (* uint8 *)
operations_hash: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ; fitness: MBytes.t list ;
context: Context_hash.t ;
data: MBytes.t ; data: MBytes.t ;
operations: (Operation_hash.t * Operation.t) list list option ; operations: (Operation_hash.t * Operation.t) list list option ;
protocol: Protocol_hash.t ; protocol: Protocol_hash.t ;
@ -75,6 +76,10 @@ module Blocks : sig
([ `POST ], unit, ([ `POST ], unit,
unit * block, unit, unit, unit * block, unit, unit,
MBytes.t list, unit) RPC_service.t MBytes.t list, unit) RPC_service.t
val context:
([ `POST ], unit,
unit * block, unit, unit,
Context_hash.t, unit) RPC_service.t
type operations_param = { type operations_param = {
contents: bool ; contents: bool ;

View File

@ -149,6 +149,7 @@ module RPC = struct
validation_passes: int ; (* uint8 *) validation_passes: int ; (* uint8 *)
operations_hash: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ; fitness: MBytes.t list ;
context: Context_hash.t ;
data: MBytes.t ; data: MBytes.t ;
operations: (Operation_hash.t * Operation.t) list list option ; operations: (Operation_hash.t * Operation.t) list list option ;
protocol: Protocol_hash.t ; protocol: Protocol_hash.t ;
@ -174,6 +175,7 @@ module RPC = struct
validation_passes = header.shell.validation_passes ; validation_passes = header.shell.validation_passes ;
operations_hash = header.shell.operations_hash ; operations_hash = header.shell.operations_hash ;
fitness = header.shell.fitness ; fitness = header.shell.fitness ;
context = header.shell.context ;
data = header.proto ; data = header.proto ;
operations = Some operations ; operations = Some operations ;
protocol ; protocol ;
@ -281,6 +283,7 @@ module RPC = struct
(fun ops -> Operation_list_hash.compute (List.map fst ops)) (fun ops -> Operation_list_hash.compute (List.map fst ops))
operations) ; operations) ;
operations = Some operations ; operations = Some operations ;
context = Context_hash.zero ;
data = MBytes.of_string "" ; data = MBytes.of_string "" ;
net_id = head_net_id ; net_id = head_net_id ;
test_network ; test_network ;
@ -356,6 +359,7 @@ module RPC = struct
validation_passes = List.length operation_hashes ; validation_passes = List.length operation_hashes ;
operations_hash ; operations_hash ;
fitness ; fitness ;
context = Context_hash.zero ;
} ; } ;
proto = MBytes.create 0 ; proto = MBytes.create 0 ;
} ; } ;
@ -490,7 +494,7 @@ module RPC = struct
(List.map fst r.Preapply_result.applied)) (List.map fst r.Preapply_result.applied))
rs) in rs) in
Prevalidation.end_prevalidation Prevalidation.end_prevalidation
validation_state >>=? fun { fitness ; context } -> validation_state >>=? fun { fitness ; context ; message } ->
let pred_shell_header = State.Block.shell_header predecessor in let pred_shell_header = State.Block.shell_header predecessor in
State.Block.protocol_hash predecessor >>= fun pred_protocol -> State.Block.protocol_hash predecessor >>= fun pred_protocol ->
Context.get_protocol context >>= fun protocol -> Context.get_protocol context >>= fun protocol ->
@ -499,6 +503,7 @@ module RPC = struct
pred_shell_header.proto_level pred_shell_header.proto_level
else else
((pred_shell_header.proto_level + 1) mod 256) in ((pred_shell_header.proto_level + 1) mod 256) in
Context.commit ?message ~time:timestamp context >>= fun context ->
let shell_header : Block_header.shell_header = { let shell_header : Block_header.shell_header = {
level = Int32.succ pred_shell_header.level ; level = Int32.succ pred_shell_header.level ;
proto_level ; proto_level ;
@ -507,6 +512,7 @@ module RPC = struct
validation_passes = List.length rs ; validation_passes = List.length rs ;
operations_hash ; operations_hash ;
fitness ; fitness ;
context ;
} in } in
return (shell_header, rs) return (shell_header, rs)

View File

@ -159,6 +159,7 @@ module Locked_block = struct
fitness = [] ; fitness = [] ;
validation_passes = 0 ; validation_passes = 0 ;
operations_hash = Operation_list_list_hash.empty ; operations_hash = Operation_list_list_hash.empty ;
context ;
} in } in
let header : Block_header.t = { shell ; proto = MBytes.create 0 } in let header : Block_header.t = { shell ; proto = MBytes.create 0 } in
Store.Block.Contents.store (store, genesis.block) Store.Block.Contents.store (store, genesis.block)

View File

@ -101,6 +101,7 @@ module Node_protocol_environment_sigs = struct
and type Hash.Block_hash.t = Block_hash.t and type Hash.Block_hash.t = Block_hash.t
and type Hash.Operation_hash.t = Operation_hash.t and type Hash.Operation_hash.t = Operation_hash.t
and type Hash.Operation_list_list_hash.t = Operation_list_list_hash.t and type Hash.Operation_list_list_hash.t = Operation_list_list_hash.t
and type Hash.Context_hash.t = Context_hash.t
and type Context.t = Context.t and type Context.t = Context.t
and type Time.t = Time.t and type Time.t = Time.t
and type MBytes.t = MBytes.t and type MBytes.t = MBytes.t

View File

@ -91,6 +91,7 @@ module Node_protocol_environment_sigs : sig
and type Hash.Block_hash.t = Block_hash.t and type Hash.Block_hash.t = Block_hash.t
and type Hash.Operation_hash.t = Operation_hash.t and type Hash.Operation_hash.t = Operation_hash.t
and type Hash.Operation_list_list_hash.t = Operation_list_list_hash.t and type Hash.Operation_list_list_hash.t = Operation_list_list_hash.t
and type Hash.Context_hash.t = Context_hash.t
and type Context.t = Context.t and type Context.t = Context.t
and type Time.t = Time.t and type Time.t = Time.t
and type MBytes.t = MBytes.t and type MBytes.t = MBytes.t

View File

@ -131,4 +131,7 @@ module Operation_list_list_hash :
(** Protocol versions / source hashes. *) (** Protocol versions / source hashes. *)
module Protocol_hash : HASH module Protocol_hash : HASH
(** Commited conntext. *)
module Context_hash : HASH
module Net_id : HASH module Net_id : HASH

View File

@ -85,6 +85,7 @@ module Block_header : sig
validation_passes: int ; validation_passes: int ;
operations_hash: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ; fitness: MBytes.t list ;
context: Context_hash.t ;
} }
val shell_header_encoding: shell_header Data_encoding.t val shell_header_encoding: shell_header Data_encoding.t

View File

@ -58,21 +58,6 @@ let operation op =
op, op,
Data_encoding.Binary.to_bytes Operation.encoding op Data_encoding.Binary.to_bytes Operation.encoding op
let block _state ?(operations = []) pred_hash pred name : Block_header.t =
let operations_hash =
Operation_list_list_hash.compute
[Operation_list_hash.compute operations] in
let fitness = incr_fitness pred.Block_header.shell.fitness in
let timestamp = incr_timestamp pred.shell.timestamp in
{ shell = {
level = Int32.succ pred.shell.level ;
proto_level = pred.shell.proto_level ;
predecessor = pred_hash ;
validation_passes = 1 ;
timestamp ; operations_hash ; fitness } ;
proto = MBytes.of_string name ;
}
let equal_operation ?msg op1 op2 = let equal_operation ?msg op1 op2 =
let msg = Assert.format_msg msg in let msg = Assert.format_msg msg in
let eq op1 op2 = let eq op1 op2 =
@ -98,7 +83,7 @@ let equal_block ?msg st1 st2 =
| Some st -> Block_hash.to_hex (Block_header.hash st) in | Some st -> Block_hash.to_hex (Block_header.hash st) in
Assert.equal ?msg ~prn ~eq st1 st2 Assert.equal ?msg ~prn ~eq st1 st2
let block _state ?(operations = []) (pred: State.Block.t) name let block _state ?(context = Context_hash.zero) ?(operations = []) (pred: State.Block.t) name
: Block_header.t = : Block_header.t =
let operations_hash = let operations_hash =
Operation_list_list_hash.compute Operation_list_list_hash.compute
@ -110,19 +95,21 @@ let block _state ?(operations = []) (pred: State.Block.t) name
proto_level = pred_header.proto_level ; proto_level = pred_header.proto_level ;
predecessor = State.Block.hash pred ; predecessor = State.Block.hash pred ;
validation_passes = 1 ; validation_passes = 1 ;
timestamp ; operations_hash ; fitness } ; timestamp ; operations_hash ; fitness ;
context } ;
proto = MBytes.of_string name ; proto = MBytes.of_string name ;
} }
let build_valid_chain state vtbl pred names = let build_valid_chain state vtbl pred names =
Lwt_list.fold_left_s Lwt_list.fold_left_s
(fun pred name -> (fun pred name ->
State.Block.context pred >>= fun predecessor_context ->
let rec attempt context =
begin begin
let oph, op, _bytes = operation name in let oph, op, _bytes = operation name in
let block = block state ~operations:[oph] pred name in let block = block ?context state ~operations:[oph] pred name in
let hash = Block_header.hash block in let hash = Block_header.hash block in
let pred_header = State.Block.header pred in let pred_header = State.Block.header pred in
State.Block.context pred >>= fun predecessor_context ->
begin begin
Proto.begin_application Proto.begin_application
~predecessor_context ~predecessor_context
@ -138,9 +125,13 @@ let build_valid_chain state vtbl pred names =
return vblock return vblock
end >>= function end >>= function
| Ok v -> Lwt.return v | Ok v -> Lwt.return v
| Error [ State.Block.Inconsistent_hash (got, _) ] ->
(* Kind of a hack, but at least it tests idempotence to some extent. *)
attempt (Some got)
| Error err -> | Error err ->
Error_monad.pp_print_error Format.err_formatter err ; Error_monad.pp_print_error Format.err_formatter err ;
assert false) assert false in
attempt None)
pred pred
names >>= fun _ -> names >>= fun _ ->
Lwt.return () Lwt.return ()

View File

@ -83,7 +83,8 @@ let lolblock ?(operations = []) header =
validation_passes = Random.int 32 ; validation_passes = Random.int 32 ;
predecessor = genesis_block ; operations_hash ; predecessor = genesis_block ; operations_hash ;
fitness = [MBytes.of_string @@ string_of_int @@ String.length header; fitness = [MBytes.of_string @@ string_of_int @@ String.length header;
MBytes.of_string @@ string_of_int @@ 12] } ; MBytes.of_string @@ string_of_int @@ 12] ;
context = Context_hash.zero } ;
proto = MBytes.of_string header ; proto = MBytes.of_string header ;
} ; } ;
max_operations_ttl = 0 ; max_operations_ttl = 0 ;