Shell: add context
in block header
This commit is contained in:
parent
270dc3e9e8
commit
009d562e08
@ -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 ;
|
||||
|
@ -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
|
||||
|
@ -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 ;
|
||||
|
@ -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 ;
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
|
@ -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."
|
||||
|
@ -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 ;
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 ()
|
||||
|
@ -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 ;
|
||||
|
Loading…
Reference in New Issue
Block a user