Shell: add the number of validation passes in the block header.

This commit is contained in:
Grégoire Henry 2017-09-29 18:43:13 +02:00 committed by Benjamin Canou
parent f7aed9d45d
commit 5c1f96f3a1
20 changed files with 62 additions and 48 deletions

View File

@ -63,6 +63,7 @@ module Blocks = struct
proto_level: int ; (* uint8 *) proto_level: int ; (* uint8 *)
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
timestamp: Time.t ; timestamp: Time.t ;
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 ;
data: MBytes.t ; data: MBytes.t ;

View File

@ -99,6 +99,7 @@ module Blocks : sig
proto_level: int ; (* uint8 *) proto_level: int ; (* uint8 *)
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
timestamp: Time.t ; timestamp: Time.t ;
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 ;
data: MBytes.t ; data: MBytes.t ;

View File

@ -53,6 +53,7 @@ let mine cctxt =
level = Int32.succ bi.level ; level = Int32.succ bi.level ;
timestamp = Time.now () ; timestamp = Time.now () ;
fitness ; fitness ;
validation_passes = 0 ;
operations_hash = Operation_list_list_hash.empty } ; operations_hash = Operation_list_list_hash.empty } ;
proto = MBytes.create 0 } >>=? fun bytes -> proto = MBytes.create 0 } >>=? fun bytes ->
Client_node_rpcs.inject_block cctxt.rpc_config bytes [] >>=? fun hash -> Client_node_rpcs.inject_block cctxt.rpc_config bytes [] >>=? fun hash ->

View File

@ -69,6 +69,7 @@ module Block_header : sig
proto_level: int ; (* uint8 *) proto_level: int ; (* uint8 *)
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
timestamp: Time.t ; timestamp: Time.t ;
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 ;
} }

View File

@ -85,7 +85,6 @@ module Block = struct
type contents = { type contents = {
header: Block_header.t ; header: Block_header.t ;
message: string ; message: string ;
operation_list_count: int ;
max_operations_ttl: int ; max_operations_ttl: int ;
context: Context.commit ; context: Context.commit ;
} }
@ -99,17 +98,12 @@ module Block = struct
let encoding = let encoding =
let open Data_encoding in let open Data_encoding in
conv conv
(fun { header ; message ; operation_list_count ; (fun { header ; message ; max_operations_ttl ; context } ->
max_operations_ttl ; context } -> (message, max_operations_ttl, context, header))
(message, operation_list_count, max_operations_ttl, (fun (message, max_operations_ttl, context, header) ->
context, header)) { header ; message ; max_operations_ttl ; context })
(fun (message, operation_list_count, (obj4
max_operations_ttl, context, header) ->
{ header ; message ; max_operations_ttl ;
operation_list_count ; context })
(obj5
(req "message" string) (req "message" string)
(req "operation_list_count" uint8)
(req "max_operations_ttl" uint16) (req "max_operations_ttl" uint16)
(req "context" Context.commit_encoding) (req "context" Context.commit_encoding)
(req "header" Block_header.encoding)) (req "header" Block_header.encoding))

View File

@ -88,7 +88,6 @@ module Block : sig
type contents = { type contents = {
header: Block_header.t ; header: Block_header.t ;
message: string ; message: string ;
operation_list_count: int ;
max_operations_ttl: int ; max_operations_ttl: int ;
context: Context.commit ; context: Context.commit ;
} }

View File

