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 *)
operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ;
context: Context_hash.t ;
}
let shell_header_encoding =
let open Data_encoding in
conv
(fun { level ; proto_level ; predecessor ;
timestamp ; validation_passes ; operations_hash ; fitness } ->
timestamp ; validation_passes ; operations_hash ; fitness ;
context } ->
(level, proto_level, predecessor,
timestamp, validation_passes, operations_hash, fitness))
timestamp, validation_passes, operations_hash, fitness,
context))
(fun (level, proto_level, predecessor,
timestamp, validation_passes, operations_hash, fitness) ->
timestamp, validation_passes, operations_hash, fitness,
context) ->
{ level ; proto_level ; predecessor ;
timestamp ; validation_passes ; operations_hash ; fitness })
(obj7
timestamp ; validation_passes ; operations_hash ; fitness ;
context })
(obj8
(req "level" int32)
(req "proto" uint8)
(req "predecessor" Block_hash.encoding)
(req "timestamp" Time.encoding)
(req "validation_pass" uint8)
(req "operations_hash" Operation_list_list_hash.encoding)
(req "fitness" Fitness.encoding))
(req "fitness" Fitness.encoding)
(req "context" Context_hash.encoding))
type t = {
shell: shell_header ;

View File

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

View File

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

View File

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

View File

@ -82,14 +82,16 @@ type error +=
let parse
({ 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 =
match Data_encoding.Binary.of_bytes signed_proto_header_encoding proto with
| None -> Error [Cant_parse_proto_header]
| Some (proto, signature) ->
let shell =
{ 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 }
let parse_unsigned_proto_header bytes =

View File

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

View File

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

View File

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

View File

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

View File

@ -159,6 +159,7 @@ module Locked_block = struct
fitness = [] ;
validation_passes = 0 ;
operations_hash = Operation_list_list_hash.empty ;
context ;
} in
let header : Block_header.t = { shell ; proto = MBytes.create 0 } in
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.Operation_hash.t = Operation_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 Time.t = Time.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.Operation_hash.t = Operation_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 Time.t = Time.t
and type MBytes.t = MBytes.t

View File

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

View File

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

View File

@ -58,21 +58,6 @@ let operation op =
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 msg = Assert.format_msg msg in
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
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 =
let operations_hash =
Operation_list_list_hash.compute
@ -110,37 +95,43 @@ let block _state ?(operations = []) (pred: State.Block.t) name
proto_level = pred_header.proto_level ;
predecessor = State.Block.hash pred ;
validation_passes = 1 ;
timestamp ; operations_hash ; fitness } ;
timestamp ; operations_hash ; fitness ;
context } ;
proto = MBytes.of_string name ;
}
let build_valid_chain state vtbl pred names =
Lwt_list.fold_left_s
(fun pred name ->
begin
let oph, op, _bytes = operation name in
let block = block state ~operations:[oph] pred name in
let hash = Block_header.hash block in
let pred_header = State.Block.header pred in
State.Block.context pred >>= fun predecessor_context ->
State.Block.context pred >>= fun predecessor_context ->
let rec attempt context =
begin
Proto.begin_application
~predecessor_context
~predecessor_timestamp: pred_header.shell.timestamp
~predecessor_fitness: pred_header.shell.fitness
block >>=? fun vstate ->
(* no operations *)
Proto.finalize_block vstate
end >>=? fun ctxt ->
State.Block.store state block [[op]] ctxt >>=? fun _vblock ->
State.Block.read state hash >>=? fun vblock ->
Hashtbl.add vtbl name vblock ;
return vblock
end >>= function
| Ok v -> Lwt.return v
| Error err ->
Error_monad.pp_print_error Format.err_formatter err ;
assert false)
let oph, op, _bytes = operation name in
let block = block ?context state ~operations:[oph] pred name in
let hash = Block_header.hash block in
let pred_header = State.Block.header pred in
begin
Proto.begin_application
~predecessor_context
~predecessor_timestamp: pred_header.shell.timestamp
~predecessor_fitness: pred_header.shell.fitness
block >>=? fun vstate ->
(* no operations *)
Proto.finalize_block vstate
end >>=? fun ctxt ->
State.Block.store state block [[op]] ctxt >>=? fun _vblock ->
State.Block.read state hash >>=? fun vblock ->
Hashtbl.add vtbl name vblock ;
return vblock
end >>= function
| 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_monad.pp_print_error Format.err_formatter err ;
assert false in
attempt None)
pred
names >>= fun _ ->
Lwt.return ()

View File

@ -83,7 +83,8 @@ let lolblock ?(operations = []) header =
validation_passes = Random.int 32 ;
predecessor = genesis_block ; operations_hash ;
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 ;
} ;
max_operations_ttl = 0 ;