@ -736,17 +736,18 @@ let read_all_operations net_db hash n =
map_p (Raw_operation.Table.read net_db.operation_db.table) hashes) map_p (Raw_operation.Table.read net_db.operation_db.table) hashes)
operations operations
let commit_block net_db hash n validation_result = let commit_block net_db hash validation_result =
Raw_block_header.Table.read Raw_block_header.Table.read
net_db.block_header_db.table hash >>=? fun header -> net_db.block_header_db.table hash >>=? fun header ->
read_all_operations net_db hash n >>=? fun operations -> read_all_operations net_db
hash header.shell.validation_passes >>=? fun operations ->
State.Block.store State.Block.store
net_db.net_state header operations validation_result >>=? fun res -> net_db.net_state header operations validation_result >>=? fun res ->
Raw_block_header.Table.clear net_db.block_header_db.table hash ; Raw_block_header.Table.clear net_db.block_header_db.table hash ;
Raw_operation_hashes.clear_all Raw_operation_hashes.clear_all
net_db.operation_hashes_db.table hash n ; net_db.operation_hashes_db.table hash header.shell.validation_passes ;
Raw_operations.clear_all Raw_operations.clear_all
net_db.operations_db.table hash n ; net_db.operations_db.table hash header.shell.validation_passes ;
(* TODO: proper handling of the operations table by the prevalidator. *) (* TODO: proper handling of the operations table by the prevalidator. *)
List.iter List.iter
(List.iter (List.iter
@ -756,13 +757,15 @@ let commit_block net_db hash n validation_result =
operations ; operations ;
return res return res
let commit_invalid_block net_db hash n = let commit_invalid_block net_db hash =
Raw_block_header.Table.read Raw_block_header.Table.read
net_db.block_header_db.table hash >>=? fun header -> net_db.block_header_db.table hash >>=? fun header ->
State.Block.store_invalid net_db.net_state header >>=? fun res -> State.Block.store_invalid net_db.net_state header >>=? fun res ->
Raw_block_header.Table.clear net_db.block_header_db.table hash ; Raw_block_header.Table.clear net_db.block_header_db.table hash ;
Raw_operation_hashes.clear_all net_db.operation_hashes_db.table hash n ; Raw_operation_hashes.clear_all
Raw_operations.clear_all net_db.operations_db.table hash n ; net_db.operation_hashes_db.table hash header.shell.validation_passes ;
Raw_operations.clear_all
net_db.operations_db.table hash header.shell.validation_passes ;
return res return res
let inject_operation net_db h op = let inject_operation net_db h op =

View File

@ -43,10 +43,10 @@ val resolve_operation:
net_db -> operation -> (Operation_hash.t * Operation.t) tzresult Lwt.t net_db -> operation -> (Operation_hash.t * Operation.t) tzresult Lwt.t
val commit_block: val commit_block:
net_db -> Block_hash.t -> int -> Updater.validation_result -> net_db -> Block_hash.t -> Updater.validation_result ->
State.Block.t option tzresult Lwt.t State.Block.t option tzresult Lwt.t
val commit_invalid_block: val commit_invalid_block:
net_db -> Block_hash.t -> int -> net_db -> Block_hash.t ->
bool tzresult Lwt.t bool tzresult Lwt.t
val inject_block: val inject_block:
t -> MBytes.t -> operation list list -> t -> MBytes.t -> operation list list ->

View File

@ -143,6 +143,7 @@ module RPC = struct
proto_level: int ; (* uint8 *) proto_level: int ; (* uint8 *)
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
timestamp: Time.t ; timestamp: Time.t ;
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 ;
data: MBytes.t ; data: MBytes.t ;
@ -165,6 +166,7 @@ module RPC = struct
proto_level = header.shell.proto_level ; proto_level = header.shell.proto_level ;
predecessor = header.shell.predecessor ; predecessor = header.shell.predecessor ;
timestamp = header.shell.timestamp ; timestamp = header.shell.timestamp ;
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 ;
data = header.proto ; data = header.proto ;
@ -275,6 +277,7 @@ module RPC = struct
fitness ; fitness ;
timestamp = Prevalidator.timestamp pv ; timestamp = Prevalidator.timestamp pv ;
protocol ; protocol ;
validation_passes = List.length operations ;
operations_hash = operations_hash =
Operation_list_list_hash.compute Operation_list_list_hash.compute
(List.map Operation_list_hash.compute operations) ; (List.map Operation_list_hash.compute operations) ;
@ -350,6 +353,7 @@ module RPC = struct
proto_level ; proto_level ;
predecessor = head_hash ; predecessor = head_hash ;
timestamp = Prevalidator.timestamp pv ; timestamp = Prevalidator.timestamp pv ;
validation_passes = List.length operation_hashes ;
operations_hash ; operations_hash ;
fitness ; fitness ;
} ; } ;
@ -501,6 +505,7 @@ module RPC = struct
proto_level ; proto_level ;
predecessor = State.Block.hash predecessor ; predecessor = State.Block.hash predecessor ;
timestamp ; timestamp ;
validation_passes = 1 ;
operations_hash ; operations_hash ;
fitness ; fitness ;
} in } in

View File

@ -77,6 +77,7 @@ module Blocks = struct
proto_level: int ; (* uint8 *) proto_level: int ; (* uint8 *)
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
timestamp: Time.t ; timestamp: Time.t ;
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 ;
data: MBytes.t ; data: MBytes.t ;
@ -88,20 +89,22 @@ module Blocks = struct
let block_info_encoding = let block_info_encoding =
conv conv
(fun { hash ; net_id ; level ; proto_level ; predecessor ; (fun { hash ; net_id ; level ; proto_level ; predecessor ;
fitness ; timestamp ; protocol ; operations_hash ; data ; fitness ; timestamp ; protocol ;
validation_passes ; operations_hash ; data ;
operations ; test_network } -> operations ; test_network } ->
((hash, operations, protocol, test_network), ((hash, operations, protocol, test_network),
{ Block_header.shell = { Block_header.shell =
{ net_id ; level ; proto_level ; predecessor ; { net_id ; level ; proto_level ; predecessor ;
timestamp ; operations_hash ; fitness } ; timestamp ; validation_passes ; operations_hash ; fitness } ;
proto = data })) proto = data }))
(fun ((hash, operations, protocol, test_network), (fun ((hash, operations, protocol, test_network),
{ Block_header.shell = { Block_header.shell =
{ net_id ; level ; proto_level ; predecessor ; { net_id ; level ; proto_level ; predecessor ;
timestamp ; operations_hash ; fitness } ; timestamp ; validation_passes ; operations_hash ; fitness } ;
proto = data }) -> proto = data }) ->
{ hash ; net_id ; level ; proto_level ; predecessor ; { hash ; net_id ; level ; proto_level ; predecessor ;
fitness ; timestamp ; protocol ; operations_hash ; data ; fitness ; timestamp ; protocol ;
validation_passes ; operations_hash ; data ;
operations ; test_network }) operations ; test_network })
(dynamic_size (dynamic_size
(merge_objs (merge_objs

View File

@ -39,6 +39,7 @@ module Blocks : sig
proto_level: int ; (* uint8 *) proto_level: int ; (* uint8 *)
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
timestamp: Time.t ; timestamp: Time.t ;
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 ;
data: MBytes.t ; data: MBytes.t ;

View File

@ -114,13 +114,13 @@ module Locked_block = struct
predecessor = genesis.block ; predecessor = genesis.block ;
timestamp = genesis.time ; timestamp = genesis.time ;
fitness = [] ; fitness = [] ;
validation_passes = 0 ;
operations_hash = Operation_list_list_hash.empty ; operations_hash = Operation_list_list_hash.empty ;
} 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)
{ Store.Block.header ; message = "Genesis" ; { Store.Block.header ; message = "Genesis" ;
operation_list_count = 0 ; max_operations_ttl = 0 ; max_operations_ttl = 0 ; context = commit } >>= fun () ->
context = commit } >>= fun () ->
Lwt.return header Lwt.return header
end end
@ -311,9 +311,8 @@ module Block = struct
let fitness b = (shell_header b).fitness let fitness b = (shell_header b).fitness
let level b = (shell_header b).level let level b = (shell_header b).level
let proto_level b = (shell_header b).proto_level let proto_level b = (shell_header b).proto_level
let validation_passes b = (shell_header b).validation_passes
let message { contents = { message } } = message let message { contents = { message } } = message
let operation_list_count { contents = { operation_list_count } } =
operation_list_count
let max_operations_ttl { contents = { max_operations_ttl } } = let max_operations_ttl { contents = { max_operations_ttl } } =
max_operations_ttl max_operations_ttl
@ -395,7 +394,6 @@ module Block = struct
let contents = { let contents = {
Store.Block.header = block_header ; Store.Block.header = block_header ;
message ; message ;
operation_list_count = List.length operations ;
max_operations_ttl ; max_operations_ttl ;
context = commit ; context = commit ;
} in } in
@ -444,7 +442,7 @@ module Block = struct
Watcher.create_stream net_state.block_watcher Watcher.create_stream net_state.block_watcher
let operation_hashes { net_state ; hash ; contents } i = let operation_hashes { net_state ; hash ; contents } i =
if i < 0 || contents.operation_list_count <= i then if i < 0 || contents.header.shell.validation_passes <= i then
invalid_arg "State.Block.operations" ; invalid_arg "State.Block.operations" ;
Shared.use net_state.block_store begin fun store -> Shared.use net_state.block_store begin fun store ->
Store.Block.Operation_hashes.read_exn (store, hash) i >>= fun hashes -> Store.Block.Operation_hashes.read_exn (store, hash) i >>= fun hashes ->
@ -456,11 +454,11 @@ module Block = struct
Shared.use net_state.block_store begin fun store -> Shared.use net_state.block_store begin fun store ->
Lwt_list.map_p Lwt_list.map_p
(Store.Block.Operation_hashes.read_exn (store, hash)) (Store.Block.Operation_hashes.read_exn (store, hash))
(0 -- (contents.operation_list_count - 1)) (0 -- (contents.header.shell.validation_passes - 1))
end end
let operations { net_state ; hash ; contents } i = let operations { net_state ; hash ; contents } i =
if i < 0 || contents.operation_list_count <= i then if i < 0 || contents.header.shell.validation_passes <= i then
invalid_arg "State.Block.operations" ; invalid_arg "State.Block.operations" ;
Shared.use net_state.block_store begin fun store -> Shared.use net_state.block_store begin fun store ->
Store.Block.Operation_path.read_exn (store, hash) i >>= fun path -> Store.Block.Operation_path.read_exn (store, hash) i >>= fun path ->
@ -472,7 +470,7 @@ module Block = struct
Shared.use net_state.block_store begin fun store -> Shared.use net_state.block_store begin fun store ->
Lwt_list.map_p Lwt_list.map_p
(fun i -> Store.Block.Operations.read_exn (store, hash) i) (fun i -> Store.Block.Operations.read_exn (store, hash) i)
(0 -- (contents.operation_list_count - 1)) (0 -- (contents.header.shell.validation_passes - 1))
end end
let context { net_state ; hash } = let context { net_state ; hash } =

View File

@ -118,7 +118,7 @@ module Block : sig
val shell_header: t -> Block_header.shell_header val shell_header: t -> Block_header.shell_header
val timestamp: t -> Time.t val timestamp: t -> Time.t
val fitness: t -> Fitness.t val fitness: t -> Fitness.t
val operation_list_count: t -> int val validation_passes: t -> int
val net_id: t -> Net_id.t val net_id: t -> Net_id.t
val net_state: t -> Net.t val net_state: t -> Net.t
val level: t -> Int32.t val level: t -> Int32.t

View File

@ -254,6 +254,9 @@ let apply_block net_state db
Block_hash.pp_short hash >>= fun () -> Block_hash.pp_short hash >>= fun () ->
Distributed_db.Operations.fetch Distributed_db.Operations.fetch
db (hash, 0) block.shell.operations_hash >>= fun operations -> db (hash, 0) block.shell.operations_hash >>= fun operations ->
fail_unless (block.shell.validation_passes <= 1)
(* TODO constant to be exported from the protocol... *)
(failure "unexpected error (TO BE REMOVED)") >>=? fun () ->
let operation_hashes = List.map Operation.hash operations in let operation_hashes = List.map Operation.hash operations in
lwt_debug "validation of %a: found operations" lwt_debug "validation of %a: found operations"
Block_hash.pp_short hash >>= fun () -> Block_hash.pp_short hash >>= fun () ->
@ -447,7 +450,7 @@ module Context_db = struct
begin begin
match data with match data with
| Ok data -> begin | Ok data -> begin
Distributed_db.commit_block net_db hash 1 data >>=? function Distributed_db.commit_block net_db hash data >>=? function
| None -> | None ->
(* Should not happen if the block is not validated twice *) (* Should not happen if the block is not validated twice *)
assert false assert false
@ -455,7 +458,7 @@ module Context_db = struct
return (Ok block) return (Ok block)
end end
| Error err -> | Error err ->
Distributed_db.commit_invalid_block net_db hash 1 >>=? fun changed -> Distributed_db.commit_invalid_block net_db hash >>=? fun changed ->
assert changed ; assert changed ;
return (Error err) return (Error err)
end >>= function end >>= function

View File

@ -82,14 +82,14 @@ type error +=
let parse let parse
({ shell = { net_id ; level ; proto_level ; predecessor ; ({ shell = { net_id ; level ; proto_level ; predecessor ;
timestamp ; fitness ; operations_hash } ; timestamp ; fitness ; validation_passes ; operations_hash } ;
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.net_id ; level ; proto_level ; predecessor ; { Block_header.net_id ; level ; proto_level ; predecessor ;
timestamp ; fitness ; operations_hash } in timestamp ; fitness ; validation_passes ; operations_hash } in
Ok { shell ; proto ; signature } Ok { shell ; proto ; signature }
let parse_unsigned_proto_header bytes = let parse_unsigned_proto_header bytes =

View File

@ -67,7 +67,7 @@ let rpc_services : Updater.rpc_context RPC.directory =
(fun _ctxt ((net_id, level, proto_level, predecessor, (fun _ctxt ((net_id, level, proto_level, predecessor,
timestamp, fitness), command) -> timestamp, fitness), command) ->
let shell = { Block_header.net_id ; level ; proto_level ; predecessor ; let shell = { Block_header.net_id ; level ; proto_level ; predecessor ;
timestamp ; fitness ; operations_hash } in timestamp ; fitness ; validation_passes = 1 ; operations_hash } 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

@ -172,6 +172,7 @@ module Block_header = struct
proto_level: int ; (* uint8 *) proto_level: int ; (* uint8 *)
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
timestamp: Time.t ; timestamp: Time.t ;
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 ;
} }
@ -180,19 +181,20 @@ module Block_header = struct
let open Data_encoding in let open Data_encoding in
conv conv
(fun { net_id ; level ; proto_level ; predecessor ; (fun { net_id ; level ; proto_level ; predecessor ;
timestamp ; operations_hash ; fitness } -> timestamp ; validation_passes ; operations_hash ; fitness } ->
(net_id, level, proto_level, predecessor, (net_id, level, proto_level, predecessor,
timestamp, operations_hash, fitness)) timestamp, validation_passes, operations_hash, fitness))
(fun (net_id, level, proto_level, predecessor, (fun (net_id, level, proto_level, predecessor,
timestamp, operations_hash, fitness) -> timestamp, validation_passes, operations_hash, fitness) ->
{ net_id ; level ; proto_level ; predecessor ; { net_id ; level ; proto_level ; predecessor ;
timestamp ; operations_hash ; fitness }) timestamp ; validation_passes ; operations_hash ; fitness })
(obj7 (obj8
(req "net_id" Net_id.encoding) (req "net_id" Net_id.encoding)
(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 "operations_hash" Operation_list_list_hash.encoding) (req "operations_hash" Operation_list_list_hash.encoding)
(req "fitness" Fitness.encoding)) (req "fitness" Fitness.encoding))

View File

@ -72,6 +72,7 @@ module Block_header : sig
proto_level: int ; (* uint8 *) proto_level: int ; (* uint8 *)
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
timestamp: Time.t ; timestamp: Time.t ;
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 ;
} }

View File

@ -72,6 +72,7 @@ let block _state ?(operations = []) pred_hash pred name : Block_header.t =
level = Int32.succ pred.shell.level ; level = Int32.succ pred.shell.level ;
proto_level = pred.shell.proto_level ; proto_level = pred.shell.proto_level ;
predecessor = pred_hash ; predecessor = pred_hash ;
validation_passes = 1 ;
timestamp ; operations_hash ; fitness } ; timestamp ; operations_hash ; fitness } ;
proto = MBytes.of_string name ; proto = MBytes.of_string name ;
} }
@ -114,6 +115,7 @@ let block _state ?(operations = []) (pred: State.Block.t) name
level = Int32.succ pred_header.level ; level = Int32.succ pred_header.level ;
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 ;
timestamp ; operations_hash ; fitness } ; timestamp ; operations_hash ; fitness } ;
proto = MBytes.of_string name ; proto = MBytes.of_string name ;
} }

View File

@ -83,12 +83,12 @@ let lolblock ?(operations = []) header =
level = 0l ; (* dummy *) level = 0l ; (* dummy *)
proto_level = 0 ; (* dummy *) proto_level = 0 ; (* dummy *)
net_id ; net_id ;
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] } ;
proto = MBytes.of_string header ; proto = MBytes.of_string header ;
} ; } ;
operation_list_count = Random.int 32 ;
max_operations_ttl = 0 ; max_operations_ttl = 0 ;
message = "" ; message = "" ;
context = Context.dummy_commit ; context = Context.dummy_commit ;
@ -108,8 +108,7 @@ let bh3' =
let equal (b1: Store.Block.contents) (b2: Store.Block.contents) = let equal (b1: Store.Block.contents) (b2: Store.Block.contents) =
Block_header.equal b1.header b2.header && Block_header.equal b1.header b2.header &&
b1.message = b2.message && b1.message = b2.message
b1.operation_list_count = b2.operation_list_count
let check_block s h b = let check_block s h b =
Store.Block.Contents.read (s, h) >>= function Store.Block.Contents.read (s, h) >>= function