Shell: remove the on-disk index of operations
Let's get serious. The full index of operations is not sustainable in the production code. We now only keep the index of operations not yet in the chain (i.e. the mempool/prevalidation). Operations from the chain are now only accesible through a block. For instance, see the RPC: /blocks/<hash>/proto/operations
This commit is contained in:
parent
4995864316
commit
f39eca214a
@ -1 +1 @@
|
|||||||
2017-04-17
|
2017-04-19
|
||||||
|
@ -224,6 +224,8 @@ NODE_LIB_INTFS := \
|
|||||||
node/shell/distributed_db_message.mli \
|
node/shell/distributed_db_message.mli \
|
||||||
node/shell/distributed_db_metadata.mli \
|
node/shell/distributed_db_metadata.mli \
|
||||||
node/shell/distributed_db.mli \
|
node/shell/distributed_db.mli \
|
||||||
|
node/shell/chain_traversal.mli \
|
||||||
|
node/shell/chain.mli \
|
||||||
node/shell/prevalidation.mli \
|
node/shell/prevalidation.mli \
|
||||||
node/shell/prevalidator.mli \
|
node/shell/prevalidator.mli \
|
||||||
node/shell/validator.mli \
|
node/shell/validator.mli \
|
||||||
@ -269,6 +271,8 @@ FULL_NODE_LIB_IMPLS := \
|
|||||||
node/shell/distributed_db_message.ml \
|
node/shell/distributed_db_message.ml \
|
||||||
node/shell/distributed_db_metadata.ml \
|
node/shell/distributed_db_metadata.ml \
|
||||||
node/shell/distributed_db.ml \
|
node/shell/distributed_db.ml \
|
||||||
|
node/shell/chain_traversal.ml \
|
||||||
|
node/shell/chain.ml \
|
||||||
node/shell/prevalidation.ml \
|
node/shell/prevalidation.ml \
|
||||||
node/shell/prevalidator.ml \
|
node/shell/prevalidator.ml \
|
||||||
node/shell/validator.ml \
|
node/shell/validator.ml \
|
||||||
|
@ -22,6 +22,12 @@ let forge_block cctxt ?net_id ?level ?proto_level ?predecessor ?timestamp fitnes
|
|||||||
let validate_block cctxt net block =
|
let validate_block cctxt net block =
|
||||||
call_err_service0 cctxt Services.validate_block (net, block)
|
call_err_service0 cctxt Services.validate_block (net, block)
|
||||||
|
|
||||||
|
type operation = Node_rpc_services.operation =
|
||||||
|
| Blob of Operation.t
|
||||||
|
| Hash of Operation_hash.t
|
||||||
|
|
||||||
|
let operation_encoding = Node_rpc_services.operation_encoding
|
||||||
|
|
||||||
let inject_block cctxt ?(async = false) ?(force = false) raw operations =
|
let inject_block cctxt ?(async = false) ?(force = false) raw operations =
|
||||||
call_err_service0 cctxt Services.inject_block
|
call_err_service0 cctxt Services.inject_block
|
||||||
{ raw ; blocking = not async ; force ; operations }
|
{ raw ; blocking = not async ; force ; operations }
|
||||||
@ -66,7 +72,7 @@ module Blocks = struct
|
|||||||
test_network: Context.test_network;
|
test_network: Context.test_network;
|
||||||
}
|
}
|
||||||
type preapply_param = Services.Blocks.preapply_param = {
|
type preapply_param = Services.Blocks.preapply_param = {
|
||||||
operations: Operation_hash.t list ;
|
operations: operation list ;
|
||||||
sort: bool ;
|
sort: bool ;
|
||||||
timestamp: Time.t option ;
|
timestamp: Time.t option ;
|
||||||
}
|
}
|
||||||
@ -89,8 +95,9 @@ module Blocks = struct
|
|||||||
call_service1 cctxt Services.Blocks.timestamp h ()
|
call_service1 cctxt Services.Blocks.timestamp h ()
|
||||||
let fitness cctxt h =
|
let fitness cctxt h =
|
||||||
call_service1 cctxt Services.Blocks.fitness h ()
|
call_service1 cctxt Services.Blocks.fitness h ()
|
||||||
let operations cctxt h =
|
let operations cctxt ?(contents = false) h =
|
||||||
call_service1 cctxt Services.Blocks.operations h ()
|
call_service1 cctxt Services.Blocks.operations h
|
||||||
|
{ contents ; monitor = false }
|
||||||
let protocol cctxt h =
|
let protocol cctxt h =
|
||||||
call_service1 cctxt Services.Blocks.protocol h ()
|
call_service1 cctxt Services.Blocks.protocol h ()
|
||||||
let test_network cctxt h =
|
let test_network cctxt h =
|
||||||
@ -121,12 +128,10 @@ end
|
|||||||
|
|
||||||
module Operations = struct
|
module Operations = struct
|
||||||
|
|
||||||
let contents cctxt hashes =
|
let monitor cctxt ?(contents = false) () =
|
||||||
call_service1 cctxt Services.Operations.contents hashes ()
|
call_streamed_service1 cctxt Services.Blocks.operations
|
||||||
|
`Prevalidation
|
||||||
let monitor cctxt ?contents () =
|
{ contents ; monitor = true }
|
||||||
call_streamed_service0 cctxt Services.Operations.list
|
|
||||||
{ monitor = Some true ; contents }
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -34,10 +34,16 @@ val validate_block:
|
|||||||
Net_id.t -> Block_hash.t ->
|
Net_id.t -> Block_hash.t ->
|
||||||
unit tzresult Lwt.t
|
unit tzresult Lwt.t
|
||||||
|
|
||||||
|
type operation =
|
||||||
|
| Blob of Operation.t
|
||||||
|
| Hash of Operation_hash.t
|
||||||
|
|
||||||
|
val operation_encoding: operation Data_encoding.t
|
||||||
|
|
||||||
val inject_block:
|
val inject_block:
|
||||||
config ->
|
config ->
|
||||||
?async:bool -> ?force:bool ->
|
?async:bool -> ?force:bool ->
|
||||||
MBytes.t -> Operation_hash.t list list ->
|
MBytes.t -> operation list list ->
|
||||||
Block_hash.t tzresult Lwt.t
|
Block_hash.t tzresult Lwt.t
|
||||||
(** [inject_block cctxt ?async ?force raw_block] tries to inject
|
(** [inject_block cctxt ?async ?force raw_block] tries to inject
|
||||||
[raw_block] inside the node. If [?async] is [true], [raw_block]
|
[raw_block] inside the node. If [?async] is [true], [raw_block]
|
||||||
@ -89,7 +95,8 @@ module Blocks : sig
|
|||||||
block -> MBytes.t list tzresult Lwt.t
|
block -> MBytes.t list tzresult Lwt.t
|
||||||
val operations:
|
val operations:
|
||||||
config ->
|
config ->
|
||||||
block -> Operation_hash.t list list tzresult Lwt.t
|
?contents:bool ->
|
||||||
|
block -> (Operation_hash.t * Operation.t option) list list tzresult Lwt.t
|
||||||
val protocol:
|
val protocol:
|
||||||
config ->
|
config ->
|
||||||
block -> Protocol_hash.t tzresult Lwt.t
|
block -> Protocol_hash.t tzresult Lwt.t
|
||||||
@ -144,21 +151,17 @@ module Blocks : sig
|
|||||||
block ->
|
block ->
|
||||||
?timestamp:Time.t ->
|
?timestamp:Time.t ->
|
||||||
?sort:bool ->
|
?sort:bool ->
|
||||||
Hash.Operation_hash.t list -> preapply_result tzresult Lwt.t
|
operation list -> preapply_result tzresult Lwt.t
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module Operations : sig
|
module Operations : sig
|
||||||
|
|
||||||
val contents:
|
|
||||||
config ->
|
|
||||||
Operation_hash.t list -> Operation.t list tzresult Lwt.t
|
|
||||||
|
|
||||||
val monitor:
|
val monitor:
|
||||||
config ->
|
config ->
|
||||||
?contents:bool -> unit ->
|
?contents:bool ->
|
||||||
(Operation_hash.t * Operation.t option) list list tzresult
|
unit ->
|
||||||
Lwt_stream.t tzresult Lwt.t
|
(Operation_hash.t * Operation.t option) list list tzresult Lwt_stream.t tzresult Lwt.t
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -277,8 +277,7 @@ let call_service2 cctxt service a1 a2 arg =
|
|||||||
get_json cctxt meth path arg >>=? fun json ->
|
get_json cctxt meth path arg >>=? fun json ->
|
||||||
parse_answer cctxt service path json
|
parse_answer cctxt service path json
|
||||||
|
|
||||||
let call_streamed_service0 cctxt service arg =
|
let call_streamed cctxt service (meth, path, arg) =
|
||||||
let meth, path, arg = RPC.forge_request service () arg in
|
|
||||||
get_streamed_json cctxt meth path arg >>=? fun json_st ->
|
get_streamed_json cctxt meth path arg >>=? fun json_st ->
|
||||||
let parsed_st, push = Lwt_stream.create () in
|
let parsed_st, push = Lwt_stream.create () in
|
||||||
let rec loop () =
|
let rec loop () =
|
||||||
@ -296,6 +295,12 @@ let call_streamed_service0 cctxt service arg =
|
|||||||
Lwt.async loop ;
|
Lwt.async loop ;
|
||||||
return parsed_st
|
return parsed_st
|
||||||
|
|
||||||
|
let call_streamed_service0 cctxt service arg =
|
||||||
|
call_streamed cctxt service (RPC.forge_request service () arg)
|
||||||
|
|
||||||
|
let call_streamed_service1 cctxt service arg1 arg2 =
|
||||||
|
call_streamed cctxt service (RPC.forge_request service ((), arg1) arg2)
|
||||||
|
|
||||||
let parse_err_answer config service path json =
|
let parse_err_answer config service path json =
|
||||||
match RPC.read_answer service json with
|
match RPC.read_answer service json with
|
||||||
| Error msg -> (* TODO print_error *)
|
| Error msg -> (* TODO print_error *)
|
||||||
|
@ -53,6 +53,11 @@ val call_streamed_service0:
|
|||||||
(unit, unit, 'a, 'b) RPC.service ->
|
(unit, unit, 'a, 'b) RPC.service ->
|
||||||
'a -> ('b, error list) result Lwt_stream.t tzresult Lwt.t
|
'a -> ('b, error list) result Lwt_stream.t tzresult Lwt.t
|
||||||
|
|
||||||
|
val call_streamed_service1:
|
||||||
|
config ->
|
||||||
|
(unit, unit * 'a, 'b, 'c) RPC.service ->
|
||||||
|
'a -> 'b -> ('c, error list) result Lwt_stream.t tzresult Lwt.t
|
||||||
|
|
||||||
val call_err_service0:
|
val call_err_service0:
|
||||||
config ->
|
config ->
|
||||||
(unit, unit, 'i, 'o tzresult) RPC.service ->
|
(unit, unit, 'i, 'o tzresult) RPC.service ->
|
||||||
|
@ -49,7 +49,7 @@ let inject_block cctxt block
|
|||||||
Client_proto_rpcs.Context.next_level cctxt block >>=? fun level ->
|
Client_proto_rpcs.Context.next_level cctxt block >>=? fun level ->
|
||||||
let operations_hash =
|
let operations_hash =
|
||||||
Operation_list_list_hash.compute
|
Operation_list_list_hash.compute
|
||||||
(List.map Operation_list_hash.compute operations) in
|
(List.map Operation_list_hash.compute (List.map (List.map (function Client_node_rpcs.Blob op -> Tezos_data.Operation.hash op | Hash oph -> oph)) operations)) in
|
||||||
let shell =
|
let shell =
|
||||||
{ Block_header.net_id = bi.net_id ; level = bi.level ;
|
{ Block_header.net_id = bi.net_id ; level = bi.level ;
|
||||||
proto_level = bi.proto_level ;
|
proto_level = bi.proto_level ;
|
||||||
@ -92,10 +92,12 @@ let forge_block cctxt block
|
|||||||
| None ->
|
| None ->
|
||||||
Client_node_rpcs.Blocks.pending_operations
|
Client_node_rpcs.Blocks.pending_operations
|
||||||
cctxt block >>=? fun (ops, pendings) ->
|
cctxt block >>=? fun (ops, pendings) ->
|
||||||
return (Operation_hash.Set.elements @@
|
let ops =
|
||||||
Operation_hash.Set.union
|
Operation_hash.Set.elements @@
|
||||||
(Prevalidation.preapply_result_operations ops)
|
Operation_hash.Set.union
|
||||||
pendings)
|
(Prevalidation.preapply_result_operations ops)
|
||||||
|
pendings in
|
||||||
|
return (List.map (fun x -> Client_node_rpcs.Hash x) ops)
|
||||||
| Some operations -> return operations
|
| Some operations -> return operations
|
||||||
end >>=? fun operations ->
|
end >>=? fun operations ->
|
||||||
begin
|
begin
|
||||||
@ -153,7 +155,7 @@ let forge_block cctxt block
|
|||||||
&& Operation_hash.Map.is_empty operations.branch_delayed ) then
|
&& Operation_hash.Map.is_empty operations.branch_delayed ) then
|
||||||
inject_block cctxt ?force ~src_sk
|
inject_block cctxt ?force ~src_sk
|
||||||
~priority ~timestamp ~fitness ~seed_nonce block
|
~priority ~timestamp ~fitness ~seed_nonce block
|
||||||
[operations.applied]
|
[List.map (fun h -> Client_node_rpcs.Hash h) operations.applied]
|
||||||
else
|
else
|
||||||
failwith "Cannot (fully) validate the given operations."
|
failwith "Cannot (fully) validate the given operations."
|
||||||
|
|
||||||
@ -425,6 +427,7 @@ let mine cctxt state =
|
|||||||
block >>=? fun (res, ops) ->
|
block >>=? fun (res, ops) ->
|
||||||
let operations =
|
let operations =
|
||||||
let open Operation_hash.Set in
|
let open Operation_hash.Set in
|
||||||
|
List.map (fun x -> Client_node_rpcs.Hash x) @@
|
||||||
elements (union ops (Prevalidation.preapply_result_operations res)) in
|
elements (union ops (Prevalidation.preapply_result_operations res)) in
|
||||||
let request = List.length operations in
|
let request = List.length operations in
|
||||||
Client_node_rpcs.Blocks.preapply cctxt.rpc_config block
|
Client_node_rpcs.Blocks.preapply cctxt.rpc_config block
|
||||||
@ -460,7 +463,7 @@ let mine cctxt state =
|
|||||||
Client_keys.get_key cctxt delegate >>=? fun (_,_,src_sk) ->
|
Client_keys.get_key cctxt delegate >>=? fun (_,_,src_sk) ->
|
||||||
inject_block cctxt.rpc_config
|
inject_block cctxt.rpc_config
|
||||||
~force:true ~src_sk ~priority ~timestamp ~fitness ~seed_nonce
|
~force:true ~src_sk ~priority ~timestamp ~fitness ~seed_nonce
|
||||||
(`Hash bi.hash) [operations.applied]
|
(`Hash bi.hash) [List.map (fun h -> Client_node_rpcs.Hash h) operations.applied]
|
||||||
|> trace_exn (Failure "Error while injecting block") >>=? fun block_hash ->
|
|> trace_exn (Failure "Error while injecting block") >>=? fun block_hash ->
|
||||||
State.record_block cctxt level block_hash seed_nonce
|
State.record_block cctxt level block_hash seed_nonce
|
||||||
|> trace_exn (Failure "Error while recording block") >>=? fun () ->
|
|> trace_exn (Failure "Error while recording block") >>=? fun () ->
|
||||||
|
@ -22,7 +22,7 @@ val inject_block:
|
|||||||
fitness:Fitness.t ->
|
fitness:Fitness.t ->
|
||||||
seed_nonce:Nonce.t ->
|
seed_nonce:Nonce.t ->
|
||||||
src_sk:secret_key ->
|
src_sk:secret_key ->
|
||||||
Operation_hash.t list list ->
|
Client_node_rpcs.operation list list ->
|
||||||
Block_hash.t tzresult Lwt.t
|
Block_hash.t tzresult Lwt.t
|
||||||
(** [inject_block cctxt blk ?force ~priority ~timestamp ~fitness
|
(** [inject_block cctxt blk ?force ~priority ~timestamp ~fitness
|
||||||
~seed_nonce ~src_sk ops] tries to inject a block in the node. If
|
~seed_nonce ~src_sk ops] tries to inject a block in the node. If
|
||||||
@ -34,7 +34,7 @@ val forge_block:
|
|||||||
Client_rpcs.config ->
|
Client_rpcs.config ->
|
||||||
Client_proto_rpcs.block ->
|
Client_proto_rpcs.block ->
|
||||||
?force:bool ->
|
?force:bool ->
|
||||||
?operations:Operation_hash.t list ->
|
?operations:Client_node_rpcs.operation list ->
|
||||||
?best_effort:bool ->
|
?best_effort:bool ->
|
||||||
?sort:bool ->
|
?sort:bool ->
|
||||||
?timestamp:Time.t ->
|
?timestamp:Time.t ->
|
||||||
|
@ -15,7 +15,7 @@ open Operation
|
|||||||
|
|
||||||
type operation = {
|
type operation = {
|
||||||
hash: Operation_hash.t ;
|
hash: Operation_hash.t ;
|
||||||
content: Tezos_context.Operation.t option
|
content: Operation.t option
|
||||||
}
|
}
|
||||||
|
|
||||||
let monitor cctxt ?contents ?check () =
|
let monitor cctxt ?contents ?check () =
|
||||||
@ -81,7 +81,8 @@ let filter_valid_endorsement cctxt ({ hash ; content } : operation) =
|
|||||||
pp_print_error error >>= fun () ->
|
pp_print_error error >>= fun () ->
|
||||||
Lwt.return_none
|
Lwt.return_none
|
||||||
| Ok () ->
|
| Ok () ->
|
||||||
Client_node_rpcs.Blocks.preapply cctxt (`Hash block) [hash] >>= function
|
Client_node_rpcs.Blocks.preapply
|
||||||
|
cctxt (`Hash block) [Client_node_rpcs.Hash hash] >>= function
|
||||||
| Ok _ ->
|
| Ok _ ->
|
||||||
Lwt.return (Some { hash ; source ; block ; slots })
|
Lwt.return (Some { hash ; source ; block ; slots })
|
||||||
| Error error ->
|
| Error error ->
|
||||||
|
@ -16,7 +16,7 @@ let demo cctxt =
|
|||||||
cctxt.Client_commands.message "Calling the 'echo' RPC." >>= fun () ->
|
cctxt.Client_commands.message "Calling the 'echo' RPC." >>= fun () ->
|
||||||
let msg = "test" in
|
let msg = "test" in
|
||||||
Client_proto_rpcs.echo cctxt.rpc_config block msg >>=? fun reply ->
|
Client_proto_rpcs.echo cctxt.rpc_config block msg >>=? fun reply ->
|
||||||
fail_unless (reply = msg) (Unclassified "...") >>=? fun () ->
|
fail_unless (reply = msg) (failure "...") >>=? fun () ->
|
||||||
begin
|
begin
|
||||||
cctxt.message "Calling the 'failing' RPC." >>= fun () ->
|
cctxt.message "Calling the 'failing' RPC." >>= fun () ->
|
||||||
Client_proto_rpcs.failing cctxt.rpc_config block 3 >>= function
|
Client_proto_rpcs.failing cctxt.rpc_config block 3 >>= function
|
||||||
|
@ -78,8 +78,15 @@ module Kind = struct
|
|||||||
| `Fixed n1, `Fixed n2 -> `Fixed (n1 + n2)
|
| `Fixed n1, `Fixed n2 -> `Fixed (n1 + n2)
|
||||||
| `Dynamic, `Dynamic | `Fixed _, `Dynamic
|
| `Dynamic, `Dynamic | `Fixed _, `Dynamic
|
||||||
| `Dynamic, `Fixed _ -> `Dynamic
|
| `Dynamic, `Fixed _ -> `Dynamic
|
||||||
| `Variable, (`Dynamic | `Fixed _)
|
| `Variable, `Fixed _
|
||||||
| (`Dynamic | `Fixed _), `Variable -> `Variable
|
| (`Dynamic | `Fixed _), `Variable -> `Variable
|
||||||
|
| `Variable, `Dynamic ->
|
||||||
|
Printf.ksprintf invalid_arg
|
||||||
|
"Cannot merge two %s when the left element is of variable length \
|
||||||
|
and the right one of dynamic length. \
|
||||||
|
You should use the reverse order, or wrap the second one \
|
||||||
|
with Data_encoding.dynamic_size."
|
||||||
|
name
|
||||||
| `Variable, `Variable ->
|
| `Variable, `Variable ->
|
||||||
Printf.ksprintf invalid_arg
|
Printf.ksprintf invalid_arg
|
||||||
"Cannot merge two %s with variable length. \
|
"Cannot merge two %s with variable length. \
|
||||||
|
@ -66,196 +66,45 @@ module Net = struct
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
(**************************************************************************
|
|
||||||
* Generic store for "tracked" data: discovery_time, invalidity,
|
|
||||||
* incoming peers,... (for operations, block_headers, and protocols).
|
|
||||||
**************************************************************************)
|
|
||||||
|
|
||||||
module type DATA_STORE = sig
|
|
||||||
|
|
||||||
type store
|
|
||||||
type key
|
|
||||||
type key_set
|
|
||||||
type value
|
|
||||||
|
|
||||||
module Discovery_time : MAP_STORE
|
|
||||||
with type t := store
|
|
||||||
and type key := key
|
|
||||||
and type value := Time.t
|
|
||||||
|
|
||||||
module Contents : SINGLE_STORE
|
|
||||||
with type t = store * key
|
|
||||||
and type value := value
|
|
||||||
|
|
||||||
module RawContents : SINGLE_STORE
|
|
||||||
with type t = store * key
|
|
||||||
and type value := MBytes.t
|
|
||||||
|
|
||||||
module Validation_time : SINGLE_STORE
|
|
||||||
with type t = store * key
|
|
||||||
and type value := Time.t
|
|
||||||
|
|
||||||
module Errors : MAP_STORE
|
|
||||||
with type t := store
|
|
||||||
and type key := key
|
|
||||||
and type value = error list
|
|
||||||
|
|
||||||
module Pending : BUFFERED_SET_STORE
|
|
||||||
with type t = store
|
|
||||||
and type elt := key
|
|
||||||
and type Set.t = key_set
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
module Errors_value =
|
|
||||||
Store_helpers.Make_value(struct
|
|
||||||
type t = error list
|
|
||||||
let encoding = (Data_encoding.list (Error_monad.error_encoding ()))
|
|
||||||
end)
|
|
||||||
|
|
||||||
module Raw_value = struct
|
|
||||||
type t = MBytes.t
|
|
||||||
let of_bytes b = ok b
|
|
||||||
let to_bytes b = b
|
|
||||||
end
|
|
||||||
|
|
||||||
module Make_data_store
|
|
||||||
(S : STORE) (I : INDEX) (V : VALUE)
|
|
||||||
(Set : Set.S with type elt = I.t) = struct
|
|
||||||
|
|
||||||
type key = I.t
|
|
||||||
type value = V.t
|
|
||||||
type key_set = Set.t
|
|
||||||
|
|
||||||
let of_bytes = V.of_bytes
|
|
||||||
let to_bytes = V.to_bytes
|
|
||||||
|
|
||||||
module Indexed_store =
|
|
||||||
Store_helpers.Make_indexed_substore
|
|
||||||
(Store_helpers.Make_substore (S) (struct let name = ["data"] end))
|
|
||||||
(I)
|
|
||||||
|
|
||||||
module Discovery_time =
|
|
||||||
Indexed_store.Make_map
|
|
||||||
(struct let name = ["discovery_time"] end)
|
|
||||||
(Store_helpers.Make_value(Time))
|
|
||||||
module Contents =
|
|
||||||
Store_helpers.Make_single_store
|
|
||||||
(Indexed_store.Store)
|
|
||||||
(struct let name = ["contents"] end)
|
|
||||||
(V)
|
|
||||||
module RawContents =
|
|
||||||
Store_helpers.Make_single_store
|
|
||||||
(Indexed_store.Store)
|
|
||||||
(struct let name = ["contents"] end)
|
|
||||||
(Raw_value)
|
|
||||||
module Errors =
|
|
||||||
Store_helpers.Make_map
|
|
||||||
(Store_helpers.Make_substore (S) (struct let name = ["invalids"] end))
|
|
||||||
(I)
|
|
||||||
(Errors_value)
|
|
||||||
module Pending =
|
|
||||||
Store_helpers.Make_buffered_set
|
|
||||||
(Store_helpers.Make_substore (S) (struct let name = ["pending"] end))
|
|
||||||
(I)
|
|
||||||
(Set)
|
|
||||||
module Validation_time =
|
|
||||||
Store_helpers.Make_single_store
|
|
||||||
(Indexed_store.Store)
|
|
||||||
(struct let name = ["validation_time"] end)
|
|
||||||
(Store_helpers.Make_value(Time))
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
(**************************************************************************
|
|
||||||
* Operation store under "net/<id>/operations/"
|
|
||||||
**************************************************************************)
|
|
||||||
|
|
||||||
module Operation = struct
|
|
||||||
|
|
||||||
module Value = Store_helpers.Make_value(Operation)
|
|
||||||
|
|
||||||
let compare o1 o2 =
|
|
||||||
let (>>) x y = if x = 0 then y () else x in
|
|
||||||
Net_id.compare o1.Operation.shell.net_id o2.Operation.shell.net_id >> fun () ->
|
|
||||||
MBytes.compare o1.proto o2.proto
|
|
||||||
let equal b1 b2 = compare b1 b2 = 0
|
|
||||||
let hash op = Operation_hash.hash_bytes [Value.to_bytes op]
|
|
||||||
let hash_raw bytes = Operation_hash.hash_bytes [bytes]
|
|
||||||
|
|
||||||
type store = Net.store
|
|
||||||
let get x = x
|
|
||||||
|
|
||||||
include
|
|
||||||
Make_data_store
|
|
||||||
(Store_helpers.Make_substore
|
|
||||||
(Net.Indexed_store.Store)
|
|
||||||
(struct let name = ["operations"] end))
|
|
||||||
(Operation_hash)
|
|
||||||
(Value)
|
|
||||||
(Operation_hash.Set)
|
|
||||||
|
|
||||||
let register s =
|
|
||||||
Base58.register_resolver Operation_hash.b58check_encoding begin fun str ->
|
|
||||||
let pstr = Operation_hash.prefix_path str in
|
|
||||||
Net.Indexed_store.fold_indexes s ~init:[]
|
|
||||||
~f:begin fun net acc ->
|
|
||||||
Indexed_store.resolve_index (s, net) pstr >>= fun l ->
|
|
||||||
Lwt.return (List.rev_append l acc)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
(**************************************************************************
|
(**************************************************************************
|
||||||
* Block_header store under "net/<id>/blocks/"
|
* Block_header store under "net/<id>/blocks/"
|
||||||
**************************************************************************)
|
**************************************************************************)
|
||||||
|
|
||||||
module Block_header = struct
|
module Block = struct
|
||||||
|
|
||||||
module Value = Store_helpers.Make_value(Block_header)
|
|
||||||
|
|
||||||
let compare b1 b2 =
|
|
||||||
let (>>) x y = if x = 0 then y () else x in
|
|
||||||
let rec list compare xs ys =
|
|
||||||
match xs, ys with
|
|
||||||
| [], [] -> 0
|
|
||||||
| _ :: _, [] -> -1
|
|
||||||
| [], _ :: _ -> 1
|
|
||||||
| x :: xs, y :: ys ->
|
|
||||||
compare x y >> fun () -> list compare xs ys in
|
|
||||||
Block_hash.compare b1.Block_header.shell.predecessor b2.Block_header.shell.predecessor >> fun () ->
|
|
||||||
compare b1.proto b2.proto >> fun () ->
|
|
||||||
Operation_list_list_hash.compare
|
|
||||||
b1.shell.operations_hash b2.shell.operations_hash >> fun () ->
|
|
||||||
Time.compare b1.shell.timestamp b2.shell.timestamp >> fun () ->
|
|
||||||
list compare b1.shell.fitness b2.shell.fitness
|
|
||||||
|
|
||||||
let equal b1 b2 = compare b1 b2 = 0
|
|
||||||
let hash block = Block_hash.hash_bytes [Value.to_bytes block]
|
|
||||||
let hash_raw bytes = Block_hash.hash_bytes [bytes]
|
|
||||||
|
|
||||||
type store = Net.store
|
type store = Net.store
|
||||||
let get x = x
|
let get x = x
|
||||||
|
|
||||||
include Make_data_store
|
module Indexed_store =
|
||||||
|
Store_helpers.Make_indexed_substore
|
||||||
(Store_helpers.Make_substore
|
(Store_helpers.Make_substore
|
||||||
(Net.Indexed_store.Store)
|
(Net.Indexed_store.Store)
|
||||||
(struct let name = ["blocks"] end))
|
(struct let name = ["blocks"] end))
|
||||||
(Block_hash)
|
(Block_hash)
|
||||||
(Value)
|
|
||||||
(Block_hash.Set)
|
|
||||||
|
|
||||||
module Operation_list_count =
|
type contents = {
|
||||||
|
header: Block_header.t ;
|
||||||
|
message: string ;
|
||||||
|
operation_list_count: int ;
|
||||||
|
}
|
||||||
|
|
||||||
|
module Contents =
|
||||||
Store_helpers.Make_single_store
|
Store_helpers.Make_single_store
|
||||||
(Indexed_store.Store)
|
(Indexed_store.Store)
|
||||||
(struct let name = ["operation_list_count"] end)
|
(struct let name = ["contents"] end)
|
||||||
(Store_helpers.Make_value(struct
|
(Store_helpers.Make_value(struct
|
||||||
type t = int
|
type t = contents
|
||||||
let encoding = Data_encoding.int8
|
let encoding =
|
||||||
|
let open Data_encoding in
|
||||||
|
conv
|
||||||
|
(fun { header ; message ; operation_list_count } ->
|
||||||
|
(message, operation_list_count, header))
|
||||||
|
(fun (message, operation_list_count, header) ->
|
||||||
|
{ header ; message ; operation_list_count })
|
||||||
|
(obj3
|
||||||
|
(req "message" string)
|
||||||
|
(req "operation_list_count" uint8)
|
||||||
|
(req "header" Block_header.encoding))
|
||||||
end))
|
end))
|
||||||
|
|
||||||
module Operations_index =
|
module Operations_index =
|
||||||
@ -265,15 +114,15 @@ module Block_header = struct
|
|||||||
(struct let name = ["operations"] end))
|
(struct let name = ["operations"] end))
|
||||||
(Store_helpers.Integer_index)
|
(Store_helpers.Integer_index)
|
||||||
|
|
||||||
module Operation_list =
|
module Operation_hashes =
|
||||||
Operations_index.Make_map
|
Operations_index.Make_map
|
||||||
(struct let name = ["list"] end)
|
(struct let name = ["hashes"] end)
|
||||||
(Store_helpers.Make_value(struct
|
(Store_helpers.Make_value(struct
|
||||||
type t = Operation_hash.t list
|
type t = Operation_hash.t list
|
||||||
let encoding = Data_encoding.list Operation_hash.encoding
|
let encoding = Data_encoding.list Operation_hash.encoding
|
||||||
end))
|
end))
|
||||||
|
|
||||||
module Operation_list_path =
|
module Operation_path =
|
||||||
Operations_index.Make_map
|
Operations_index.Make_map
|
||||||
(struct let name = ["path"] end)
|
(struct let name = ["path"] end)
|
||||||
(Store_helpers.Make_value(struct
|
(Store_helpers.Make_value(struct
|
||||||
@ -281,6 +130,35 @@ module Block_header = struct
|
|||||||
let encoding = Operation_list_list_hash.path_encoding
|
let encoding = Operation_list_list_hash.path_encoding
|
||||||
end))
|
end))
|
||||||
|
|
||||||
|
module Operations =
|
||||||
|
Operations_index.Make_map
|
||||||
|
(struct let name = ["contents"] end)
|
||||||
|
(Store_helpers.Make_value(struct
|
||||||
|
type t = Operation.t list
|
||||||
|
let encoding = Data_encoding.(list (dynamic_size Operation.encoding))
|
||||||
|
end))
|
||||||
|
|
||||||
|
type invalid_block = {
|
||||||
|
level: int32 ;
|
||||||
|
(* errors: Error_monad.error list ; *)
|
||||||
|
}
|
||||||
|
|
||||||
|
module Invalid_block =
|
||||||
|
Store_helpers.Make_map
|
||||||
|
(Store_helpers.Make_substore
|
||||||
|
(Net.Indexed_store.Store)
|
||||||
|
(struct let name = ["invalid_blocks"] end))
|
||||||
|
(Block_hash)
|
||||||
|
(Store_helpers.Make_value(struct
|
||||||
|
type t = invalid_block
|
||||||
|
let encoding =
|
||||||
|
let open Data_encoding in
|
||||||
|
conv
|
||||||
|
(fun { level } -> (level))
|
||||||
|
(fun (level) -> { level })
|
||||||
|
int32
|
||||||
|
end))
|
||||||
|
|
||||||
let register s =
|
let register s =
|
||||||
Base58.register_resolver Block_hash.b58check_encoding begin fun str ->
|
Base58.register_resolver Block_hash.b58check_encoding begin fun str ->
|
||||||
let pstr = Block_hash.prefix_path str in
|
let pstr = Block_hash.prefix_path str in
|
||||||
@ -317,17 +195,11 @@ module Chain = struct
|
|||||||
(struct let name = ["current_head"] end)
|
(struct let name = ["current_head"] end)
|
||||||
(Store_helpers.Make_value(Block_hash))
|
(Store_helpers.Make_value(Block_hash))
|
||||||
|
|
||||||
module Successor_in_chain =
|
module In_chain =
|
||||||
Store_helpers.Make_single_store
|
Store_helpers.Make_single_store
|
||||||
(Block_header.Indexed_store.Store)
|
(Block.Indexed_store.Store)
|
||||||
(struct let name = ["successor_in_chain"] end)
|
(struct let name = ["in_chain"] end)
|
||||||
(Store_helpers.Make_value(Block_hash))
|
(Store_helpers.Make_value(Block_hash)) (* successor *)
|
||||||
|
|
||||||
module In_chain_insertion_time =
|
|
||||||
Store_helpers.Make_single_store
|
|
||||||
(Block_header.Indexed_store.Store)
|
|
||||||
(struct let name = ["in_chain_insertion_time"] end)
|
|
||||||
(Store_helpers.Make_value(Time))
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -338,19 +210,26 @@ end
|
|||||||
|
|
||||||
module Protocol = struct
|
module Protocol = struct
|
||||||
|
|
||||||
include Protocol
|
|
||||||
let hash_raw bytes = Protocol_hash.hash_bytes [bytes]
|
|
||||||
|
|
||||||
type store = global_store
|
type store = global_store
|
||||||
let get x = x
|
let get x = x
|
||||||
|
|
||||||
include Make_data_store
|
module Indexed_store =
|
||||||
|
Store_helpers.Make_indexed_substore
|
||||||
(Store_helpers.Make_substore
|
(Store_helpers.Make_substore
|
||||||
(Raw_store)
|
(Raw_store)
|
||||||
(struct let name = ["protocols"] end))
|
(struct let name = ["protocols"] end))
|
||||||
(Protocol_hash)
|
(Protocol_hash)
|
||||||
|
|
||||||
|
module Contents =
|
||||||
|
Indexed_store.Make_map
|
||||||
|
(struct let name = ["contents"] end)
|
||||||
(Store_helpers.Make_value(Protocol))
|
(Store_helpers.Make_value(Protocol))
|
||||||
(Protocol_hash.Set)
|
|
||||||
|
module RawContents =
|
||||||
|
Store_helpers.Make_single_store
|
||||||
|
(Indexed_store.Store)
|
||||||
|
(struct let name = ["contents"] end)
|
||||||
|
(Store_helpers.Raw_value)
|
||||||
|
|
||||||
let register s =
|
let register s =
|
||||||
Base58.register_resolver Protocol_hash.b58check_encoding begin fun str ->
|
Base58.register_resolver Protocol_hash.b58check_encoding begin fun str ->
|
||||||
@ -358,13 +237,11 @@ module Protocol = struct
|
|||||||
Indexed_store.resolve_index s pstr
|
Indexed_store.resolve_index s pstr
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
let init dir =
|
let init dir =
|
||||||
Raw_store.init dir >>=? fun s ->
|
Raw_store.init dir >>=? fun s ->
|
||||||
Block_header.register s ;
|
Block.register s ;
|
||||||
Operation.register s ;
|
|
||||||
Protocol.register s ;
|
Protocol.register s ;
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
(**************************************************************************)
|
(**************************************************************************)
|
||||||
|
|
||||||
open Store_sigs
|
open Store_sigs
|
||||||
|
open Tezos_data
|
||||||
|
|
||||||
type t
|
type t
|
||||||
type global_store = t
|
type global_store = t
|
||||||
@ -70,101 +71,55 @@ module Chain : sig
|
|||||||
and type elt := Block_hash.t
|
and type elt := Block_hash.t
|
||||||
and module Set := Block_hash.Set
|
and module Set := Block_hash.Set
|
||||||
|
|
||||||
module Successor_in_chain : SINGLE_STORE
|
module In_chain : SINGLE_STORE
|
||||||
with type t = store * Block_hash.t
|
with type t = store * Block_hash.t
|
||||||
and type value := Block_hash.t
|
and type value := Block_hash.t (* successor *)
|
||||||
|
|
||||||
module In_chain_insertion_time : SINGLE_STORE
|
|
||||||
with type t = store * Block_hash.t
|
|
||||||
and type value := Time.t
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
(** {2 Generic signature} *****************************************************)
|
|
||||||
|
|
||||||
(** Generic signature for Operations, Block_header, and Protocol "tracked"
|
|
||||||
contents (i.e. with 'discovery_time', 'validtity', ...) *)
|
|
||||||
module type DATA_STORE = sig
|
|
||||||
|
|
||||||
type store
|
|
||||||
type key
|
|
||||||
type key_set
|
|
||||||
type value
|
|
||||||
|
|
||||||
module Discovery_time : MAP_STORE
|
|
||||||
with type t := store
|
|
||||||
and type key := key
|
|
||||||
and type value := Time.t
|
|
||||||
|
|
||||||
module Contents : SINGLE_STORE
|
|
||||||
with type t = store * key
|
|
||||||
and type value := value
|
|
||||||
|
|
||||||
module RawContents : SINGLE_STORE
|
|
||||||
with type t = store * key
|
|
||||||
and type value := MBytes.t
|
|
||||||
|
|
||||||
module Validation_time : SINGLE_STORE
|
|
||||||
with type t = store * key
|
|
||||||
and type value := Time.t
|
|
||||||
|
|
||||||
module Errors : MAP_STORE
|
|
||||||
with type t := store
|
|
||||||
and type key := key
|
|
||||||
and type value = error list
|
|
||||||
|
|
||||||
module Pending : BUFFERED_SET_STORE
|
|
||||||
with type t = store
|
|
||||||
and type elt := key
|
|
||||||
and type Set.t = key_set
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
(** {2 Operation store} *****************************************************)
|
|
||||||
|
|
||||||
module Operation : sig
|
|
||||||
|
|
||||||
type store
|
|
||||||
val get: Net.store -> store
|
|
||||||
|
|
||||||
include DATA_STORE
|
|
||||||
with type store := store
|
|
||||||
and type key = Operation_hash.t
|
|
||||||
and type value = Operation.t
|
|
||||||
and type key_set = Operation_hash.Set.t
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
(** {2 Block header store} **************************************************)
|
(** {2 Block header store} **************************************************)
|
||||||
|
|
||||||
module Block_header : sig
|
module Block : sig
|
||||||
|
|
||||||
type store
|
type store
|
||||||
val get: Net.store -> store
|
val get: Net.store -> store
|
||||||
|
|
||||||
include DATA_STORE
|
type contents = {
|
||||||
with type store := store
|
header: Block_header.t ;
|
||||||
and type key = Block_hash.t
|
message: string ;
|
||||||
and type value = Block_header.t
|
operation_list_count: int ;
|
||||||
and type key_set = Block_hash.Set.t
|
}
|
||||||
|
|
||||||
module Operation_list_count : SINGLE_STORE
|
module Contents : SINGLE_STORE
|
||||||
with type t = store * Block_hash.t
|
with type t = store * Block_hash.t
|
||||||
and type value = int
|
and type value := contents
|
||||||
|
|
||||||
module Operation_list : MAP_STORE
|
module Operation_hashes : MAP_STORE
|
||||||
with type t = store * Block_hash.t
|
with type t = store * Block_hash.t
|
||||||
and type key = int
|
and type key = int
|
||||||
and type value = Operation_hash.t list
|
and type value = Operation_hash.t list
|
||||||
|
|
||||||
module Operation_list_path : MAP_STORE
|
module Operation_path : MAP_STORE
|
||||||
with type t = store * Block_hash.t
|
with type t = store * Block_hash.t
|
||||||
and type key = int
|
and type key = int
|
||||||
and type value = Operation_list_list_hash.path
|
and type value = Operation_list_list_hash.path
|
||||||
|
|
||||||
|
module Operations : MAP_STORE
|
||||||
|
with type t = store * Block_hash.t
|
||||||
|
and type key = int
|
||||||
|
and type value = Operation.t list
|
||||||
|
|
||||||
|
type invalid_block = {
|
||||||
|
level: int32 ;
|
||||||
|
(* errors: Error_monad.error list ; *)
|
||||||
|
}
|
||||||
|
|
||||||
|
module Invalid_block : MAP_STORE
|
||||||
|
with type t = store
|
||||||
|
and type key = Block_hash.t
|
||||||
|
and type value = invalid_block
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -175,10 +130,13 @@ module Protocol : sig
|
|||||||
type store
|
type store
|
||||||
val get: global_store -> store
|
val get: global_store -> store
|
||||||
|
|
||||||
include DATA_STORE
|
module Contents : MAP_STORE
|
||||||
with type store := store
|
with type t := store
|
||||||
and type key = Protocol_hash.t
|
and type key := Protocol_hash.t
|
||||||
and type value = Protocol.t
|
and type value := Protocol.t
|
||||||
and type key_set = Protocol_hash.Set.t
|
|
||||||
|
module RawContents : SINGLE_STORE
|
||||||
|
with type t = store * Protocol_hash.t
|
||||||
|
and type value := MBytes.t
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -23,6 +23,12 @@ module Make_value (V : ENCODED_VALUE) = struct
|
|||||||
MBytes.create 0
|
MBytes.create 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module Raw_value = struct
|
||||||
|
type t = MBytes.t
|
||||||
|
let of_bytes b = ok b
|
||||||
|
let to_bytes b = b
|
||||||
|
end
|
||||||
|
|
||||||
module Make_single_store (S : STORE) (N : NAME) (V : VALUE) = struct
|
module Make_single_store (S : STORE) (N : NAME) (V : VALUE) = struct
|
||||||
type t = S.t
|
type t = S.t
|
||||||
type value = V.t
|
type value = V.t
|
||||||
|
@ -11,6 +11,8 @@ open Store_sigs
|
|||||||
|
|
||||||
module Make_value (V : ENCODED_VALUE) : VALUE with type t = V.t
|
module Make_value (V : ENCODED_VALUE) : VALUE with type t = V.t
|
||||||
|
|
||||||
|
module Raw_value : VALUE with type t = MBytes.t
|
||||||
|
|
||||||
module Make_single_store (S : STORE) (N : NAME) (V : VALUE)
|
module Make_single_store (S : STORE) (N : NAME) (V : VALUE)
|
||||||
: SINGLE_STORE with type t = S.t
|
: SINGLE_STORE with type t = S.t
|
||||||
and type value = V.t
|
and type value = V.t
|
||||||
|
@ -463,7 +463,7 @@ module RPC = struct
|
|||||||
|
|
||||||
let connect net point timeout =
|
let connect net point timeout =
|
||||||
match net.pool with
|
match net.pool with
|
||||||
| None -> fail (Unclassified "fake net")
|
| None -> failwith "fake net"
|
||||||
| Some pool ->
|
| Some pool ->
|
||||||
P2p_connection_pool.connect ~timeout pool point >>|? ignore
|
P2p_connection_pool.connect ~timeout pool point >>|? ignore
|
||||||
|
|
||||||
|
95
src/node/shell/chain.ml
Normal file
95
src/node/shell/chain.ml
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
(**************************************************************************)
|
||||||
|
(* *)
|
||||||
|
(* Copyright (c) 2014 - 2016. *)
|
||||||
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
||||||
|
(* *)
|
||||||
|
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
||||||
|
(* *)
|
||||||
|
(**************************************************************************)
|
||||||
|
|
||||||
|
|
||||||
|
open Logging.Node.State
|
||||||
|
open State
|
||||||
|
|
||||||
|
let genesis net_state =
|
||||||
|
let genesis = Net.genesis net_state in
|
||||||
|
Block.read_exn net_state genesis.block
|
||||||
|
|
||||||
|
let known_heads net_state =
|
||||||
|
read_chain_store net_state begin fun chain_store _data ->
|
||||||
|
Store.Chain.Known_heads.elements chain_store
|
||||||
|
end >>= fun hashes ->
|
||||||
|
Lwt_list.map_p (Block.read_exn net_state) hashes
|
||||||
|
|
||||||
|
let head net_state =
|
||||||
|
read_chain_store net_state begin fun _chain_store data ->
|
||||||
|
Lwt.return data.current_head
|
||||||
|
end
|
||||||
|
|
||||||
|
let mem net_state hash =
|
||||||
|
read_chain_store net_state begin fun chain_store data ->
|
||||||
|
if Block_hash.equal (Block.hash data.current_head) hash then
|
||||||
|
Lwt.return true
|
||||||
|
else
|
||||||
|
Store.Chain.In_chain.known (chain_store, hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
let find_new net_state hist sz =
|
||||||
|
let rec common_ancestor hist =
|
||||||
|
match hist with
|
||||||
|
| [] -> Lwt.return (Net.genesis net_state).block
|
||||||
|
| h :: hist ->
|
||||||
|
mem net_state h >>= function
|
||||||
|
| false -> common_ancestor hist
|
||||||
|
| true -> Lwt.return h in
|
||||||
|
let rec path sz acc h =
|
||||||
|
if sz <= 0 then Lwt.return (List.rev acc)
|
||||||
|
else
|
||||||
|
read_chain_store net_state begin fun chain_store _data ->
|
||||||
|
Store.Chain.In_chain.read_opt (chain_store, h)
|
||||||
|
end >>= function
|
||||||
|
| None -> Lwt.return (List.rev acc)
|
||||||
|
| Some s -> path (sz-1) (s :: acc) s in
|
||||||
|
common_ancestor hist >>= fun ancestor ->
|
||||||
|
path sz [] ancestor
|
||||||
|
|
||||||
|
let locked_set_head chain_store data block =
|
||||||
|
let rec pop_blocks ancestor block =
|
||||||
|
let hash = Block.hash block in
|
||||||
|
if Block_hash.equal hash ancestor then
|
||||||
|
Lwt.return_unit
|
||||||
|
else
|
||||||
|
lwt_debug "pop_block %a" Block_hash.pp_short hash >>= fun () ->
|
||||||
|
Store.Chain.In_chain.remove (chain_store, hash) >>= fun () ->
|
||||||
|
Block.predecessor block >>= function
|
||||||
|
| Some predecessor ->
|
||||||
|
pop_blocks ancestor predecessor
|
||||||
|
| None -> assert false (* Cannot pop the genesis... *)
|
||||||
|
in
|
||||||
|
let push_block pred_hash block =
|
||||||
|
let hash = Block.hash block in
|
||||||
|
lwt_debug "push_block %a" Block_hash.pp_short hash >>= fun () ->
|
||||||
|
Store.Chain.In_chain.store (chain_store, pred_hash) hash >>= fun () ->
|
||||||
|
Lwt.return hash
|
||||||
|
in
|
||||||
|
Chain_traversal.new_blocks
|
||||||
|
data.current_head block >>= fun (ancestor, path) ->
|
||||||
|
let ancestor = Block.hash ancestor in
|
||||||
|
pop_blocks ancestor data.current_head >>= fun () ->
|
||||||
|
Lwt_list.fold_left_s push_block ancestor path >>= fun _ ->
|
||||||
|
Store.Chain.Current_head.store chain_store (Block.hash block)
|
||||||
|
|
||||||
|
let set_head net_state block =
|
||||||
|
update_chain_store net_state begin fun chain_store data ->
|
||||||
|
locked_set_head chain_store data block >>= fun () ->
|
||||||
|
Lwt.return (Some { current_head = block }, ())
|
||||||
|
end
|
||||||
|
|
||||||
|
let test_and_set_head net_state ~old block =
|
||||||
|
update_chain_store net_state begin fun chain_store data ->
|
||||||
|
if not (Block.equal data.current_head old) then
|
||||||
|
Lwt.return (None, false)
|
||||||
|
else
|
||||||
|
locked_set_head chain_store data block >>= fun () ->
|
||||||
|
Lwt.return (Some { current_head = block }, true)
|
||||||
|
end
|
37
src/node/shell/chain.mli
Normal file
37
src/node/shell/chain.mli
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
(**************************************************************************)
|
||||||
|
(* *)
|
||||||
|
(* Copyright (c) 2014 - 2016. *)
|
||||||
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
||||||
|
(* *)
|
||||||
|
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
||||||
|
(* *)
|
||||||
|
(**************************************************************************)
|
||||||
|
|
||||||
|
|
||||||
|
open State
|
||||||
|
|
||||||
|
val genesis: Net.t -> Block.t Lwt.t
|
||||||
|
(** The genesis block of the network's blockchain. On a test network,
|
||||||
|
the test protocol has been promoted as "main" protocol. *)
|
||||||
|
|
||||||
|
val head: Net.t -> Block.t Lwt.t
|
||||||
|
(** The current head of the network's blockchain. *)
|
||||||
|
|
||||||
|
val known_heads: Net.t -> Block.t list Lwt.t
|
||||||
|
|
||||||
|
val set_head: Net.t -> Block.t -> unit Lwt.t
|
||||||
|
(** Record a block as the current head of the network's blockchain. *)
|
||||||
|
|
||||||
|
val mem: Net.t -> Block_hash.t -> bool Lwt.t
|
||||||
|
|
||||||
|
val test_and_set_head:
|
||||||
|
Net.t -> old:Block.t -> Block.t -> bool Lwt.t
|
||||||
|
(** Atomically change the current head of the network's blockchain.
|
||||||
|
This returns [true] whenever the change succeeded, or [false]
|
||||||
|
when the current head os not equal to the [old] argument. *)
|
||||||
|
|
||||||
|
val find_new:
|
||||||
|
Net.t -> Block_hash.t list -> int -> Block_hash.t list Lwt.t
|
||||||
|
(** [find_new net locator max_length], where [locator] is a sparse block
|
||||||
|
locator (/à la/ Bitcoin), returns the missing block when compared
|
||||||
|
with the current branch of [net]. *)
|
134
src/node/shell/chain_traversal.ml
Normal file
134
src/node/shell/chain_traversal.ml
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
(**************************************************************************)
|
||||||
|
(* *)
|
||||||
|
(* Copyright (c) 2014 - 2016. *)
|
||||||
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
||||||
|
(* *)
|
||||||
|
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
||||||
|
(* *)
|
||||||
|
(**************************************************************************)
|
||||||
|
|
||||||
|
open State
|
||||||
|
|
||||||
|
let path (b1: Block.t) (b2: Block.t) =
|
||||||
|
if not (Net_id.equal (Block.net_id b1) (Block.net_id b2)) then
|
||||||
|
invalid_arg "Chain_traversal.path" ;
|
||||||
|
let rec loop acc current =
|
||||||
|
if Block.equal b1 current then
|
||||||
|
Lwt.return (Some acc)
|
||||||
|
else
|
||||||
|
Block.predecessor current >>= function
|
||||||
|
| Some pred -> loop (current :: acc) pred
|
||||||
|
| None -> Lwt.return_none in
|
||||||
|
loop [] b2
|
||||||
|
|
||||||
|
let common_ancestor (b1: Block.t) (b2: Block.t) =
|
||||||
|
if not ( Net_id.equal (Block.net_id b1) (Block.net_id b2)) then
|
||||||
|
invalid_arg "Chain_traversal.path" ;
|
||||||
|
let rec loop (b1: Block.t) (b2: Block.t) =
|
||||||
|
if Block.equal b1 b2 then
|
||||||
|
Lwt.return b1
|
||||||
|
else if Time.(Block.timestamp b1 <= Block.timestamp b2) then
|
||||||
|
Block.predecessor b2 >>= function
|
||||||
|
| None -> assert false
|
||||||
|
| Some b2 -> loop b1 b2
|
||||||
|
else
|
||||||
|
Block.predecessor b1 >>= function
|
||||||
|
| None -> assert false
|
||||||
|
| Some b1 -> loop b1 b2 in
|
||||||
|
loop b1 b2
|
||||||
|
|
||||||
|
let block_locator (b: Block.t) sz =
|
||||||
|
let rec loop acc sz step cpt b =
|
||||||
|
if sz = 0 then
|
||||||
|
Lwt.return (List.rev acc)
|
||||||
|
else
|
||||||
|
Block.predecessor b >>= function
|
||||||
|
| None ->
|
||||||
|
Lwt.return (List.rev (Block.hash b :: acc))
|
||||||
|
| Some predecessor ->
|
||||||
|
if cpt = 0 then
|
||||||
|
loop (Block.hash b :: acc) (sz - 1)
|
||||||
|
(step * 2) (step * 20 - 1) predecessor
|
||||||
|
else if cpt mod step = 0 then
|
||||||
|
loop (Block.hash b :: acc) (sz - 1)
|
||||||
|
step (cpt - 1) predecessor
|
||||||
|
else
|
||||||
|
loop acc sz step (cpt - 1) predecessor in
|
||||||
|
loop [] sz 1 9 b
|
||||||
|
|
||||||
|
let iter_predecessors ?max ?min_fitness ?min_date heads ~f =
|
||||||
|
let module Local = struct exception Exit end in
|
||||||
|
let compare b1 b2 =
|
||||||
|
match Fitness.compare (Block.fitness b1) (Block.fitness b2) with
|
||||||
|
| 0 -> begin
|
||||||
|
match Time.compare (Block.timestamp b1) (Block.timestamp b2) with
|
||||||
|
| 0 -> Block.compare b1 b2
|
||||||
|
| res -> res
|
||||||
|
end
|
||||||
|
| res -> res in
|
||||||
|
let pop, push =
|
||||||
|
(* Poor-man priority queue *)
|
||||||
|
let queue : Block.t list ref = ref [] in
|
||||||
|
let pop () =
|
||||||
|
match !queue with
|
||||||
|
| [] -> None
|
||||||
|
| b :: bs -> queue := bs ; Some b in
|
||||||
|
let push b =
|
||||||
|
let rec loop = function
|
||||||
|
| [] -> [b]
|
||||||
|
| b' :: bs' as bs ->
|
||||||
|
let cmp = compare b b' in
|
||||||
|
if cmp = 0 then
|
||||||
|
bs
|
||||||
|
else if cmp < 0 then
|
||||||
|
b' :: loop bs'
|
||||||
|
else
|
||||||
|
b :: bs in
|
||||||
|
queue := loop !queue in
|
||||||
|
pop, push in
|
||||||
|
let check_count =
|
||||||
|
match max with
|
||||||
|
| None -> (fun () -> ())
|
||||||
|
| Some max ->
|
||||||
|
let cpt = ref 0 in
|
||||||
|
fun () ->
|
||||||
|
if !cpt >= max then raise Local.Exit ;
|
||||||
|
incr cpt in
|
||||||
|
let check_fitness =
|
||||||
|
match min_fitness with
|
||||||
|
| None -> (fun _ -> true)
|
||||||
|
| Some min_fitness ->
|
||||||
|
(fun b -> Fitness.compare min_fitness (Block.fitness b) <= 0) in
|
||||||
|
let check_date =
|
||||||
|
match min_date with
|
||||||
|
| None -> (fun _ -> true)
|
||||||
|
| Some min_date ->
|
||||||
|
(fun b -> Time.(min_date <= Block.timestamp b)) in
|
||||||
|
let rec loop () =
|
||||||
|
match pop () with
|
||||||
|
| None -> Lwt.return ()
|
||||||
|
| Some b ->
|
||||||
|
check_count () ;
|
||||||
|
f b >>= fun () ->
|
||||||
|
Block.predecessor b >>= function
|
||||||
|
| None -> loop ()
|
||||||
|
| Some p ->
|
||||||
|
if check_fitness p && check_date p then push p ;
|
||||||
|
loop () in
|
||||||
|
List.iter push heads ;
|
||||||
|
try loop () with Local.Exit -> Lwt.return ()
|
||||||
|
|
||||||
|
let iter_predecessors ?max ?min_fitness ?min_date heads ~f =
|
||||||
|
match heads with
|
||||||
|
| [] -> Lwt.return_unit
|
||||||
|
| b :: _ ->
|
||||||
|
let net_id = Block.net_id b in
|
||||||
|
if not (List.for_all (fun b -> Net_id.equal net_id (Block.net_id b)) heads) then
|
||||||
|
invalid_arg "State.Helpers.iter_predecessors" ;
|
||||||
|
iter_predecessors ?max ?min_fitness ?min_date heads ~f
|
||||||
|
|
||||||
|
let new_blocks ~from_block ~to_block =
|
||||||
|
common_ancestor from_block to_block >>= fun ancestor ->
|
||||||
|
path ancestor to_block >>= function
|
||||||
|
| None -> assert false
|
||||||
|
| Some path -> Lwt.return (ancestor, path)
|
48
src/node/shell/chain_traversal.mli
Normal file
48
src/node/shell/chain_traversal.mli
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
(**************************************************************************)
|
||||||
|
(* *)
|
||||||
|
(* Copyright (c) 2014 - 2016. *)
|
||||||
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
||||||
|
(* *)
|
||||||
|
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
||||||
|
(* *)
|
||||||
|
(**************************************************************************)
|
||||||
|
|
||||||
|
open State
|
||||||
|
|
||||||
|
val path: Block.t -> Block.t -> Block.t list option Lwt.t
|
||||||
|
(** If [h1] is an ancestor of [h2] in the current [state],
|
||||||
|
then [path state h1 h2] returns the chain of block from
|
||||||
|
[h1] (excluded) to [h2] (included). Returns [None] otherwise. *)
|
||||||
|
|
||||||
|
val common_ancestor: Block.t -> Block.t -> Block.t Lwt.t
|
||||||
|
(** [common_ancestor state h1 h2] returns the first common ancestors
|
||||||
|
in the history of blocks [h1] and [h2]. *)
|
||||||
|
|
||||||
|
val block_locator: Block.t -> int -> Block_hash.t list Lwt.t
|
||||||
|
(** [block_locator state max_length h] compute the sparse block locator
|
||||||
|
(/à la/ Bitcoin) for the block [h]. *)
|
||||||
|
|
||||||
|
val iter_predecessors:
|
||||||
|
?max:int ->
|
||||||
|
?min_fitness:Fitness.t ->
|
||||||
|
?min_date:Time.t ->
|
||||||
|
Block.t list ->
|
||||||
|
f:(Block.t -> unit Lwt.t) ->
|
||||||
|
unit Lwt.t
|
||||||
|
(** [iter_predecessors state blocks f] iter [f] on [blocks] and
|
||||||
|
their recursive predecessors. Blocks are visited with a
|
||||||
|
decreasing fitness (then decreasing timestamp). If the optional
|
||||||
|
argument [max] is provided, the iteration is stopped after [max]
|
||||||
|
visited block. If [min_fitness] id provided, blocks with a
|
||||||
|
fitness lower than [min_fitness] are ignored. If [min_date],
|
||||||
|
blocks with a fitness lower than [min_date] are ignored. *)
|
||||||
|
|
||||||
|
val new_blocks:
|
||||||
|
from_block:Block.t -> to_block:Block.t ->
|
||||||
|
(Block.t * Block.t list) Lwt.t
|
||||||
|
(** [new_blocks ~from_block ~to_block] returns a pair [(ancestor,
|
||||||
|
path)], where [ancestor] is the common ancestor of [from_block]
|
||||||
|
and [to_block] and where [path] is the chain from [ancestor]
|
||||||
|
(excluded) to [to_block] (included). The function raises an
|
||||||
|
exception when the two provided blocks do not belong the the same
|
||||||
|
[net]. *)
|
@ -66,40 +66,84 @@ module Make_raw
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module No_precheck = struct
|
module Fake_operation_storage = struct
|
||||||
type param = unit
|
type store = State.Net.t
|
||||||
let precheck _ _ _ = true
|
type key = Operation_hash.t
|
||||||
|
type value = Operation.t
|
||||||
|
let known _ _ = Lwt.return_false
|
||||||
|
let read _ _ = Lwt.return (Error_monad.error_exn Not_found)
|
||||||
|
let read_opt _ _ = Lwt.return_none
|
||||||
|
let read_exn _ _ = raise Not_found
|
||||||
end
|
end
|
||||||
|
|
||||||
module Raw_operation =
|
module Raw_operation =
|
||||||
Make_raw
|
Make_raw
|
||||||
(Operation_hash)
|
(Operation_hash)
|
||||||
(struct
|
(Fake_operation_storage)
|
||||||
type value = Operation.t
|
|
||||||
include State.Operation
|
|
||||||
end)
|
|
||||||
(Operation_hash.Table)
|
(Operation_hash.Table)
|
||||||
(struct
|
(struct
|
||||||
type param = Net_id.t
|
type param = Net_id.t
|
||||||
let forge net_id keys = Message.Get_operations (net_id, keys)
|
let forge net_id keys = Message.Get_operations (net_id, keys)
|
||||||
end)
|
end)
|
||||||
(No_precheck)
|
(struct
|
||||||
|
type param = unit
|
||||||
|
type notified_value = Operation.t
|
||||||
|
let precheck _ _ v = Some v
|
||||||
|
end)
|
||||||
|
|
||||||
|
module Block_header_storage = struct
|
||||||
|
type store = State.Net.t
|
||||||
|
type key = Block_hash.t
|
||||||
|
type value = Block_header.t
|
||||||
|
let known = State.Block.known_valid
|
||||||
|
let read net_state h =
|
||||||
|
State.Block.read net_state h >>=? fun b ->
|
||||||
|
return (State.Block.header b)
|
||||||
|
let read_opt net_state h =
|
||||||
|
State.Block.read_opt net_state h >>= fun b ->
|
||||||
|
Lwt.return (Utils.map_option State.Block.header b)
|
||||||
|
let read_exn net_state h =
|
||||||
|
State.Block.read_exn net_state h >>= fun b ->
|
||||||
|
Lwt.return (State.Block.header b)
|
||||||
|
end
|
||||||
|
|
||||||
module Raw_block_header =
|
module Raw_block_header =
|
||||||
Make_raw
|
Make_raw
|
||||||
(Block_hash)
|
(Block_hash)
|
||||||
(struct
|
(Block_header_storage)
|
||||||
type value = Block_header.t
|
|
||||||
include State.Block_header
|
|
||||||
end)
|
|
||||||
(Block_hash.Table)
|
(Block_hash.Table)
|
||||||
(struct
|
(struct
|
||||||
type param = Net_id.t
|
type param = Net_id.t
|
||||||
let forge net_id keys = Message.Get_block_headers (net_id, keys)
|
let forge net_id keys = Message.Get_block_headers (net_id, keys)
|
||||||
end)
|
end)
|
||||||
(No_precheck)
|
(struct
|
||||||
|
type param = unit
|
||||||
|
type notified_value = Block_header.t
|
||||||
|
let precheck _ _ v = Some v
|
||||||
|
end)
|
||||||
|
|
||||||
module Operation_list_table =
|
module Operation_hashes_storage = struct
|
||||||
|
type store = State.Net.t
|
||||||
|
type key = Block_hash.t * int
|
||||||
|
type value = Operation_hash.t list
|
||||||
|
let known net_state (h, _) = State.Block.known_valid net_state h
|
||||||
|
let read net_state (h, i) =
|
||||||
|
State.Block.read net_state h >>=? fun b ->
|
||||||
|
State.Block.operation_hashes b i >>= fun (ops, _) ->
|
||||||
|
return ops
|
||||||
|
let read_opt net_state (h, i) =
|
||||||
|
State.Block.read_opt net_state h >>= function
|
||||||
|
| None -> Lwt.return_none
|
||||||
|
| Some b ->
|
||||||
|
State.Block.operation_hashes b i >>= fun (ops, _) ->
|
||||||
|
Lwt.return (Some ops)
|
||||||
|
let read_exn net_state (h, i) =
|
||||||
|
State.Block.read_exn net_state h >>= fun b ->
|
||||||
|
State.Block.operation_hashes b i >>= fun (ops, _) ->
|
||||||
|
Lwt.return ops
|
||||||
|
end
|
||||||
|
|
||||||
|
module Operations_table =
|
||||||
Hashtbl.Make(struct
|
Hashtbl.Make(struct
|
||||||
type t = Block_hash.t * int
|
type t = Block_hash.t * int
|
||||||
let hash = Hashtbl.hash
|
let hash = Hashtbl.hash
|
||||||
@ -107,39 +151,134 @@ module Operation_list_table =
|
|||||||
Block_hash.equal b1 b2 && i1 = i2
|
Block_hash.equal b1 b2 && i1 = i2
|
||||||
end)
|
end)
|
||||||
|
|
||||||
module Raw_operation_list =
|
module Raw_operation_hashes = struct
|
||||||
Make_raw
|
|
||||||
(struct type t = Block_hash.t * int end)
|
include
|
||||||
(State.Operation_list)
|
Make_raw
|
||||||
(Operation_list_table)
|
(struct type t = Block_hash.t * int end)
|
||||||
(struct
|
(Operation_hashes_storage)
|
||||||
type param = Net_id.t
|
(Operations_table)
|
||||||
let forge net_id keys =
|
(struct
|
||||||
Message.Get_operation_list (net_id, keys)
|
type param = Net_id.t
|
||||||
end)
|
let forge net_id keys =
|
||||||
(struct
|
Message.Get_operation_hashes_for_blocks (net_id, keys)
|
||||||
type param = Operation_list_list_hash.t
|
end)
|
||||||
let precheck (_block, expected_ofs) expected_hash (ops, path) =
|
(struct
|
||||||
let received_hash, received_ofs =
|
type param = Operation_list_list_hash.t
|
||||||
Operation_list_list_hash.check_path path
|
type notified_value =
|
||||||
(Operation_list_hash.compute ops) in
|
Operation_hash.t list * Operation_list_list_hash.path
|
||||||
received_ofs = expected_ofs &&
|
let precheck (_block, expected_ofs) expected_hash (ops, path) =
|
||||||
Operation_list_list_hash.compare expected_hash received_hash = 0
|
let received_hash, received_ofs =
|
||||||
end)
|
Operation_list_list_hash.check_path path
|
||||||
|
(Operation_list_hash.compute ops) in
|
||||||
|
if
|
||||||
|
received_ofs = expected_ofs &&
|
||||||
|
Operation_list_list_hash.compare expected_hash received_hash = 0
|
||||||
|
then
|
||||||
|
Some ops
|
||||||
|
else
|
||||||
|
None
|
||||||
|
end)
|
||||||
|
|
||||||
|
let inject_all table hash operations =
|
||||||
|
Lwt_list.mapi_p
|
||||||
|
(fun i ops -> Table.inject table (hash, i) ops)
|
||||||
|
operations >>= Lwt_list.for_all_s (fun x -> Lwt.return x)
|
||||||
|
|
||||||
|
let read_all table hash n =
|
||||||
|
map_p (fun i -> Table.read table (hash, i)) (0 -- (n-1))
|
||||||
|
|
||||||
|
let remove_all table hash n =
|
||||||
|
Lwt_list.iter_p (fun i -> Table.remove table (hash, i)) (0 -- (n-1))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module Operations_storage = struct
|
||||||
|
type store = State.Net.t
|
||||||
|
type key = Block_hash.t * int
|
||||||
|
type value = Operation.t list
|
||||||
|
let known net_state (h, _) = State.Block.known_valid net_state h
|
||||||
|
let read net_state (h, i) =
|
||||||
|
State.Block.read net_state h >>=? fun b ->
|
||||||
|
State.Block.operations b i >>= fun (ops, _) ->
|
||||||
|
return ops
|
||||||
|
let read_opt net_state (h, i) =
|
||||||
|
State.Block.read_opt net_state h >>= function
|
||||||
|
| None -> Lwt.return_none
|
||||||
|
| Some b ->
|
||||||
|
State.Block.operations b i >>= fun (ops, _) ->
|
||||||
|
Lwt.return (Some ops)
|
||||||
|
let read_exn net_state (h, i) =
|
||||||
|
State.Block.read_exn net_state h >>= fun b ->
|
||||||
|
State.Block.operations b i >>= fun (ops, _) ->
|
||||||
|
Lwt.return ops
|
||||||
|
end
|
||||||
|
|
||||||
|
module Raw_operations = struct
|
||||||
|
include
|
||||||
|
Make_raw
|
||||||
|
(struct type t = Block_hash.t * int end)
|
||||||
|
(Operations_storage)
|
||||||
|
(Operations_table)
|
||||||
|
(struct
|
||||||
|
type param = Net_id.t
|
||||||
|
let forge net_id keys =
|
||||||
|
Message.Get_operations_for_blocks (net_id, keys)
|
||||||
|
end)
|
||||||
|
(struct
|
||||||
|
type param = Operation_list_list_hash.t
|
||||||
|
type notified_value = Operation.t list * Operation_list_list_hash.path
|
||||||
|
let precheck (_block, expected_ofs) expected_hash (ops, path) =
|
||||||
|
let received_hash, received_ofs =
|
||||||
|
Operation_list_list_hash.check_path path
|
||||||
|
(Operation_list_hash.compute
|
||||||
|
(List.map Operation.hash ops)) in
|
||||||
|
if
|
||||||
|
received_ofs = expected_ofs &&
|
||||||
|
Operation_list_list_hash.compare expected_hash received_hash = 0
|
||||||
|
then
|
||||||
|
Some ops
|
||||||
|
else
|
||||||
|
None
|
||||||
|
end)
|
||||||
|
|
||||||
|
let inject_all table hash operations =
|
||||||
|
Lwt_list.mapi_p
|
||||||
|
(fun i ops -> Table.inject table (hash, i) ops)
|
||||||
|
operations >>= Lwt_list.for_all_s (fun x -> Lwt.return x)
|
||||||
|
|
||||||
|
let read_all table hash n =
|
||||||
|
map_p (fun i -> Table.read table (hash, i)) (0 -- (n-1))
|
||||||
|
|
||||||
|
let remove_all table hash n =
|
||||||
|
Lwt_list.iter_p (fun i -> Table.remove table (hash, i)) (0 -- (n-1))
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module Protocol_storage = struct
|
||||||
|
type store = State.t
|
||||||
|
type key = Protocol_hash.t
|
||||||
|
type value = Protocol.t
|
||||||
|
let known = State.Protocol.known
|
||||||
|
let read = State.Protocol.read
|
||||||
|
let read_opt = State.Protocol.read_opt
|
||||||
|
let read_exn = State.Protocol.read_exn
|
||||||
|
end
|
||||||
|
|
||||||
module Raw_protocol =
|
module Raw_protocol =
|
||||||
Make_raw
|
Make_raw
|
||||||
(Protocol_hash)
|
(Protocol_hash)
|
||||||
(struct
|
(Protocol_storage)
|
||||||
type value = Protocol.t
|
|
||||||
include State.Protocol
|
|
||||||
end)
|
|
||||||
(Protocol_hash.Table)
|
(Protocol_hash.Table)
|
||||||
(struct
|
(struct
|
||||||
type param = unit
|
type param = unit
|
||||||
let forge () keys = Message.Get_protocols keys
|
let forge () keys = Message.Get_protocols keys
|
||||||
end)
|
end)
|
||||||
(No_precheck)
|
(struct
|
||||||
|
type param = unit
|
||||||
|
type notified_value = Protocol.t
|
||||||
|
let precheck _ _ v = Some v
|
||||||
|
end)
|
||||||
|
|
||||||
type callback = {
|
type callback = {
|
||||||
notify_branch: P2p.Peer_id.t -> Block_hash.t list -> unit ;
|
notify_branch: P2p.Peer_id.t -> Block_hash.t list -> unit ;
|
||||||
@ -153,18 +292,19 @@ type db = {
|
|||||||
p2p: p2p ;
|
p2p: p2p ;
|
||||||
p2p_readers: p2p_reader P2p.Peer_id.Table.t ;
|
p2p_readers: p2p_reader P2p.Peer_id.Table.t ;
|
||||||
disk: State.t ;
|
disk: State.t ;
|
||||||
active_nets: net Net_id.Table.t ;
|
active_nets: net_db Net_id.Table.t ;
|
||||||
protocol_db: Raw_protocol.t ;
|
protocol_db: Raw_protocol.t ;
|
||||||
block_input: (Block_hash.t * Block_header.t) Watcher.input ;
|
block_input: (Block_hash.t * Block_header.t) Watcher.input ;
|
||||||
operation_input: (Operation_hash.t * Operation.t) Watcher.input ;
|
operation_input: (Operation_hash.t * Operation.t) Watcher.input ;
|
||||||
}
|
}
|
||||||
|
|
||||||
and net = {
|
and net_db = {
|
||||||
net: State.Net.t ;
|
net_state: State.Net.t ;
|
||||||
global_db: db ;
|
global_db: db ;
|
||||||
operation_db: Raw_operation.t ;
|
operation_db: Raw_operation.t ;
|
||||||
block_header_db: Raw_block_header.t ;
|
block_header_db: Raw_block_header.t ;
|
||||||
operation_list_db: Raw_operation_list.t ;
|
operation_hashes_db: Raw_operation_hashes.t ;
|
||||||
|
operations_db: Raw_operations.t ;
|
||||||
callback: callback ;
|
callback: callback ;
|
||||||
active_peers: P2p.Peer_id.Set.t ref ;
|
active_peers: P2p.Peer_id.Set.t ref ;
|
||||||
active_connections: p2p_reader P2p.Peer_id.Table.t ;
|
active_connections: p2p_reader P2p.Peer_id.Table.t ;
|
||||||
@ -173,14 +313,14 @@ and net = {
|
|||||||
and p2p_reader = {
|
and p2p_reader = {
|
||||||
gid: P2p.Peer_id.t ;
|
gid: P2p.Peer_id.t ;
|
||||||
conn: connection ;
|
conn: connection ;
|
||||||
peer_active_nets: net Net_id.Table.t ;
|
peer_active_nets: net_db Net_id.Table.t ;
|
||||||
canceler: Lwt_utils.Canceler.t ;
|
canceler: Lwt_utils.Canceler.t ;
|
||||||
mutable worker: unit Lwt.t ;
|
mutable worker: unit Lwt.t ;
|
||||||
}
|
}
|
||||||
|
|
||||||
type t = db
|
type t = db
|
||||||
|
|
||||||
let state { net } = net
|
let state { net_state } = net_state
|
||||||
|
|
||||||
module P2p_reader = struct
|
module P2p_reader = struct
|
||||||
|
|
||||||
@ -248,7 +388,12 @@ module P2p_reader = struct
|
|||||||
|
|
||||||
| Current_branch (net_id, locator) ->
|
| Current_branch (net_id, locator) ->
|
||||||
may_activate global_db state net_id @@ fun net_db ->
|
may_activate global_db state net_id @@ fun net_db ->
|
||||||
net_db.callback.notify_branch state.gid locator ;
|
Lwt_list.exists_p
|
||||||
|
(State.Block.known_invalid net_db.net_state)
|
||||||
|
locator >>= fun known_invalid ->
|
||||||
|
if not known_invalid then
|
||||||
|
net_db.callback.notify_branch state.gid locator ;
|
||||||
|
(* TODO Kickban *)
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
|
|
||||||
| Deactivate net_id ->
|
| Deactivate net_id ->
|
||||||
@ -267,22 +412,23 @@ module P2p_reader = struct
|
|||||||
|
|
||||||
| Current_head (net_id, head, mempool) ->
|
| Current_head (net_id, head, mempool) ->
|
||||||
may_handle state net_id @@ fun net_db ->
|
may_handle state net_id @@ fun net_db ->
|
||||||
net_db.callback.notify_head state.gid head mempool ;
|
State.Block.known_invalid net_db.net_state head >>= fun known_invalid ->
|
||||||
|
if not known_invalid then
|
||||||
|
net_db.callback.notify_head state.gid head mempool ;
|
||||||
|
(* TODO Kickban *)
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
|
|
||||||
| Get_block_headers (net_id, hashes) ->
|
| Get_block_headers (net_id, hashes) ->
|
||||||
may_handle state net_id @@ fun net_db ->
|
may_handle state net_id @@ fun net_db ->
|
||||||
(* Should we filter out invalid block ? *)
|
(* TODO: Blame request of unadvertised blocks ? *)
|
||||||
(* Should we filter out blocks whose validity is unknown ? *)
|
|
||||||
(* Should we blame request of unadvertised blocks ? *)
|
|
||||||
Lwt_list.iter_p
|
Lwt_list.iter_p
|
||||||
(fun hash ->
|
(fun hash ->
|
||||||
Raw_block_header.Table.read
|
State.Block.read_opt net_db.net_state hash >|= function
|
||||||
net_db.block_header_db.table hash >|= function
|
|
||||||
| None -> ()
|
| None -> ()
|
||||||
| Some p ->
|
| Some b ->
|
||||||
|
let header = State.Block.header b in
|
||||||
ignore @@
|
ignore @@
|
||||||
P2p.try_send global_db.p2p state.conn (Block_header p))
|
P2p.try_send global_db.p2p state.conn (Block_header header))
|
||||||
hashes
|
hashes
|
||||||
|
|
||||||
| Block_header block ->
|
| Block_header block ->
|
||||||
@ -294,9 +440,10 @@ module P2p_reader = struct
|
|||||||
|
|
||||||
| Get_operations (net_id, hashes) ->
|
| Get_operations (net_id, hashes) ->
|
||||||
may_handle state net_id @@ fun net_db ->
|
may_handle state net_id @@ fun net_db ->
|
||||||
|
(* TODO: only answers for prevalidated operations *)
|
||||||
Lwt_list.iter_p
|
Lwt_list.iter_p
|
||||||
(fun hash ->
|
(fun hash ->
|
||||||
Raw_operation.Table.read
|
Raw_operation.Table.read_opt
|
||||||
net_db.operation_db.table hash >|= function
|
net_db.operation_db.table hash >|= function
|
||||||
| None -> ()
|
| None -> ()
|
||||||
| Some p ->
|
| Some p ->
|
||||||
@ -314,8 +461,7 @@ module P2p_reader = struct
|
|||||||
| Get_protocols hashes ->
|
| Get_protocols hashes ->
|
||||||
Lwt_list.iter_p
|
Lwt_list.iter_p
|
||||||
(fun hash ->
|
(fun hash ->
|
||||||
Raw_protocol.Table.read
|
State.Protocol.read_opt global_db.disk hash >|= function
|
||||||
global_db.protocol_db.table hash >|= function
|
|
||||||
| None -> ()
|
| None -> ()
|
||||||
| Some p ->
|
| Some p ->
|
||||||
ignore @@
|
ignore @@
|
||||||
@ -328,22 +474,23 @@ module P2p_reader = struct
|
|||||||
global_db.protocol_db.table state.gid hash protocol >>= fun () ->
|
global_db.protocol_db.table state.gid hash protocol >>= fun () ->
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
|
|
||||||
| Get_operation_list (net_id, hashes) ->
|
| Get_operation_hashes_for_blocks (net_id, blocks) ->
|
||||||
may_handle state net_id @@ fun net_db ->
|
may_handle state net_id @@ fun net_db ->
|
||||||
|
(* TODO: Blame request of unadvertised blocks ? *)
|
||||||
Lwt_list.iter_p
|
Lwt_list.iter_p
|
||||||
(fun (block, ofs as key) ->
|
(fun (hash, ofs) ->
|
||||||
Raw_operation_list.Table.read
|
State.Block.read_opt net_db.net_state hash >>= function
|
||||||
net_db.operation_list_db.table key >>= function
|
|
||||||
| None -> Lwt.return_unit
|
| None -> Lwt.return_unit
|
||||||
| Some (ops, path) ->
|
| Some b ->
|
||||||
|
State.Block.operation_hashes b ofs >>= fun (hashes, path) ->
|
||||||
ignore @@
|
ignore @@
|
||||||
P2p.try_send
|
P2p.try_send global_db.p2p state.conn
|
||||||
global_db.p2p state.conn
|
(Operation_hashes_for_block
|
||||||
(Operation_list (net_id, block, ofs, ops, path)) ;
|
(net_id, hash, ofs, hashes, path)) ;
|
||||||
Lwt.return_unit)
|
Lwt.return_unit)
|
||||||
hashes
|
blocks
|
||||||
|
|
||||||
| Operation_list (net_id, block, ofs, ops, path) ->
|
| Operation_hashes_for_block (net_id, block, ofs, ops, path) -> begin
|
||||||
may_handle state net_id @@ fun net_db ->
|
may_handle state net_id @@ fun net_db ->
|
||||||
(* TODO early detection of non-requested list. *)
|
(* TODO early detection of non-requested list. *)
|
||||||
let found_hash, found_ofs =
|
let found_hash, found_ofs =
|
||||||
@ -352,7 +499,46 @@ module P2p_reader = struct
|
|||||||
if found_ofs <> ofs then
|
if found_ofs <> ofs then
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
else
|
else
|
||||||
Raw_block_header.Table.read
|
Raw_block_header.Table.read_opt
|
||||||
|
net_db.block_header_db.table block >>= function
|
||||||
|
| None -> Lwt.return_unit
|
||||||
|
| Some bh ->
|
||||||
|
if Operation_list_list_hash.compare
|
||||||
|
found_hash bh.shell.operations_hash <> 0 then
|
||||||
|
Lwt.return_unit
|
||||||
|
else
|
||||||
|
Raw_operation_hashes.Table.notify
|
||||||
|
net_db.operation_hashes_db.table state.gid
|
||||||
|
(block, ofs) (ops, path) >>= fun () ->
|
||||||
|
Lwt.return_unit
|
||||||
|
end
|
||||||
|
|
||||||
|
| Get_operations_for_blocks (net_id, blocks) ->
|
||||||
|
may_handle state net_id @@ fun net_db ->
|
||||||
|
(* TODO: Blame request of unadvertised blocks ? *)
|
||||||
|
Lwt_list.iter_p
|
||||||
|
(fun (hash, ofs) ->
|
||||||
|
State.Block.read_opt net_db.net_state hash >>= function
|
||||||
|
| None -> Lwt.return_unit
|
||||||
|
| Some b ->
|
||||||
|
State.Block.operations b ofs >>= fun (hashes, path) ->
|
||||||
|
ignore @@
|
||||||
|
P2p.try_send global_db.p2p state.conn
|
||||||
|
(Operations_for_block
|
||||||
|
(net_id, hash, ofs, hashes, path)) ;
|
||||||
|
Lwt.return_unit)
|
||||||
|
blocks
|
||||||
|
|
||||||
|
| Operations_for_block (net_id, block, ofs, ops, path) ->
|
||||||
|
may_handle state net_id @@ fun net_db ->
|
||||||
|
(* TODO early detection of non-requested operations. *)
|
||||||
|
let found_hash, found_ofs =
|
||||||
|
Operation_list_list_hash.check_path
|
||||||
|
path (Operation_list_hash.compute (List.map Operation.hash ops)) in
|
||||||
|
if found_ofs <> ofs then
|
||||||
|
Lwt.return_unit
|
||||||
|
else
|
||||||
|
Raw_block_header.Table.read_opt
|
||||||
net_db.block_header_db.table block >>= function
|
net_db.block_header_db.table block >>= function
|
||||||
| None -> Lwt.return_unit
|
| None -> Lwt.return_unit
|
||||||
| Some bh ->
|
| Some bh ->
|
||||||
@ -360,8 +546,8 @@ module P2p_reader = struct
|
|||||||
found_hash bh.shell.operations_hash <> 0 then
|
found_hash bh.shell.operations_hash <> 0 then
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
else
|
else
|
||||||
Raw_operation_list.Table.notify
|
Raw_operations.Table.notify
|
||||||
net_db.operation_list_db.table state.gid
|
net_db.operations_db.table state.gid
|
||||||
(block, ofs) (ops, path) >>= fun () ->
|
(block, ofs) (ops, path) >>= fun () ->
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
|
|
||||||
@ -435,28 +621,30 @@ let create disk p2p =
|
|||||||
P2p.iter_connections p2p (P2p_reader.run db) ;
|
P2p.iter_connections p2p (P2p_reader.run db) ;
|
||||||
db
|
db
|
||||||
|
|
||||||
let activate ~callback ({ p2p ; active_nets } as global_db) net =
|
let activate ~callback ({ p2p ; active_nets } as global_db) net_state =
|
||||||
let net_id = State.Net.id net in
|
let net_id = State.Net.id net_state in
|
||||||
match Net_id.Table.find active_nets net_id with
|
match Net_id.Table.find active_nets net_id with
|
||||||
| exception Not_found ->
|
| exception Not_found ->
|
||||||
let active_peers = ref P2p.Peer_id.Set.empty in
|
let active_peers = ref P2p.Peer_id.Set.empty in
|
||||||
let p2p_request =
|
let p2p_request =
|
||||||
let net_id = State.Net.id net in
|
|
||||||
{ data = net_id ;
|
{ data = net_id ;
|
||||||
active = (fun () -> !active_peers) ;
|
active = (fun () -> !active_peers) ;
|
||||||
send = raw_try_send p2p ;
|
send = raw_try_send p2p ;
|
||||||
} in
|
} in
|
||||||
let operation_db =
|
let operation_db =
|
||||||
Raw_operation.create
|
Raw_operation.create
|
||||||
~global_input:global_db.operation_input p2p_request net in
|
~global_input:global_db.operation_input p2p_request net_state in
|
||||||
let block_header_db =
|
let block_header_db =
|
||||||
Raw_block_header.create
|
Raw_block_header.create
|
||||||
~global_input:global_db.block_input p2p_request net in
|
~global_input:global_db.block_input p2p_request net_state in
|
||||||
let operation_list_db =
|
let operation_hashes_db =
|
||||||
Raw_operation_list.create p2p_request net in
|
Raw_operation_hashes.create p2p_request net_state in
|
||||||
|
let operations_db =
|
||||||
|
Raw_operations.create p2p_request net_state in
|
||||||
let net = {
|
let net = {
|
||||||
global_db ; operation_db ; block_header_db ; operation_list_db ;
|
global_db ; operation_db ; block_header_db ;
|
||||||
net ; callback ; active_peers ;
|
operation_hashes_db ; operations_db ;
|
||||||
|
net_state ; callback ; active_peers ;
|
||||||
active_connections = P2p.Peer_id.Table.create 53 ;
|
active_connections = P2p.Peer_id.Table.create 53 ;
|
||||||
} in
|
} in
|
||||||
P2p.iter_connections p2p (fun _peer_id conn ->
|
P2p.iter_connections p2p (fun _peer_id conn ->
|
||||||
@ -468,19 +656,19 @@ let activate ~callback ({ p2p ; active_nets } as global_db) net =
|
|||||||
| net ->
|
| net ->
|
||||||
net
|
net
|
||||||
|
|
||||||
let deactivate net =
|
let deactivate net_db =
|
||||||
let { active_nets ; p2p } = net.global_db in
|
let { active_nets ; p2p } = net_db.global_db in
|
||||||
let net_id = State.Net.id net.net in
|
let net_id = State.Net.id net_db.net_state in
|
||||||
Net_id.Table.remove active_nets net_id ;
|
Net_id.Table.remove active_nets net_id ;
|
||||||
P2p.Peer_id.Table.iter
|
P2p.Peer_id.Table.iter
|
||||||
(fun _peer_id reader ->
|
(fun _peer_id reader ->
|
||||||
P2p_reader.deactivate reader net ;
|
P2p_reader.deactivate reader net_db ;
|
||||||
Lwt.async begin fun () ->
|
Lwt.async begin fun () ->
|
||||||
P2p.send p2p reader.conn (Deactivate net_id)
|
P2p.send p2p reader.conn (Deactivate net_id)
|
||||||
end)
|
end)
|
||||||
net.active_connections ;
|
net_db.active_connections ;
|
||||||
Raw_operation.shutdown net.operation_db >>= fun () ->
|
Raw_operation.shutdown net_db.operation_db >>= fun () ->
|
||||||
Raw_block_header.shutdown net.block_header_db >>= fun () ->
|
Raw_block_header.shutdown net_db.block_header_db >>= fun () ->
|
||||||
Lwt.return_unit >>= fun () ->
|
Lwt.return_unit >>= fun () ->
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
|
|
||||||
@ -504,212 +692,133 @@ let shutdown { p2p ; p2p_readers ; active_nets } =
|
|||||||
P2p.shutdown p2p >>= fun () ->
|
P2p.shutdown p2p >>= fun () ->
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
|
|
||||||
module type PARAMETRIZED_DISTRIBUTED_DB =
|
let read_all_operations net_db hash n =
|
||||||
Distributed_db_functors.PARAMETRIZED_DISTRIBUTED_DB
|
Lwt_list.map_p
|
||||||
module type DISTRIBUTED_DB =
|
(fun i ->
|
||||||
Distributed_db_functors.DISTRIBUTED_DB
|
Raw_operations.Table.read_opt net_db.operations_db.table (hash, i))
|
||||||
|
(0 -- (n-1)) >>= fun operations ->
|
||||||
|
mapi_p
|
||||||
|
(fun i ops ->
|
||||||
|
match ops with
|
||||||
|
| Some ops -> return ops
|
||||||
|
| None ->
|
||||||
|
Raw_operation_hashes.Table.read
|
||||||
|
net_db.operation_hashes_db.table (hash, i) >>=? fun hashes ->
|
||||||
|
map_p (Raw_operation.Table.read net_db.operation_db.table) hashes)
|
||||||
|
operations
|
||||||
|
|
||||||
module Make
|
let commit_block net_db hash n validation_result =
|
||||||
(Table : PARAMETRIZED_DISTRIBUTED_DB with type param := unit)
|
Raw_block_header.Table.read
|
||||||
(Kind : sig
|
net_db.block_header_db.table hash >>=? fun header ->
|
||||||
type t
|
read_all_operations net_db hash n >>=? fun operations ->
|
||||||
val proj: t -> Table.t
|
State.Block.store
|
||||||
end) = struct
|
net_db.net_state header operations validation_result >>=? fun res ->
|
||||||
type t = Kind.t
|
Raw_block_header.Table.remove
|
||||||
type key = Table.key
|
net_db.block_header_db.table hash >>= fun () ->
|
||||||
type value = Table.value
|
Raw_operation_hashes.remove_all
|
||||||
let known t k = Table.known (Kind.proj t) k
|
net_db.operation_hashes_db.table hash n >>= fun () ->
|
||||||
let read t k = Table.read (Kind.proj t) k
|
Raw_operations.remove_all
|
||||||
let read_exn t k = Table.read_exn (Kind.proj t) k
|
net_db.operations_db.table hash n >>= fun () ->
|
||||||
let prefetch t ?peer k = Table.prefetch (Kind.proj t) ?peer k ()
|
(* TODO: proper handling of the operations table by the prevalidator. *)
|
||||||
let fetch t ?peer k = Table.fetch (Kind.proj t) ?peer k ()
|
Lwt_list.iter_p
|
||||||
let commit t k = Table.commit (Kind.proj t) k
|
(Lwt_list.iter_p
|
||||||
let inject t k v = Table.inject (Kind.proj t) k v
|
(fun op -> Raw_operation.Table.remove
|
||||||
let watch t = Table.watch (Kind.proj t)
|
net_db.operation_db.table
|
||||||
end
|
(Operation.hash op)))
|
||||||
|
operations >>= fun () ->
|
||||||
|
return res
|
||||||
|
|
||||||
module Operation =
|
let commit_invalid_block net_db hash n =
|
||||||
Make (Raw_operation.Table) (struct
|
Raw_block_header.Table.read
|
||||||
type t = net
|
net_db.block_header_db.table hash >>=? fun header ->
|
||||||
let proj net = net.operation_db.table
|
State.Block.store_invalid net_db.net_state header >>=? fun res ->
|
||||||
end)
|
Raw_block_header.Table.remove
|
||||||
|
net_db.block_header_db.table hash >>= fun () ->
|
||||||
|
Raw_operation_hashes.remove_all
|
||||||
|
net_db.operation_hashes_db.table hash n >>= fun () ->
|
||||||
|
Raw_operations.remove_all
|
||||||
|
net_db.operations_db.table hash n >>= fun () ->
|
||||||
|
return res
|
||||||
|
|
||||||
module Block_header =
|
let inject_operation net_db h op =
|
||||||
Make (Raw_block_header.Table) (struct
|
fail_unless
|
||||||
type t = net
|
(Net_id.equal op.Operation.shell.net_id (State.Net.id net_db.net_state))
|
||||||
let proj net = net.block_header_db.table
|
(failure "Inconsitent net_id in operation") >>=? fun () ->
|
||||||
end)
|
Raw_operation.Table.inject net_db.operation_db.table h op >>= fun res ->
|
||||||
|
return res
|
||||||
|
|
||||||
module Protocol =
|
let inject_protocol db h p =
|
||||||
Make (Raw_protocol.Table) (struct
|
Raw_protocol.Table.inject db.protocol_db.table h p
|
||||||
type t = db
|
|
||||||
let proj db = db.protocol_db.table
|
|
||||||
end)
|
|
||||||
|
|
||||||
module Operation_list = struct
|
let commit_protocol db h =
|
||||||
|
Raw_protocol.Table.read db.protocol_db.table h >>=? fun p ->
|
||||||
|
State.Protocol.store db.disk p >>= fun res ->
|
||||||
|
Raw_protocol.Table.remove db.protocol_db.table h >>= fun () ->
|
||||||
|
return (res <> None)
|
||||||
|
|
||||||
type t = net
|
type operation =
|
||||||
type key = Block_hash.t * int
|
| Blob of Operation.t
|
||||||
type value = Operation_hash.t list
|
| Hash of Operation_hash.t
|
||||||
type param = Operation_list_list_hash.t
|
|
||||||
|
|
||||||
let proj net = net.operation_list_db.table
|
let resolve_operation net_db = function
|
||||||
|
| Blob op ->
|
||||||
|
fail_unless
|
||||||
|
(Net_id.equal op.shell.net_id (State.Net.id net_db.net_state))
|
||||||
|
(failure "Inconsistent net_id in operation.") >>=? fun () ->
|
||||||
|
return (Operation.hash op, op)
|
||||||
|
| Hash oph ->
|
||||||
|
Raw_operation.Table.read net_db.operation_db.table oph >>=? fun op ->
|
||||||
|
return (oph, op)
|
||||||
|
|
||||||
module Table = Raw_operation_list.Table
|
let inject_block db bytes operations =
|
||||||
|
|
||||||
let known t k = Table.known (proj t) k
|
|
||||||
let read t k =
|
|
||||||
Table.read (proj t) k >>= function
|
|
||||||
| None -> Lwt.return_none
|
|
||||||
| Some (op, _) -> Lwt.return (Some op)
|
|
||||||
let read_exn t k = Table.read_exn (proj t) k >|= fst
|
|
||||||
let prefetch t ?peer k p = Table.prefetch (proj t) ?peer k p
|
|
||||||
let fetch t ?peer k p = Table.fetch (proj t) ?peer k p >|= fst
|
|
||||||
|
|
||||||
let rec do_read net block acc i =
|
|
||||||
if i <= 0 then
|
|
||||||
Lwt.return acc
|
|
||||||
else
|
|
||||||
read_exn net (block, i-1) >>= fun ops ->
|
|
||||||
do_read net block (ops :: acc) (i-1)
|
|
||||||
|
|
||||||
let read_all_opt net block =
|
|
||||||
State.Operation_list.read_count_opt
|
|
||||||
net.net block >>= function
|
|
||||||
| None -> Lwt.return_none
|
|
||||||
| Some len -> do_read net block [] len >>= fun ops -> Lwt.return (Some ops)
|
|
||||||
|
|
||||||
let read_all_exn net block =
|
|
||||||
State.Operation_list.read_count_exn
|
|
||||||
net.net block >>= fun len ->
|
|
||||||
do_read net block [] len
|
|
||||||
|
|
||||||
let rec do_commit net block i =
|
|
||||||
if i <= 0 then
|
|
||||||
Lwt.return_unit
|
|
||||||
else
|
|
||||||
Raw_operation_list.Table.commit
|
|
||||||
net.operation_list_db.table (block, i-1) >>= fun () ->
|
|
||||||
do_commit net block (i-1)
|
|
||||||
|
|
||||||
let commit_all net block len =
|
|
||||||
State.Operation_list.store_count net.net block len >>= fun () ->
|
|
||||||
do_commit net block len
|
|
||||||
|
|
||||||
let inject_all net block opss =
|
|
||||||
State.Operation_list.read_count_opt net.net block >>= function
|
|
||||||
| Some _ -> Lwt.return_false
|
|
||||||
| None ->
|
|
||||||
let hashes = List.map Operation_list_hash.compute opss in
|
|
||||||
Lwt_list.mapi_p
|
|
||||||
(fun i ops ->
|
|
||||||
let path = Operation_list_list_hash.compute_path hashes i in
|
|
||||||
Raw_operation_list.Table.inject
|
|
||||||
net.operation_list_db.table
|
|
||||||
(block, i) (ops, path))
|
|
||||||
opss >>= fun injected ->
|
|
||||||
Lwt.return (List.for_all (fun x -> x) injected)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
let inject_block t bytes operations =
|
|
||||||
let hash = Block_hash.hash_bytes [bytes] in
|
let hash = Block_hash.hash_bytes [bytes] in
|
||||||
match
|
match Block_header.of_bytes bytes with
|
||||||
Data_encoding.Binary.of_bytes Tezos_data.Block_header.encoding bytes
|
|
||||||
with
|
|
||||||
| None ->
|
| None ->
|
||||||
failwith "Cannot parse block header."
|
failwith "Cannot parse block header."
|
||||||
| Some block ->
|
| Some block ->
|
||||||
match get_net t block.shell.net_id with
|
match get_net db block.shell.net_id with
|
||||||
| None ->
|
| None ->
|
||||||
failwith "Unknown network."
|
failwith "Unknown network."
|
||||||
| Some net_db ->
|
| Some net_db ->
|
||||||
Block_header.known net_db hash >>= function
|
map_p
|
||||||
| true ->
|
(map_p (resolve_operation net_db))
|
||||||
failwith "Previously injected block."
|
operations >>=? fun operations ->
|
||||||
|
let hashes = List.map (List.map fst) operations in
|
||||||
|
let operations = List.map (List.map snd) operations in
|
||||||
|
let computed_hash =
|
||||||
|
Operation_list_list_hash.compute
|
||||||
|
(List.map Operation_list_hash.compute hashes) in
|
||||||
|
fail_when
|
||||||
|
(Operation_list_list_hash.compare
|
||||||
|
computed_hash block.shell.operations_hash <> 0)
|
||||||
|
(Exn (Failure "Incoherent operation list")) >>=? fun () ->
|
||||||
|
Raw_block_header.Table.inject
|
||||||
|
net_db.block_header_db.table hash block >>= function
|
||||||
| false ->
|
| false ->
|
||||||
let computed_hash =
|
|
||||||
Operation_list_list_hash.compute
|
|
||||||
(List.map Operation_list_hash.compute operations) in
|
|
||||||
fail_unless
|
|
||||||
(Operation_list_list_hash.compare
|
|
||||||
computed_hash block.shell.operations_hash = 0)
|
|
||||||
(Exn (Failure "Incoherent operation list")) >>=? fun () ->
|
|
||||||
Raw_block_header.Table.inject
|
|
||||||
net_db.block_header_db.table hash block >>= function
|
|
||||||
| false ->
|
|
||||||
failwith "Previously injected block."
|
|
||||||
| true ->
|
|
||||||
Operation_list.inject_all
|
|
||||||
net_db hash operations >>= fun _ ->
|
|
||||||
return (hash, block)
|
|
||||||
|
|
||||||
(*
|
|
||||||
let inject_operation t bytes =
|
|
||||||
let hash = Operation_hash.hash_bytes [bytes] in
|
|
||||||
match Data_encoding.Binary.of_bytes Operation.encoding bytes with
|
|
||||||
| None ->
|
|
||||||
failwith "Cannot parse operations."
|
|
||||||
| Some op ->
|
|
||||||
match get_net t op.shell.net_id with
|
|
||||||
| None ->
|
|
||||||
failwith "Unknown network."
|
|
||||||
| Some net_db ->
|
|
||||||
Operation.known net_db hash >>= function
|
|
||||||
| true ->
|
|
||||||
failwith "Previously injected block."
|
failwith "Previously injected block."
|
||||||
| false ->
|
| true ->
|
||||||
Raw_operation.Table.inject
|
Raw_operation_hashes.inject_all
|
||||||
net_db.operation_db.table hash op >>= function
|
net_db.operation_hashes_db.table hash hashes >>= fun _ ->
|
||||||
| false ->
|
Raw_operations.inject_all
|
||||||
failwith "Previously injected block."
|
net_db.operations_db.table hash operations >>= fun _ ->
|
||||||
| true ->
|
return (hash, block)
|
||||||
return (hash, op)
|
|
||||||
*)
|
|
||||||
|
|
||||||
let broadcast_head net head mempool =
|
let remove_block net_db hash n =
|
||||||
|
Raw_operations.remove_all
|
||||||
|
net_db.operations_db.table hash n >>= fun () ->
|
||||||
|
Raw_operation_hashes.remove_all
|
||||||
|
net_db.operation_hashes_db.table hash n >>= fun () ->
|
||||||
|
Raw_block_header.Table.remove net_db.block_header_db.table hash
|
||||||
|
|
||||||
|
let broadcast_head net_db head mempool =
|
||||||
let msg : Message.t =
|
let msg : Message.t =
|
||||||
Current_head (State.Net.id net.net, head, mempool) in
|
Current_head (State.Net.id net_db.net_state, head, mempool) in
|
||||||
P2p.Peer_id.Table.iter
|
P2p.Peer_id.Table.iter
|
||||||
(fun _peer_id state ->
|
(fun _peer_id state ->
|
||||||
ignore (P2p.try_send net.global_db.p2p state.conn msg))
|
ignore (P2p.try_send net_db.global_db.p2p state.conn msg))
|
||||||
net.active_connections
|
net_db.active_connections
|
||||||
|
|
||||||
let read_block { active_nets } hash =
|
let watch_block_header { block_input } =
|
||||||
Net_id.Table.fold
|
|
||||||
(fun _net_id net acc ->
|
|
||||||
acc >>= function
|
|
||||||
| Some _ -> acc
|
|
||||||
| None ->
|
|
||||||
Block_header.read net hash >>= function
|
|
||||||
| None -> acc
|
|
||||||
| Some block -> Lwt.return (Some (net, block)))
|
|
||||||
active_nets
|
|
||||||
Lwt.return_none
|
|
||||||
|
|
||||||
let read_block_exn t hash =
|
|
||||||
read_block t hash >>= function
|
|
||||||
| None -> Lwt.fail Not_found
|
|
||||||
| Some b -> Lwt.return b
|
|
||||||
|
|
||||||
let read_operation { active_nets } hash =
|
|
||||||
Net_id.Table.fold
|
|
||||||
(fun _net_id net acc ->
|
|
||||||
acc >>= function
|
|
||||||
| Some _ -> acc
|
|
||||||
| None ->
|
|
||||||
Operation.read net hash >>= function
|
|
||||||
| None -> acc
|
|
||||||
| Some block -> Lwt.return (Some (net, block)))
|
|
||||||
active_nets
|
|
||||||
Lwt.return_none
|
|
||||||
|
|
||||||
let read_operation_exn t hash =
|
|
||||||
read_operation t hash >>= function
|
|
||||||
| None -> Lwt.fail Not_found
|
|
||||||
| Some b -> Lwt.return b
|
|
||||||
|
|
||||||
let watch_block { block_input } =
|
|
||||||
Watcher.create_stream block_input
|
Watcher.create_stream block_input
|
||||||
let watch_operation { operation_input } =
|
let watch_operation { operation_input } =
|
||||||
Watcher.create_stream operation_input
|
Watcher.create_stream operation_input
|
||||||
@ -725,3 +834,71 @@ module Raw = struct
|
|||||||
let encoding = P2p.Raw.encoding Message.cfg.encoding
|
let encoding = P2p.Raw.encoding Message.cfg.encoding
|
||||||
let supported_versions = Message.cfg.versions
|
let supported_versions = Message.cfg.versions
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module type DISTRIBUTED_DB = sig
|
||||||
|
type t
|
||||||
|
type key
|
||||||
|
type value
|
||||||
|
type param
|
||||||
|
val known: t -> key -> bool Lwt.t
|
||||||
|
type error += Missing_data of key
|
||||||
|
val read: t -> key -> value tzresult Lwt.t
|
||||||
|
val read_opt: t -> key -> value option Lwt.t
|
||||||
|
val read_exn: t -> key -> value Lwt.t
|
||||||
|
val watch: t -> (key * value) Lwt_stream.t * Watcher.stopper
|
||||||
|
val prefetch: t -> ?peer:P2p.Peer_id.t -> key -> param -> unit
|
||||||
|
val fetch: t -> ?peer:P2p.Peer_id.t -> key -> param -> value Lwt.t
|
||||||
|
end
|
||||||
|
|
||||||
|
module Make
|
||||||
|
(Table : Distributed_db_functors.DISTRIBUTED_DB)
|
||||||
|
(Kind : sig
|
||||||
|
type t
|
||||||
|
val proj: t -> Table.t
|
||||||
|
end) = struct
|
||||||
|
type t = Kind.t
|
||||||
|
type key = Table.key
|
||||||
|
type value = Table.value
|
||||||
|
type param = Table.param
|
||||||
|
let known t k = Table.known (Kind.proj t) k
|
||||||
|
type error += Missing_data of key
|
||||||
|
let read t k = Table.read (Kind.proj t) k
|
||||||
|
let read_opt t k = Table.read_opt (Kind.proj t) k
|
||||||
|
let read_exn t k = Table.read_exn (Kind.proj t) k
|
||||||
|
let prefetch t ?peer k p = Table.prefetch (Kind.proj t) ?peer k p
|
||||||
|
let fetch t ?peer k p = Table.fetch (Kind.proj t) ?peer k p
|
||||||
|
let remove t k = Table.remove (Kind.proj t) k
|
||||||
|
let inject t k v = Table.inject (Kind.proj t) k v
|
||||||
|
let watch t = Table.watch (Kind.proj t)
|
||||||
|
end
|
||||||
|
|
||||||
|
module Block_header =
|
||||||
|
Make (Raw_block_header.Table) (struct
|
||||||
|
type t = net_db
|
||||||
|
let proj net = net.block_header_db.table
|
||||||
|
end)
|
||||||
|
|
||||||
|
module Operation_hashes =
|
||||||
|
Make (Raw_operation_hashes.Table) (struct
|
||||||
|
type t = net_db
|
||||||
|
let proj net = net.operation_hashes_db.table
|
||||||
|
end)
|
||||||
|
|
||||||
|
module Operations =
|
||||||
|
Make (Raw_operations.Table) (struct
|
||||||
|
type t = net_db
|
||||||
|
let proj net = net.operations_db.table
|
||||||
|
end)
|
||||||
|
|
||||||
|
module Operation =
|
||||||
|
Make (Raw_operation.Table) (struct
|
||||||
|
type t = net_db
|
||||||
|
let proj net = net.operation_db.table
|
||||||
|
end)
|
||||||
|
|
||||||
|
module Protocol =
|
||||||
|
Make (Raw_protocol.Table) (struct
|
||||||
|
type t = db
|
||||||
|
let proj db = db.protocol_db.table
|
||||||
|
end)
|
||||||
|
|
||||||
|
@ -18,9 +18,9 @@ type p2p = (Message.t, Metadata.t) P2p.net
|
|||||||
val create: State.t -> p2p -> t
|
val create: State.t -> p2p -> t
|
||||||
val shutdown: t -> unit Lwt.t
|
val shutdown: t -> unit Lwt.t
|
||||||
|
|
||||||
type net
|
type net_db
|
||||||
|
|
||||||
val state: net -> State.Net.t
|
val state: net_db -> State.Net.t
|
||||||
|
|
||||||
type callback = {
|
type callback = {
|
||||||
notify_branch: P2p.Peer_id.t -> Block_hash.t list -> unit ;
|
notify_branch: P2p.Peer_id.t -> Block_hash.t list -> unit ;
|
||||||
@ -30,90 +30,90 @@ type callback = {
|
|||||||
disconnection: P2p.Peer_id.t -> unit ;
|
disconnection: P2p.Peer_id.t -> unit ;
|
||||||
}
|
}
|
||||||
|
|
||||||
val activate: callback:callback -> t -> State.Net.t -> net
|
val activate: callback:callback -> t -> State.Net.t -> net_db
|
||||||
val deactivate: net -> unit Lwt.t
|
val deactivate: net_db -> unit Lwt.t
|
||||||
|
|
||||||
|
val broadcast_head:
|
||||||
|
net_db -> Block_hash.t -> Operation_hash.t list -> unit
|
||||||
|
|
||||||
|
type operation =
|
||||||
|
| Blob of Operation.t
|
||||||
|
| Hash of Operation_hash.t
|
||||||
|
|
||||||
|
val resolve_operation:
|
||||||
|
net_db -> operation -> (Operation_hash.t * Operation.t) tzresult Lwt.t
|
||||||
|
|
||||||
|
val commit_block:
|
||||||
|
net_db -> Block_hash.t -> int -> Updater.validation_result ->
|
||||||
|
State.Block.t option tzresult Lwt.t
|
||||||
|
val commit_invalid_block:
|
||||||
|
net_db -> Block_hash.t -> int ->
|
||||||
|
bool tzresult Lwt.t
|
||||||
|
val inject_block:
|
||||||
|
t -> MBytes.t -> operation list list ->
|
||||||
|
(Block_hash.t * Block_header.t) tzresult Lwt.t
|
||||||
|
val remove_block: net_db -> Block_hash.t -> int -> unit Lwt.t
|
||||||
|
|
||||||
|
val inject_operation:
|
||||||
|
net_db -> Operation_hash.t -> Operation.t -> bool tzresult Lwt.t
|
||||||
|
|
||||||
|
val commit_protocol:
|
||||||
|
db -> Protocol_hash.t -> bool tzresult Lwt.t
|
||||||
|
val inject_protocol:
|
||||||
|
db -> Protocol_hash.t -> Protocol.t -> bool Lwt.t
|
||||||
|
|
||||||
|
val watch_block_header:
|
||||||
|
t -> (Block_hash.t * Block_header.t) Lwt_stream.t * Watcher.stopper
|
||||||
|
val watch_operation:
|
||||||
|
t -> (Operation_hash.t * Operation.t) Lwt_stream.t * Watcher.stopper
|
||||||
|
val watch_protocol:
|
||||||
|
t -> (Protocol_hash.t * Protocol.t) Lwt_stream.t * Watcher.stopper
|
||||||
|
|
||||||
|
|
||||||
module type DISTRIBUTED_DB = sig
|
module type DISTRIBUTED_DB = sig
|
||||||
type t
|
type t
|
||||||
type key
|
type key
|
||||||
type value
|
type value
|
||||||
|
type param
|
||||||
val known: t -> key -> bool Lwt.t
|
val known: t -> key -> bool Lwt.t
|
||||||
val read: t -> key -> value option Lwt.t
|
type error += Missing_data of key
|
||||||
|
val read: t -> key -> value tzresult Lwt.t
|
||||||
|
val read_opt: t -> key -> value option Lwt.t
|
||||||
val read_exn: t -> key -> value Lwt.t
|
val read_exn: t -> key -> value Lwt.t
|
||||||
val commit: t -> key -> unit Lwt.t
|
|
||||||
val inject: t -> key -> value -> bool Lwt.t
|
|
||||||
val watch: t -> (key * value) Lwt_stream.t * Watcher.stopper
|
val watch: t -> (key * value) Lwt_stream.t * Watcher.stopper
|
||||||
val prefetch: t -> ?peer:P2p.Peer_id.t -> key -> unit
|
val prefetch: t -> ?peer:P2p.Peer_id.t -> key -> param -> unit
|
||||||
val fetch: t -> ?peer:P2p.Peer_id.t -> key -> value Lwt.t
|
val fetch: t -> ?peer:P2p.Peer_id.t -> key -> param -> value Lwt.t
|
||||||
end
|
end
|
||||||
|
|
||||||
module Operation :
|
|
||||||
DISTRIBUTED_DB with type t = net
|
|
||||||
and type key := Operation_hash.t
|
|
||||||
and type value := Operation.t
|
|
||||||
|
|
||||||
module Block_header :
|
module Block_header :
|
||||||
DISTRIBUTED_DB with type t = net
|
DISTRIBUTED_DB with type t = net_db
|
||||||
and type key := Block_hash.t
|
and type key := Block_hash.t
|
||||||
and type value := Block_header.t
|
and type value := Block_header.t
|
||||||
|
and type param := unit
|
||||||
|
|
||||||
|
module Operations :
|
||||||
|
DISTRIBUTED_DB with type t = net_db
|
||||||
|
and type key = Block_hash.t * int
|
||||||
|
and type value = Operation.t list
|
||||||
|
and type param := Operation_list_list_hash.t
|
||||||
|
|
||||||
|
module Operation_hashes :
|
||||||
|
DISTRIBUTED_DB with type t = net_db
|
||||||
|
and type key = Block_hash.t * int
|
||||||
|
and type value = Operation_hash.t list
|
||||||
|
and type param := Operation_list_list_hash.t
|
||||||
|
|
||||||
|
module Operation :
|
||||||
|
DISTRIBUTED_DB with type t = net_db
|
||||||
|
and type key := Operation_hash.t
|
||||||
|
and type value := Operation.t
|
||||||
|
and type param := unit
|
||||||
|
|
||||||
module Protocol :
|
module Protocol :
|
||||||
DISTRIBUTED_DB with type t = db
|
DISTRIBUTED_DB with type t = db
|
||||||
and type key := Protocol_hash.t
|
and type key := Protocol_hash.t
|
||||||
and type value := Protocol.t
|
and type value := Protocol.t
|
||||||
|
and type param := unit
|
||||||
module Operation_list : sig
|
|
||||||
|
|
||||||
type t = net
|
|
||||||
type key = Block_hash.t * int
|
|
||||||
type value = Operation_hash.t list
|
|
||||||
type param = Operation_list_list_hash.t
|
|
||||||
|
|
||||||
val known: t -> key -> bool Lwt.t
|
|
||||||
val read: t -> key -> value option Lwt.t
|
|
||||||
val read_exn: t -> key -> value Lwt.t
|
|
||||||
val prefetch: t -> ?peer:P2p.Peer_id.t -> key -> param -> unit
|
|
||||||
val fetch: t -> ?peer:P2p.Peer_id.t -> key -> param -> value Lwt.t
|
|
||||||
|
|
||||||
val read_all_opt:
|
|
||||||
net -> Block_hash.t -> Operation_hash.t list list option Lwt.t
|
|
||||||
val read_all_exn:
|
|
||||||
net -> Block_hash.t -> Operation_hash.t list list Lwt.t
|
|
||||||
|
|
||||||
val commit_all:
|
|
||||||
net -> Block_hash.t -> int -> unit Lwt.t
|
|
||||||
val inject_all:
|
|
||||||
net -> Block_hash.t -> Operation_hash.t list list -> bool Lwt.t
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
val broadcast_head:
|
|
||||||
net -> Block_hash.t -> Operation_hash.t list -> unit
|
|
||||||
|
|
||||||
val inject_block:
|
|
||||||
t -> MBytes.t -> Operation_hash.t list list ->
|
|
||||||
(Block_hash.t * Tezos_data.Block_header.t) tzresult Lwt.t
|
|
||||||
|
|
||||||
(* val inject_operation: *)
|
|
||||||
(* t -> MBytes.t -> *)
|
|
||||||
(* (Block_hash.t * Operation.t) tzresult Lwt.t *)
|
|
||||||
|
|
||||||
val read_block:
|
|
||||||
t -> Block_hash.t -> (net * Tezos_data.Block_header.t) option Lwt.t
|
|
||||||
val read_block_exn:
|
|
||||||
t -> Block_hash.t -> (net * Tezos_data.Block_header.t) Lwt.t
|
|
||||||
|
|
||||||
val read_operation:
|
|
||||||
t -> Operation_hash.t -> (net * Tezos_data.Operation.t) option Lwt.t
|
|
||||||
val read_operation_exn:
|
|
||||||
t -> Operation_hash.t -> (net * Tezos_data.Operation.t) Lwt.t
|
|
||||||
|
|
||||||
val watch_block:
|
|
||||||
t -> (Block_hash.t * Tezos_data.Block_header.t) Lwt_stream.t * Watcher.stopper
|
|
||||||
val watch_operation:
|
|
||||||
t -> (Operation_hash.t * Tezos_data.Operation.t) Lwt_stream.t * Watcher.stopper
|
|
||||||
val watch_protocol:
|
|
||||||
t -> (Protocol_hash.t * Tezos_data.Protocol.t) Lwt_stream.t * Watcher.stopper
|
|
||||||
|
|
||||||
module Raw : sig
|
module Raw : sig
|
||||||
val encoding: Message.t P2p.Raw.t Data_encoding.t
|
val encoding: Message.t P2p.Raw.t Data_encoding.t
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
(* *)
|
(* *)
|
||||||
(**************************************************************************)
|
(**************************************************************************)
|
||||||
|
|
||||||
module type PARAMETRIZED_RO_DISTRIBUTED_DB = sig
|
module type DISTRIBUTED_DB = sig
|
||||||
|
|
||||||
type t
|
type t
|
||||||
type key
|
type key
|
||||||
@ -15,34 +15,21 @@ module type PARAMETRIZED_RO_DISTRIBUTED_DB = sig
|
|||||||
type param
|
type param
|
||||||
|
|
||||||
val known: t -> key -> bool Lwt.t
|
val known: t -> key -> bool Lwt.t
|
||||||
val read: t -> key -> value option Lwt.t
|
|
||||||
|
type error += Missing_data of key
|
||||||
|
val read: t -> key -> value tzresult Lwt.t
|
||||||
|
val read_opt: t -> key -> value option Lwt.t
|
||||||
val read_exn: t -> key -> value Lwt.t
|
val read_exn: t -> key -> value Lwt.t
|
||||||
|
|
||||||
val prefetch: t -> ?peer:P2p.Peer_id.t -> key -> param -> unit
|
val prefetch: t -> ?peer:P2p.Peer_id.t -> key -> param -> unit
|
||||||
val fetch: t -> ?peer:P2p.Peer_id.t -> key -> param -> value Lwt.t
|
val fetch: t -> ?peer:P2p.Peer_id.t -> key -> param -> value Lwt.t
|
||||||
|
|
||||||
end
|
val remove: t -> key -> unit Lwt.t
|
||||||
|
|
||||||
module type PARAMETRIZED_DISTRIBUTED_DB = sig
|
|
||||||
|
|
||||||
include PARAMETRIZED_RO_DISTRIBUTED_DB
|
|
||||||
|
|
||||||
val commit: t -> key -> unit Lwt.t
|
|
||||||
(* val commit_invalid: t -> key -> unit Lwt.t *) (* TODO *)
|
|
||||||
val inject: t -> key -> value -> bool Lwt.t
|
val inject: t -> key -> value -> bool Lwt.t
|
||||||
val watch: t -> (key * value) Lwt_stream.t * Watcher.stopper
|
val watch: t -> (key * value) Lwt_stream.t * Watcher.stopper
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module type DISTRIBUTED_DB = sig
|
|
||||||
|
|
||||||
include PARAMETRIZED_DISTRIBUTED_DB with type param := unit
|
|
||||||
|
|
||||||
val prefetch: t -> ?peer:P2p.Peer_id.t -> key -> unit
|
|
||||||
val fetch: t -> ?peer:P2p.Peer_id.t -> key -> value Lwt.t
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
module type DISK_TABLE = sig
|
module type DISK_TABLE = sig
|
||||||
type store
|
type store
|
||||||
type key
|
type key
|
||||||
@ -51,8 +38,6 @@ module type DISK_TABLE = sig
|
|||||||
val read: store -> key -> value tzresult Lwt.t
|
val read: store -> key -> value tzresult Lwt.t
|
||||||
val read_opt: store -> key -> value option Lwt.t
|
val read_opt: store -> key -> value option Lwt.t
|
||||||
val read_exn: store -> key -> value Lwt.t
|
val read_exn: store -> key -> value Lwt.t
|
||||||
val store: store -> key -> value -> bool Lwt.t
|
|
||||||
val remove: store -> key -> bool Lwt.t
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module type MEMORY_TABLE = sig
|
module type MEMORY_TABLE = sig
|
||||||
@ -79,8 +64,9 @@ end
|
|||||||
module type PRECHECK = sig
|
module type PRECHECK = sig
|
||||||
type key
|
type key
|
||||||
type param
|
type param
|
||||||
|
type notified_value
|
||||||
type value
|
type value
|
||||||
val precheck: key -> param -> value -> bool
|
val precheck: key -> param -> notified_value -> value option
|
||||||
end
|
end
|
||||||
|
|
||||||
module Make_table
|
module Make_table
|
||||||
@ -91,13 +77,13 @@ module Make_table
|
|||||||
(Precheck : PRECHECK with type key := Hash.t
|
(Precheck : PRECHECK with type key := Hash.t
|
||||||
and type value := Disk_table.value) : sig
|
and type value := Disk_table.value) : sig
|
||||||
|
|
||||||
include PARAMETRIZED_DISTRIBUTED_DB with type key = Hash.t
|
include DISTRIBUTED_DB with type key = Hash.t
|
||||||
and type value = Disk_table.value
|
and type value = Disk_table.value
|
||||||
and type param = Precheck.param
|
and type param = Precheck.param
|
||||||
val create:
|
val create:
|
||||||
?global_input:(key * value) Watcher.input ->
|
?global_input:(key * value) Watcher.input ->
|
||||||
Scheduler.t -> Disk_table.store -> t
|
Scheduler.t -> Disk_table.store -> t
|
||||||
val notify: t -> P2p.Peer_id.t -> key -> value -> unit Lwt.t
|
val notify: t -> P2p.Peer_id.t -> key -> Precheck.notified_value -> unit Lwt.t
|
||||||
|
|
||||||
end = struct
|
end = struct
|
||||||
|
|
||||||
@ -123,7 +109,7 @@ end = struct
|
|||||||
| Pending _ -> Lwt.return_false
|
| Pending _ -> Lwt.return_false
|
||||||
| Found _ -> Lwt.return_true
|
| Found _ -> Lwt.return_true
|
||||||
|
|
||||||
let read s k =
|
let read_opt s k =
|
||||||
match Memory_table.find s.memory k with
|
match Memory_table.find s.memory k with
|
||||||
| exception Not_found -> Disk_table.read_opt s.disk k
|
| exception Not_found -> Disk_table.read_opt s.disk k
|
||||||
| Found v -> Lwt.return (Some v)
|
| Found v -> Lwt.return (Some v)
|
||||||
@ -135,6 +121,16 @@ end = struct
|
|||||||
| Found v -> Lwt.return v
|
| Found v -> Lwt.return v
|
||||||
| Pending _ -> Lwt.fail Not_found
|
| Pending _ -> Lwt.fail Not_found
|
||||||
|
|
||||||
|
type error += Missing_data of key
|
||||||
|
|
||||||
|
let read s k =
|
||||||
|
match Memory_table.find s.memory k with
|
||||||
|
| exception Not_found ->
|
||||||
|
trace (Missing_data k) @@
|
||||||
|
Disk_table.read s.disk k
|
||||||
|
| Found v -> return v
|
||||||
|
| Pending _ -> fail (Missing_data k)
|
||||||
|
|
||||||
let fetch s ?peer k param =
|
let fetch s ?peer k param =
|
||||||
match Memory_table.find s.memory k with
|
match Memory_table.find s.memory k with
|
||||||
| exception Not_found -> begin
|
| exception Not_found -> begin
|
||||||
@ -162,18 +158,19 @@ end = struct
|
|||||||
Scheduler.notify_unrequested s.scheduler p k ;
|
Scheduler.notify_unrequested s.scheduler p k ;
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
end
|
end
|
||||||
| Pending (w, param) ->
|
| Pending (w, param) -> begin
|
||||||
if not (Precheck.precheck k param v) then begin
|
match Precheck.precheck k param v with
|
||||||
Scheduler.notify_invalid s.scheduler p k ;
|
| None ->
|
||||||
Lwt.return_unit
|
Scheduler.notify_invalid s.scheduler p k ;
|
||||||
end else begin
|
Lwt.return_unit
|
||||||
Scheduler.notify s.scheduler p k ;
|
| Some v ->
|
||||||
Memory_table.replace s.memory k (Found v) ;
|
Scheduler.notify s.scheduler p k ;
|
||||||
Lwt.wakeup w v ;
|
Memory_table.replace s.memory k (Found v) ;
|
||||||
iter_option s.global_input
|
Lwt.wakeup w v ;
|
||||||
~f:(fun input -> Watcher.notify input (k, v)) ;
|
iter_option s.global_input
|
||||||
Watcher.notify s.input (k, v) ;
|
~f:(fun input -> Watcher.notify input (k, v)) ;
|
||||||
Lwt.return_unit
|
Watcher.notify s.input (k, v) ;
|
||||||
|
Lwt.return_unit
|
||||||
end
|
end
|
||||||
| Found _ ->
|
| Found _ ->
|
||||||
Scheduler.notify_duplicate s.scheduler p k ;
|
Scheduler.notify_duplicate s.scheduler p k ;
|
||||||
@ -193,12 +190,11 @@ end = struct
|
|||||||
| Found _ ->
|
| Found _ ->
|
||||||
Lwt.return_false
|
Lwt.return_false
|
||||||
|
|
||||||
let commit s k =
|
let remove s k =
|
||||||
match Memory_table.find s.memory k with
|
match Memory_table.find s.memory k with
|
||||||
| exception Not_found -> Lwt.return_unit
|
| exception Not_found -> Lwt.return_unit
|
||||||
| Pending _ -> assert false
|
| Pending _ -> assert false
|
||||||
| Found v ->
|
| Found _ ->
|
||||||
Disk_table.store s.disk k v >>= fun _ ->
|
|
||||||
Memory_table.remove s.memory k ;
|
Memory_table.remove s.memory k ;
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
(* *)
|
(* *)
|
||||||
(**************************************************************************)
|
(**************************************************************************)
|
||||||
|
|
||||||
module type PARAMETRIZED_RO_DISTRIBUTED_DB = sig
|
module type DISTRIBUTED_DB = sig
|
||||||
|
|
||||||
type t
|
type t
|
||||||
type key
|
type key
|
||||||
@ -15,36 +15,22 @@ module type PARAMETRIZED_RO_DISTRIBUTED_DB = sig
|
|||||||
type param
|
type param
|
||||||
|
|
||||||
val known: t -> key -> bool Lwt.t
|
val known: t -> key -> bool Lwt.t
|
||||||
val read: t -> key -> value option Lwt.t
|
|
||||||
|
type error += Missing_data of key
|
||||||
|
val read: t -> key -> value tzresult Lwt.t
|
||||||
|
val read_opt: t -> key -> value option Lwt.t
|
||||||
val read_exn: t -> key -> value Lwt.t
|
val read_exn: t -> key -> value Lwt.t
|
||||||
|
|
||||||
val prefetch: t -> ?peer:P2p.Peer_id.t -> key -> param -> unit
|
val prefetch: t -> ?peer:P2p.Peer_id.t -> key -> param -> unit
|
||||||
val fetch: t -> ?peer:P2p.Peer_id.t -> key -> param -> value Lwt.t
|
val fetch: t -> ?peer:P2p.Peer_id.t -> key -> param -> value Lwt.t
|
||||||
|
|
||||||
end
|
val remove: t -> key -> unit Lwt.t
|
||||||
|
|
||||||
module type PARAMETRIZED_DISTRIBUTED_DB = sig
|
|
||||||
|
|
||||||
include PARAMETRIZED_RO_DISTRIBUTED_DB
|
|
||||||
|
|
||||||
val commit: t -> key -> unit Lwt.t
|
|
||||||
(* val commit_invalid: t -> key -> unit Lwt.t *) (* TODO *)
|
|
||||||
val inject: t -> key -> value -> bool Lwt.t
|
val inject: t -> key -> value -> bool Lwt.t
|
||||||
val watch: t -> (key * value) Lwt_stream.t * Watcher.stopper
|
val watch: t -> (key * value) Lwt_stream.t * Watcher.stopper
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module type DISTRIBUTED_DB = sig
|
|
||||||
|
|
||||||
include PARAMETRIZED_DISTRIBUTED_DB with type param := unit
|
|
||||||
|
|
||||||
val prefetch: t -> ?peer:P2p.Peer_id.t -> key -> unit
|
|
||||||
val fetch: t -> ?peer:P2p.Peer_id.t -> key -> value Lwt.t
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
module type DISK_TABLE = sig
|
module type DISK_TABLE = sig
|
||||||
(* A subtype of State.DATA_STORE *)
|
|
||||||
type store
|
type store
|
||||||
type key
|
type key
|
||||||
type value
|
type value
|
||||||
@ -52,8 +38,6 @@ module type DISK_TABLE = sig
|
|||||||
val read: store -> key -> value tzresult Lwt.t
|
val read: store -> key -> value tzresult Lwt.t
|
||||||
val read_opt: store -> key -> value option Lwt.t
|
val read_opt: store -> key -> value option Lwt.t
|
||||||
val read_exn: store -> key -> value Lwt.t
|
val read_exn: store -> key -> value Lwt.t
|
||||||
val store: store -> key -> value -> bool Lwt.t
|
|
||||||
val remove: store -> key -> bool Lwt.t
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module type MEMORY_TABLE = sig
|
module type MEMORY_TABLE = sig
|
||||||
@ -81,8 +65,9 @@ end
|
|||||||
module type PRECHECK = sig
|
module type PRECHECK = sig
|
||||||
type key
|
type key
|
||||||
type param
|
type param
|
||||||
|
type notified_value
|
||||||
type value
|
type value
|
||||||
val precheck: key -> param -> value -> bool
|
val precheck: key -> param -> notified_value -> value option
|
||||||
end
|
end
|
||||||
|
|
||||||
module Make_table
|
module Make_table
|
||||||
@ -93,13 +78,13 @@ module Make_table
|
|||||||
(Precheck : PRECHECK with type key := Hash.t
|
(Precheck : PRECHECK with type key := Hash.t
|
||||||
and type value := Disk_table.value) : sig
|
and type value := Disk_table.value) : sig
|
||||||
|
|
||||||
include PARAMETRIZED_DISTRIBUTED_DB with type key = Hash.t
|
include DISTRIBUTED_DB with type key = Hash.t
|
||||||
and type value = Disk_table.value
|
and type value = Disk_table.value
|
||||||
and type param := Precheck.param
|
and type param = Precheck.param
|
||||||
val create:
|
val create:
|
||||||
?global_input:(key * value) Watcher.input ->
|
?global_input:(key * value) Watcher.input ->
|
||||||
Scheduler.t -> Disk_table.store -> t
|
Scheduler.t -> Disk_table.store -> t
|
||||||
val notify: t -> P2p.Peer_id.t -> key -> value -> unit Lwt.t
|
val notify: t -> P2p.Peer_id.t -> key -> Precheck.notified_value -> unit Lwt.t
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -25,9 +25,15 @@ type t =
|
|||||||
| Get_protocols of Protocol_hash.t list
|
| Get_protocols of Protocol_hash.t list
|
||||||
| Protocol of Protocol.t
|
| Protocol of Protocol.t
|
||||||
|
|
||||||
| Get_operation_list of Net_id.t * (Block_hash.t * int) list
|
| Get_operation_hashes_for_blocks of Net_id.t * (Block_hash.t * int) list
|
||||||
| Operation_list of Net_id.t * Block_hash.t * int *
|
| Operation_hashes_for_block of
|
||||||
Operation_hash.t list * Operation_list_list_hash.path
|
Net_id.t * Block_hash.t * int *
|
||||||
|
Operation_hash.t list * Operation_list_list_hash.path
|
||||||
|
|
||||||
|
| Get_operations_for_blocks of Net_id.t * (Block_hash.t * int) list
|
||||||
|
| Operations_for_block of
|
||||||
|
Net_id.t * Block_hash.t * int *
|
||||||
|
Operation.t list * Operation_list_list_hash.path
|
||||||
|
|
||||||
let encoding =
|
let encoding =
|
||||||
let open Data_encoding in
|
let open Data_encoding in
|
||||||
@ -123,22 +129,44 @@ let encoding =
|
|||||||
case ~tag:0x50
|
case ~tag:0x50
|
||||||
(obj2
|
(obj2
|
||||||
(req "net_id" Net_id.encoding)
|
(req "net_id" Net_id.encoding)
|
||||||
(req "get_operation_list" (list (tup2 Block_hash.encoding int8))))
|
(req "get_operation_hashes_for_blocks"
|
||||||
|
(list (tup2 Block_hash.encoding int8))))
|
||||||
(function
|
(function
|
||||||
| Get_operation_list (net_id, keys) -> Some (net_id, keys)
|
| Get_operation_hashes_for_blocks (net_id, keys) -> Some (net_id, keys)
|
||||||
| _ -> None)
|
| _ -> None)
|
||||||
(fun (net_id, keys) -> Get_operation_list (net_id, keys));
|
(fun (net_id, keys) -> Get_operation_hashes_for_blocks (net_id, keys));
|
||||||
|
|
||||||
case ~tag:0x51
|
case ~tag:0x51
|
||||||
(obj4
|
(obj4
|
||||||
(req "net_id" Net_id.encoding)
|
(req "net_id" Net_id.encoding)
|
||||||
(req "operation_list" (tup2 Block_hash.encoding int8))
|
(req "operation_hashes_for_block" (tup2 Block_hash.encoding int8))
|
||||||
(req "operations" (list Operation_hash.encoding))
|
(req "operation_hashes" (list Operation_hash.encoding))
|
||||||
(req "operation_list_path" Operation_list_list_hash.path_encoding))
|
(req "operation_hashes_path" Operation_list_list_hash.path_encoding))
|
||||||
(function Operation_list (net_id, block, ofs, ops, path) ->
|
(function Operation_hashes_for_block (net_id, block, ofs, ops, path) ->
|
||||||
Some (net_id, (block, ofs), ops, path) | _ -> None)
|
Some (net_id, (block, ofs), ops, path) | _ -> None)
|
||||||
(fun (net_id, (block, ofs), ops, path) ->
|
(fun (net_id, (block, ofs), ops, path) ->
|
||||||
Operation_list (net_id, block, ofs, ops, path)) ;
|
Operation_hashes_for_block (net_id, block, ofs, ops, path)) ;
|
||||||
|
|
||||||
|
case ~tag:0x60
|
||||||
|
(obj2
|
||||||
|
(req "net_id" Net_id.encoding)
|
||||||
|
(req "get_operations_for_blocks"
|
||||||
|
(list (tup2 Block_hash.encoding int8))))
|
||||||
|
(function
|
||||||
|
| Get_operations_for_blocks (net_id, keys) -> Some (net_id, keys)
|
||||||
|
| _ -> None)
|
||||||
|
(fun (net_id, keys) -> Get_operations_for_blocks (net_id, keys));
|
||||||
|
|
||||||
|
case ~tag:0x61
|
||||||
|
(obj4
|
||||||
|
(req "net_id" Net_id.encoding)
|
||||||
|
(req "operations_for_block" (tup2 Block_hash.encoding int8))
|
||||||
|
(req "operations" (list (dynamic_size Operation.encoding)))
|
||||||
|
(req "operations_path" Operation_list_list_hash.path_encoding))
|
||||||
|
(function Operations_for_block (net_id, block, ofs, ops, path) ->
|
||||||
|
Some (net_id, (block, ofs), ops, path) | _ -> None)
|
||||||
|
(fun (net_id, (block, ofs), ops, path) ->
|
||||||
|
Operations_for_block (net_id, block, ofs, ops, path)) ;
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -146,7 +174,7 @@ let versions =
|
|||||||
let open P2p.Version in
|
let open P2p.Version in
|
||||||
[ { name = "TEZOS" ;
|
[ { name = "TEZOS" ;
|
||||||
major = 0 ;
|
major = 0 ;
|
||||||
minor = 5 ;
|
minor = 6 ;
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -25,9 +25,15 @@ type t =
|
|||||||
| Get_protocols of Protocol_hash.t list
|
| Get_protocols of Protocol_hash.t list
|
||||||
| Protocol of Protocol.t
|
| Protocol of Protocol.t
|
||||||
|
|
||||||
| Get_operation_list of Net_id.t * (Block_hash.t * int) list
|
| Get_operation_hashes_for_blocks of Net_id.t * (Block_hash.t * int) list
|
||||||
| Operation_list of Net_id.t * Block_hash.t * int *
|
| Operation_hashes_for_block of
|
||||||
Operation_hash.t list * Operation_list_list_hash.path
|
Net_id.t * Block_hash.t * int *
|
||||||
|
Operation_hash.t list * Operation_list_list_hash.path
|
||||||
|
|
||||||
|
| Get_operations_for_blocks of Net_id.t * (Block_hash.t * int) list
|
||||||
|
| Operations_for_block of
|
||||||
|
Net_id.t * Block_hash.t * int *
|
||||||
|
Operation.t list * Operation_list_list_hash.path
|
||||||
|
|
||||||
val cfg : t P2p.message_config
|
val cfg : t P2p.message_config
|
||||||
|
|
||||||
|
@ -33,12 +33,12 @@ let inject_protocol state ?force:_ proto =
|
|||||||
"Compilation failed (%a)"
|
"Compilation failed (%a)"
|
||||||
Protocol_hash.pp_short hash
|
Protocol_hash.pp_short hash
|
||||||
| true ->
|
| true ->
|
||||||
State.Protocol.store state hash proto >>= function
|
State.Protocol.store state proto >>= function
|
||||||
| false ->
|
| None ->
|
||||||
failwith
|
failwith
|
||||||
"Previously registred protocol (%a)"
|
"Previously registred protocol (%a)"
|
||||||
Protocol_hash.pp_short hash
|
Protocol_hash.pp_short hash
|
||||||
| true -> return ()
|
| Some _ -> return ()
|
||||||
in
|
in
|
||||||
Lwt.return (hash, validation)
|
Lwt.return (hash, validation)
|
||||||
|
|
||||||
@ -52,12 +52,12 @@ type t = {
|
|||||||
state: State.t ;
|
state: State.t ;
|
||||||
distributed_db: Distributed_db.t ;
|
distributed_db: Distributed_db.t ;
|
||||||
validator: Validator.worker ;
|
validator: Validator.worker ;
|
||||||
mainnet_db: Distributed_db.net ;
|
mainnet_db: Distributed_db.net_db ;
|
||||||
mainnet_net: State.Net.t ;
|
mainnet_net: State.Net.t ;
|
||||||
mainnet_validator: Validator.t ;
|
mainnet_validator: Validator.t ;
|
||||||
inject_block:
|
inject_block:
|
||||||
?force:bool ->
|
?force:bool ->
|
||||||
MBytes.t -> Operation_hash.t list list ->
|
MBytes.t -> Distributed_db.operation list list ->
|
||||||
(Block_hash.t * unit tzresult Lwt.t) tzresult Lwt.t ;
|
(Block_hash.t * unit tzresult Lwt.t) tzresult Lwt.t ;
|
||||||
inject_operation:
|
inject_operation:
|
||||||
?force:bool -> MBytes.t ->
|
?force:bool -> MBytes.t ->
|
||||||
@ -151,21 +151,26 @@ module RPC = struct
|
|||||||
test_network: Context.test_network;
|
test_network: Context.test_network;
|
||||||
}
|
}
|
||||||
|
|
||||||
let convert (block: State.Valid_block.t) =
|
let convert (block: State.Block.t) =
|
||||||
Lazy.force block.operation_hashes >>= fun operations ->
|
let hash = State.Block.hash block in
|
||||||
|
let header = State.Block.header block in
|
||||||
|
State.Block.all_operation_hashes block >>= fun operations ->
|
||||||
|
State.Block.context block >>= fun context ->
|
||||||
|
Context.get_protocol context >>= fun protocol ->
|
||||||
|
Context.get_test_network context >>= fun test_network ->
|
||||||
Lwt.return {
|
Lwt.return {
|
||||||
hash = block.hash ;
|
hash ;
|
||||||
net_id = block.net_id ;
|
net_id = header.shell.net_id ;
|
||||||
level = block.level ;
|
level = header.shell.level ;
|
||||||
proto_level = block.proto_level ;
|
proto_level = header.shell.proto_level ;
|
||||||
predecessor = block.predecessor ;
|
predecessor = header.shell.predecessor ;
|
||||||
timestamp = block.timestamp ;
|
timestamp = header.shell.timestamp ;
|
||||||
operations_hash = block.operations_hash ;
|
operations_hash = header.shell.operations_hash ;
|
||||||
fitness = block.fitness ;
|
fitness = header.shell.fitness ;
|
||||||
data = block.proto_header ;
|
data = header.proto ;
|
||||||
operations = Some operations ;
|
operations = Some operations ;
|
||||||
protocol = block.protocol_hash ;
|
protocol ;
|
||||||
test_network = block.test_network ;
|
test_network ;
|
||||||
}
|
}
|
||||||
|
|
||||||
let inject_block node = node.inject_block
|
let inject_block node = node.inject_block
|
||||||
@ -173,10 +178,8 @@ module RPC = struct
|
|||||||
let inject_protocol node = node.inject_protocol
|
let inject_protocol node = node.inject_protocol
|
||||||
|
|
||||||
let raw_block_info node hash =
|
let raw_block_info node hash =
|
||||||
Distributed_db.read_block node.distributed_db hash >>= function
|
State.read_block node.state hash >>= function
|
||||||
| Some (net_db, _block) ->
|
| Some block ->
|
||||||
let net = Distributed_db.state net_db in
|
|
||||||
State.Valid_block.read_exn net hash >>= fun block ->
|
|
||||||
convert block
|
convert block
|
||||||
| None ->
|
| None ->
|
||||||
Lwt.fail Not_found
|
Lwt.fail Not_found
|
||||||
@ -201,89 +204,74 @@ module RPC = struct
|
|||||||
| Some (v, _) -> v
|
| Some (v, _) -> v
|
||||||
|
|
||||||
let get_validator_per_hash node hash =
|
let get_validator_per_hash node hash =
|
||||||
Distributed_db.read_block_exn
|
State.read_block_exn node.state hash >>= fun block ->
|
||||||
node.distributed_db hash >>= fun (_net_db, block) ->
|
let header = State.Block.header block in
|
||||||
if Net_id.equal
|
if Net_id.equal
|
||||||
(State.Net.id node.mainnet_net)
|
(State.Net.id node.mainnet_net)
|
||||||
block.shell.net_id then
|
header.shell.net_id then
|
||||||
Lwt.return (Some (node.mainnet_validator, node.mainnet_db))
|
Lwt.return (Some (node.mainnet_validator, node.mainnet_db))
|
||||||
else
|
else
|
||||||
match Validator.test_validator node.mainnet_validator with
|
match Validator.test_validator node.mainnet_validator with
|
||||||
| Some (test_validator, net_db)
|
| Some (test_validator, net_db)
|
||||||
when Net_id.equal
|
when Net_id.equal
|
||||||
(State.Net.id (Validator.net_state test_validator))
|
(State.Net.id (Validator.net_state test_validator))
|
||||||
block.shell.net_id ->
|
header.shell.net_id ->
|
||||||
Lwt.return (Some (node.mainnet_validator, net_db))
|
Lwt.return (Some (node.mainnet_validator, net_db))
|
||||||
| _ -> Lwt.return_none
|
| _ -> Lwt.return_none
|
||||||
|
|
||||||
let read_valid_block node h =
|
let read_valid_block node h =
|
||||||
Distributed_db.read_block node.distributed_db h >>= function
|
State.read_block node.state h
|
||||||
| None -> Lwt.return_none
|
|
||||||
| Some (_net_db, block) ->
|
|
||||||
State.Net.get node.state block.shell.net_id >>= function
|
|
||||||
| Error _ -> Lwt.return_none
|
|
||||||
| Ok net ->
|
|
||||||
State.Valid_block.read_exn net h >>= fun block ->
|
|
||||||
Lwt.return (Some block)
|
|
||||||
|
|
||||||
let read_valid_block_exn node h =
|
let read_valid_block_exn node h =
|
||||||
Distributed_db.read_block_exn
|
State.read_block_exn node.state h
|
||||||
node.distributed_db h >>= fun (net_db, _block) ->
|
|
||||||
let net = Distributed_db.state net_db in
|
|
||||||
State.Valid_block.read_exn net h >>= fun block ->
|
|
||||||
Lwt.return block
|
|
||||||
|
|
||||||
let get_pred net_db n (v: State.Valid_block.t) =
|
let rec predecessor net_db n v =
|
||||||
let rec loop net_db n h =
|
|
||||||
if n <= 0 then
|
|
||||||
Lwt.return h
|
|
||||||
else
|
|
||||||
Distributed_db.Block_header.read net_db h >>= function
|
|
||||||
| None -> Lwt.fail Not_found
|
|
||||||
| Some { shell = { predecessor } } ->
|
|
||||||
loop net_db (n-1) predecessor in
|
|
||||||
if n <= 0 then
|
if n <= 0 then
|
||||||
Lwt.return v
|
Lwt.return v
|
||||||
else
|
else
|
||||||
loop net_db n v.hash >>= fun hash ->
|
State.Block.predecessor v >>= function
|
||||||
let net_state = Distributed_db.state net_db in
|
| None -> Lwt.fail Not_found
|
||||||
State.Valid_block.read_exn net_state hash
|
| Some v -> predecessor net_db (n-1) v
|
||||||
|
|
||||||
let block_info node (block: block) =
|
let block_info node (block: block) =
|
||||||
match block with
|
match block with
|
||||||
| `Genesis ->
|
| `Genesis ->
|
||||||
State.Valid_block.Current.genesis node.mainnet_net >>= convert
|
Chain.genesis node.mainnet_net >>= convert
|
||||||
| ( `Head n | `Test_head n ) as block ->
|
| ( `Head n | `Test_head n ) as block ->
|
||||||
let validator = get_validator node block in
|
let validator = get_validator node block in
|
||||||
let net_db = Validator.net_db validator in
|
let net_db = Validator.net_db validator in
|
||||||
let net_state = Validator.net_state validator in
|
let net_state = Validator.net_state validator in
|
||||||
State.Valid_block.Current.head net_state >>= fun head ->
|
Chain.head net_state >>= fun head ->
|
||||||
get_pred net_db n head >>= convert
|
predecessor net_db n head >>= convert
|
||||||
| `Hash h ->
|
| `Hash h ->
|
||||||
read_valid_block_exn node h >>= convert
|
read_valid_block_exn node h >>= convert
|
||||||
| ( `Prevalidation | `Test_prevalidation ) as block ->
|
| ( `Prevalidation | `Test_prevalidation ) as block ->
|
||||||
let validator = get_validator node block in
|
let validator = get_validator node block in
|
||||||
let pv = Validator.prevalidator validator in
|
let pv = Validator.prevalidator validator in
|
||||||
let net_state = Validator.net_state validator in
|
let net_state = Validator.net_state validator in
|
||||||
State.Valid_block.Current.head net_state >>= fun head ->
|
Chain.head net_state >>= fun head ->
|
||||||
|
let head_header = State.Block.header head in
|
||||||
|
let head_hash = State.Block.hash head in
|
||||||
|
State.Block.context head >>= fun head_context ->
|
||||||
|
Context.get_protocol head_context >>= fun head_protocol ->
|
||||||
Prevalidator.context pv >>= function
|
Prevalidator.context pv >>= function
|
||||||
| Error _ -> Lwt.fail Not_found
|
| Error _ -> Lwt.fail Not_found
|
||||||
| Ok { context ; fitness } ->
|
| Ok { context ; fitness } ->
|
||||||
Context.get_protocol context >>= fun protocol ->
|
Context.get_protocol context >>= fun protocol ->
|
||||||
Context.get_test_network context >>= fun test_network ->
|
Context.get_test_network context >>= fun test_network ->
|
||||||
let proto_level =
|
let proto_level =
|
||||||
if Protocol_hash.equal protocol head.protocol_hash then
|
if Protocol_hash.equal protocol head_protocol then
|
||||||
head.proto_level
|
head_header.shell.proto_level
|
||||||
else
|
else
|
||||||
((head.proto_level + 1) mod 256) in
|
((head_header.shell.proto_level + 1) mod 256) in
|
||||||
let operations =
|
let operations =
|
||||||
let pv_result, _ = Prevalidator.operations pv in
|
let pv_result, _ = Prevalidator.operations pv in
|
||||||
[ pv_result.applied ] in
|
[ pv_result.applied ] in
|
||||||
Lwt.return
|
Lwt.return
|
||||||
{ hash = prevalidation_hash ;
|
{ hash = prevalidation_hash ;
|
||||||
level = Int32.succ head.level ;
|
level = Int32.succ head_header.shell.level ;
|
||||||
proto_level ;
|
proto_level ;
|
||||||
predecessor = head.hash ;
|
predecessor = head_hash ;
|
||||||
fitness ;
|
fitness ;
|
||||||
timestamp = Prevalidator.timestamp pv ;
|
timestamp = Prevalidator.timestamp pv ;
|
||||||
protocol ;
|
protocol ;
|
||||||
@ -292,60 +280,61 @@ module RPC = struct
|
|||||||
(List.map Operation_list_hash.compute operations) ;
|
(List.map Operation_list_hash.compute operations) ;
|
||||||
operations = Some operations ;
|
operations = Some operations ;
|
||||||
data = MBytes.of_string "" ;
|
data = MBytes.of_string "" ;
|
||||||
net_id = head.net_id ;
|
net_id = head_header.shell.net_id ;
|
||||||
test_network ;
|
test_network ;
|
||||||
}
|
}
|
||||||
|
|
||||||
let rpc_context (block : State.Valid_block.t) : Updater.rpc_context =
|
let rpc_context block : Updater.rpc_context Lwt.t =
|
||||||
{ block_hash = block.hash ;
|
let block_hash = State.Block.hash block in
|
||||||
block_header = {
|
let block_header = State.Block.header block in
|
||||||
shell = {
|
State.Block.context block >|= fun context ->
|
||||||
net_id = block.net_id ;
|
{ Updater.block_hash ;
|
||||||
level = block.level ;
|
block_header ;
|
||||||
proto_level = block.proto_level ;
|
operation_hashes = (fun () -> State.Block.all_operation_hashes block) ;
|
||||||
predecessor = block.predecessor ;
|
operations = (fun () -> State.Block.all_operations block) ;
|
||||||
timestamp = block.timestamp ;
|
context ;
|
||||||
operations_hash = block.operations_hash ;
|
|
||||||
fitness = block.fitness ;
|
|
||||||
} ;
|
|
||||||
proto = block.proto_header ;
|
|
||||||
} ;
|
|
||||||
operation_hashes = (fun () -> Lazy.force block.operation_hashes) ;
|
|
||||||
operations = (fun () -> Lazy.force block.operations) ;
|
|
||||||
context = block.context ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let get_rpc_context node block =
|
let get_rpc_context node block =
|
||||||
match block with
|
match block with
|
||||||
| `Genesis ->
|
| `Genesis ->
|
||||||
State.Valid_block.Current.genesis node.mainnet_net >>= fun block ->
|
Chain.genesis node.mainnet_net >>= fun block ->
|
||||||
Lwt.return (Some (rpc_context block))
|
rpc_context block >>= fun ctxt ->
|
||||||
|
Lwt.return (Some ctxt)
|
||||||
| ( `Head n | `Test_head n ) as block ->
|
| ( `Head n | `Test_head n ) as block ->
|
||||||
let validator = get_validator node block in
|
let validator = get_validator node block in
|
||||||
let net_state = Validator.net_state validator in
|
let net_state = Validator.net_state validator in
|
||||||
let net_db = Validator.net_db validator in
|
let net_db = Validator.net_db validator in
|
||||||
State.Valid_block.Current.head net_state >>= fun head ->
|
Chain.head net_state >>= fun head ->
|
||||||
get_pred net_db n head >>= fun block ->
|
predecessor net_db n head >>= fun block ->
|
||||||
Lwt.return (Some (rpc_context block))
|
rpc_context block >>= fun ctxt ->
|
||||||
|
Lwt.return (Some ctxt)
|
||||||
| `Hash hash-> begin
|
| `Hash hash-> begin
|
||||||
read_valid_block node hash >|= function
|
read_valid_block node hash >>= function
|
||||||
| None -> None
|
| None ->
|
||||||
| Some block -> Some (rpc_context block)
|
Lwt.return_none
|
||||||
|
| Some block ->
|
||||||
|
rpc_context block >>= fun ctxt ->
|
||||||
|
Lwt.return (Some ctxt)
|
||||||
end
|
end
|
||||||
| ( `Prevalidation | `Test_prevalidation ) as block ->
|
| ( `Prevalidation | `Test_prevalidation ) as block ->
|
||||||
let validator, net_db = get_net node block in
|
let validator, net_db = get_net node block in
|
||||||
let pv = Validator.prevalidator validator in
|
let pv = Validator.prevalidator validator in
|
||||||
let net_state = Validator.net_state validator in
|
let net_state = Validator.net_state validator in
|
||||||
State.Valid_block.Current.head net_state >>= fun head ->
|
Chain.head net_state >>= fun head ->
|
||||||
|
let head_header = State.Block.header head in
|
||||||
|
let head_hash = State.Block.hash head in
|
||||||
|
State.Block.context head >>= fun head_context ->
|
||||||
|
Context.get_protocol head_context >>= fun head_protocol ->
|
||||||
Prevalidator.context pv >>= function
|
Prevalidator.context pv >>= function
|
||||||
| Error _ -> Lwt.fail Not_found
|
| Error _ -> Lwt.fail Not_found
|
||||||
| Ok { context ; fitness } ->
|
| Ok { context ; fitness } ->
|
||||||
Context.get_protocol context >>= fun protocol ->
|
Context.get_protocol context >>= fun protocol ->
|
||||||
let proto_level =
|
let proto_level =
|
||||||
if Protocol_hash.equal protocol head.protocol_hash then
|
if Protocol_hash.equal protocol head_protocol then
|
||||||
head.proto_level
|
head_header.shell.proto_level
|
||||||
else
|
else
|
||||||
((head.proto_level + 1) mod 256) in
|
((head_header.shell.proto_level + 1) mod 256) in
|
||||||
let operation_hashes =
|
let operation_hashes =
|
||||||
let pv_result, _ = Prevalidator.operations pv in
|
let pv_result, _ = Prevalidator.operations pv in
|
||||||
[ pv_result.applied ] in
|
[ pv_result.applied ] in
|
||||||
@ -356,10 +345,10 @@ module RPC = struct
|
|||||||
Updater.block_hash = prevalidation_hash ;
|
Updater.block_hash = prevalidation_hash ;
|
||||||
block_header = {
|
block_header = {
|
||||||
shell = {
|
shell = {
|
||||||
net_id = head.net_id ;
|
net_id = head_header.shell.net_id ;
|
||||||
level = Int32.succ head.level ;
|
level = Int32.succ head_header.shell.level ;
|
||||||
proto_level ;
|
proto_level ;
|
||||||
predecessor = head.hash ;
|
predecessor = head_hash ;
|
||||||
timestamp = Prevalidator.timestamp pv ;
|
timestamp = Prevalidator.timestamp pv ;
|
||||||
operations_hash ;
|
operations_hash ;
|
||||||
fitness ;
|
fitness ;
|
||||||
@ -376,18 +365,16 @@ module RPC = struct
|
|||||||
context ;
|
context ;
|
||||||
})
|
})
|
||||||
|
|
||||||
let operations node block =
|
let operation_hashes node block =
|
||||||
match block with
|
match block with
|
||||||
| `Genesis ->
|
| `Genesis -> Lwt.return []
|
||||||
State.Valid_block.Current.genesis node.mainnet_net >>= fun { operation_hashes } ->
|
|
||||||
Lazy.force operation_hashes
|
|
||||||
| ( `Head n | `Test_head n ) as block ->
|
| ( `Head n | `Test_head n ) as block ->
|
||||||
let validator = get_validator node block in
|
let validator = get_validator node block in
|
||||||
let net_state = Validator.net_state validator in
|
let net_state = Validator.net_state validator in
|
||||||
let net_db = Validator.net_db validator in
|
let net_db = Validator.net_db validator in
|
||||||
State.Valid_block.Current.head net_state >>= fun head ->
|
Chain.head net_state >>= fun head ->
|
||||||
get_pred net_db n head >>= fun { operation_hashes } ->
|
predecessor net_db n head >>= fun block ->
|
||||||
Lazy.force operation_hashes
|
State.Block.all_operation_hashes block
|
||||||
| (`Prevalidation | `Test_prevalidation) as block ->
|
| (`Prevalidation | `Test_prevalidation) as block ->
|
||||||
let validator, _net = get_net node block in
|
let validator, _net = get_net node block in
|
||||||
let pv = Validator.prevalidator validator in
|
let pv = Validator.prevalidator validator in
|
||||||
@ -396,12 +383,31 @@ module RPC = struct
|
|||||||
| `Hash hash ->
|
| `Hash hash ->
|
||||||
read_valid_block node hash >>= function
|
read_valid_block node hash >>= function
|
||||||
| None -> Lwt.return_nil
|
| None -> Lwt.return_nil
|
||||||
| Some { operation_hashes } ->
|
| Some block ->
|
||||||
Lazy.force operation_hashes
|
State.Block.all_operation_hashes block
|
||||||
|
|
||||||
let operation_content node hash =
|
let operations node block =
|
||||||
Distributed_db.read_operation node.distributed_db hash >>= fun op ->
|
match block with
|
||||||
Lwt.return (map_option ~f:snd op)
|
| `Genesis -> Lwt.return []
|
||||||
|
| ( `Head n | `Test_head n ) as block ->
|
||||||
|
let validator = get_validator node block in
|
||||||
|
let net_state = Validator.net_state validator in
|
||||||
|
let net_db = Validator.net_db validator in
|
||||||
|
Chain.head net_state >>= fun head ->
|
||||||
|
predecessor net_db n head >>= fun block ->
|
||||||
|
State.Block.all_operations block
|
||||||
|
| (`Prevalidation | `Test_prevalidation) as block ->
|
||||||
|
let validator, net_db = get_net node block in
|
||||||
|
let pv = Validator.prevalidator validator in
|
||||||
|
let { Prevalidation.applied }, _ = Prevalidator.operations pv in
|
||||||
|
Lwt_list.map_p
|
||||||
|
(Distributed_db.Operation.read_exn net_db) applied >>= fun applied ->
|
||||||
|
Lwt.return [applied]
|
||||||
|
| `Hash hash ->
|
||||||
|
read_valid_block node hash >>= function
|
||||||
|
| None -> Lwt.return_nil
|
||||||
|
| Some block ->
|
||||||
|
State.Block.all_operations block
|
||||||
|
|
||||||
let pending_operations node (block: block) =
|
let pending_operations node (block: block) =
|
||||||
match block with
|
match block with
|
||||||
@ -415,13 +421,13 @@ module RPC = struct
|
|||||||
let prevalidator = Validator.prevalidator validator in
|
let prevalidator = Validator.prevalidator validator in
|
||||||
let net_state = Validator.net_state validator in
|
let net_state = Validator.net_state validator in
|
||||||
let net_db = Validator.net_db validator in
|
let net_db = Validator.net_db validator in
|
||||||
State.Valid_block.Current.head net_state >>= fun head ->
|
Chain.head net_state >>= fun head ->
|
||||||
get_pred net_db n head >>= fun b ->
|
predecessor net_db n head >>= fun b ->
|
||||||
Prevalidator.pending ~block:b prevalidator >|= fun ops ->
|
Prevalidator.pending ~block:b prevalidator >|= fun ops ->
|
||||||
Prevalidation.empty_result, ops
|
Prevalidation.empty_result, ops
|
||||||
| `Genesis ->
|
| `Genesis ->
|
||||||
let net = node.mainnet_net in
|
let net = node.mainnet_net in
|
||||||
State.Valid_block.Current.genesis net >>= fun b ->
|
Chain.genesis net >>= fun b ->
|
||||||
let validator = get_validator node `Genesis in
|
let validator = get_validator node `Genesis in
|
||||||
let prevalidator = Validator.prevalidator validator in
|
let prevalidator = Validator.prevalidator validator in
|
||||||
Prevalidator.pending ~block:b prevalidator >|= fun ops ->
|
Prevalidator.pending ~block:b prevalidator >|= fun ops ->
|
||||||
@ -433,7 +439,7 @@ module RPC = struct
|
|||||||
| Some (validator, net_db) ->
|
| Some (validator, net_db) ->
|
||||||
let net_state = Distributed_db.state net_db in
|
let net_state = Distributed_db.state net_db in
|
||||||
let prevalidator = Validator.prevalidator validator in
|
let prevalidator = Validator.prevalidator validator in
|
||||||
State.Valid_block.read_exn net_state h >>= fun block ->
|
State.Block.read_exn net_state h >>= fun block ->
|
||||||
Prevalidator.pending ~block prevalidator >|= fun ops ->
|
Prevalidator.pending ~block prevalidator >|= fun ops ->
|
||||||
Prevalidation.empty_result, ops
|
Prevalidation.empty_result, ops
|
||||||
end
|
end
|
||||||
@ -450,18 +456,18 @@ module RPC = struct
|
|||||||
match block with
|
match block with
|
||||||
| `Genesis ->
|
| `Genesis ->
|
||||||
let net = node.mainnet_net in
|
let net = node.mainnet_net in
|
||||||
State.Valid_block.Current.genesis net >>= return
|
Chain.genesis net >>= return
|
||||||
| ( `Head 0 | `Prevalidation
|
| ( `Head 0 | `Prevalidation
|
||||||
| `Test_head 0 | `Test_prevalidation ) as block ->
|
| `Test_head 0 | `Test_prevalidation ) as block ->
|
||||||
let validator = get_validator node block in
|
let validator = get_validator node block in
|
||||||
let net_state = Validator.net_state validator in
|
let net_state = Validator.net_state validator in
|
||||||
State.Valid_block.Current.head net_state >>= return
|
Chain.head net_state >>= return
|
||||||
| `Head n | `Test_head n as block -> begin
|
| `Head n | `Test_head n as block -> begin
|
||||||
let validator = get_validator node block in
|
let validator = get_validator node block in
|
||||||
let net_state = Validator.net_state validator in
|
let net_state = Validator.net_state validator in
|
||||||
let net_db = Validator.net_db validator in
|
let net_db = Validator.net_db validator in
|
||||||
State.Valid_block.Current.head net_state >>= fun head ->
|
Chain.head net_state >>= fun head ->
|
||||||
get_pred net_db n head >>= return
|
predecessor net_db n head >>= return
|
||||||
end
|
end
|
||||||
| `Hash hash ->
|
| `Hash hash ->
|
||||||
read_valid_block node hash >>= function
|
read_valid_block node hash >>= function
|
||||||
@ -469,12 +475,7 @@ module RPC = struct
|
|||||||
| Some data -> return data
|
| Some data -> return data
|
||||||
end >>=? fun predecessor ->
|
end >>=? fun predecessor ->
|
||||||
let net_db = Validator.net_db node.mainnet_validator in
|
let net_db = Validator.net_db node.mainnet_validator in
|
||||||
map_p
|
map_p (Distributed_db.resolve_operation net_db) ops >>=? fun rops ->
|
||||||
(fun h ->
|
|
||||||
Distributed_db.Operation.read net_db h >>= function
|
|
||||||
| None -> failwith "Unknown operation %a" Operation_hash.pp h
|
|
||||||
| Some po -> return (h, po))
|
|
||||||
ops >>=? fun rops ->
|
|
||||||
Prevalidation.start_prevalidation
|
Prevalidation.start_prevalidation
|
||||||
~predecessor ~timestamp >>=? fun validation_state ->
|
~predecessor ~timestamp >>=? fun validation_state ->
|
||||||
Prevalidation.prevalidate
|
Prevalidation.prevalidate
|
||||||
@ -506,62 +507,57 @@ module RPC = struct
|
|||||||
Lwt.return (Some (RPC.map (fun _ -> ()) dir))
|
Lwt.return (Some (RPC.map (fun _ -> ()) dir))
|
||||||
|
|
||||||
let heads node =
|
let heads node =
|
||||||
State.Valid_block.known_heads node.mainnet_net >>= fun heads ->
|
Chain.known_heads node.mainnet_net >>= fun heads ->
|
||||||
begin
|
begin
|
||||||
match Validator.test_validator node.mainnet_validator with
|
match Validator.test_validator node.mainnet_validator with
|
||||||
| None -> Lwt.return_nil
|
| None -> Lwt.return_nil
|
||||||
| Some (_, net_db) ->
|
| Some (_, net_db) ->
|
||||||
State.Valid_block.known_heads (Distributed_db.state net_db)
|
Chain.known_heads (Distributed_db.state net_db)
|
||||||
end >>= fun test_heads ->
|
end >>= fun test_heads ->
|
||||||
Lwt_list.fold_left_s
|
Lwt_list.fold_left_s
|
||||||
(fun map block ->
|
(fun map block ->
|
||||||
convert block >|= fun bi ->
|
convert block >|= fun bi ->
|
||||||
Block_hash.Map.add
|
Block_hash.Map.add
|
||||||
block.State.Valid_block.hash bi map)
|
(State.Block.hash block) bi map)
|
||||||
Block_hash.Map.empty (test_heads @ heads)
|
Block_hash.Map.empty (test_heads @ heads)
|
||||||
|
|
||||||
let predecessors node len head =
|
let predecessors node len head =
|
||||||
let rec loop net_db acc len hash (block: Block_header.t) =
|
let rec loop acc len block =
|
||||||
if Block_hash.equal block.shell.predecessor hash then
|
if len = 0 then
|
||||||
Lwt.return (List.rev acc)
|
Lwt.return (List.rev acc)
|
||||||
else begin
|
else
|
||||||
if len = 0 then
|
State.Block.predecessor block >>= function
|
||||||
Lwt.return (List.rev acc)
|
| None -> Lwt.return (List.rev acc)
|
||||||
else
|
| Some block ->
|
||||||
let hash = block.shell.predecessor in
|
loop (State.Block.hash block :: acc) (len-1) block
|
||||||
Distributed_db.Block_header.read_exn net_db hash >>= fun block ->
|
in
|
||||||
loop net_db (hash :: acc) (len-1) hash block
|
|
||||||
end in
|
|
||||||
try
|
try
|
||||||
Distributed_db.read_block_exn
|
State.read_block_exn node.state head >>= fun block ->
|
||||||
node.distributed_db head >>= fun (net_db, block) ->
|
loop [] len block
|
||||||
loop net_db [] len head block
|
|
||||||
with Not_found -> Lwt.return_nil
|
with Not_found -> Lwt.return_nil
|
||||||
|
|
||||||
let predecessors_bi state ignored len head =
|
let predecessors_bi ignored len head =
|
||||||
try
|
try
|
||||||
let rec loop acc len hash =
|
let rec loop acc len block =
|
||||||
State.Valid_block.read_exn state hash >>= fun block ->
|
|
||||||
convert block >>= fun bi ->
|
convert block >>= fun bi ->
|
||||||
if Block_hash.equal bi.predecessor hash then
|
State.Block.predecessor block >>= function
|
||||||
Lwt.return (List.rev (bi :: acc))
|
| None ->
|
||||||
else begin
|
Lwt.return (List.rev (bi :: acc))
|
||||||
if len = 0
|
| Some pred ->
|
||||||
|| Block_hash.Set.mem hash ignored then
|
if len = 0 ||
|
||||||
Lwt.return (List.rev acc)
|
Block_hash.Set.mem (State.Block.hash block) ignored then
|
||||||
else
|
Lwt.return (List.rev acc)
|
||||||
loop (bi :: acc) (len-1) bi.predecessor
|
else
|
||||||
end in
|
loop (bi :: acc) (len-1) pred
|
||||||
|
in
|
||||||
loop [] len head
|
loop [] len head
|
||||||
with Not_found -> Lwt.return_nil
|
with Not_found -> Lwt.return_nil
|
||||||
|
|
||||||
let list node len heads =
|
let list node len heads =
|
||||||
Lwt_list.fold_left_s
|
Lwt_list.fold_left_s
|
||||||
(fun (ignored, acc) head ->
|
(fun (ignored, acc) head ->
|
||||||
Distributed_db.read_block_exn
|
State.read_block_exn node.state head >>= fun block ->
|
||||||
node.distributed_db head >>= fun (net_db, _block) ->
|
predecessors_bi ignored len block >>= fun predecessors ->
|
||||||
let net_state = Distributed_db.state net_db in
|
|
||||||
predecessors_bi net_state ignored len head >>= fun predecessors ->
|
|
||||||
let ignored =
|
let ignored =
|
||||||
List.fold_right
|
List.fold_right
|
||||||
(fun x s -> Block_hash.Set.add x.hash s)
|
(fun x s -> Block_hash.Set.add x.hash s)
|
||||||
@ -572,9 +568,10 @@ module RPC = struct
|
|||||||
heads >>= fun (_, blocks) ->
|
heads >>= fun (_, blocks) ->
|
||||||
Lwt.return (List.rev blocks)
|
Lwt.return (List.rev blocks)
|
||||||
|
|
||||||
let block_watcher node = Distributed_db.watch_block node.distributed_db
|
let block_header_watcher node =
|
||||||
|
Distributed_db.watch_block_header node.distributed_db
|
||||||
|
|
||||||
let valid_block_watcher node =
|
let block_watcher node =
|
||||||
let stream, shutdown = Validator.global_watcher node.validator in
|
let stream, shutdown = Validator.global_watcher node.validator in
|
||||||
Lwt_stream.map_s (fun block -> convert block) stream,
|
Lwt_stream.map_s (fun block -> convert block) stream,
|
||||||
shutdown
|
shutdown
|
||||||
@ -597,12 +594,15 @@ module RPC = struct
|
|||||||
let rec next () =
|
let rec next () =
|
||||||
if !first_run then begin
|
if !first_run then begin
|
||||||
first_run := false ;
|
first_run := false ;
|
||||||
State.Valid_block.Current.head node.mainnet_net >>= fun head ->
|
Chain.head node.mainnet_net >>= fun head ->
|
||||||
Lwt.return (Some (head.hash, head.timestamp))
|
let head_hash = State.Block.hash head in
|
||||||
|
let head_header = State.Block.header head in
|
||||||
|
Lwt.return (Some (head_hash, head_header.shell.timestamp))
|
||||||
end else begin
|
end else begin
|
||||||
Lwt.pick [
|
Lwt.pick [
|
||||||
( Lwt_stream.get block_stream >|=
|
( Lwt_stream.get block_stream >|=
|
||||||
map_option ~f:(fun b -> (b.State.Valid_block.hash, b.timestamp)) ) ;
|
map_option ~f:(fun b ->
|
||||||
|
(State.Block.hash b, (State.Block.header b).shell.timestamp)) ) ;
|
||||||
(Validator.bootstrapped node.mainnet_validator >|= fun () -> None) ;
|
(Validator.bootstrapped node.mainnet_validator >|= fun () -> None) ;
|
||||||
]
|
]
|
||||||
end in
|
end in
|
||||||
|
@ -27,7 +27,7 @@ module RPC : sig
|
|||||||
|
|
||||||
val inject_block:
|
val inject_block:
|
||||||
t -> ?force:bool ->
|
t -> ?force:bool ->
|
||||||
MBytes.t -> Operation_hash.t list list ->
|
MBytes.t -> Distributed_db.operation list list ->
|
||||||
(Block_hash.t * unit tzresult Lwt.t) tzresult Lwt.t
|
(Block_hash.t * unit tzresult Lwt.t) tzresult Lwt.t
|
||||||
(** [inject_block node ?force bytes] tries to insert [bytes]
|
(** [inject_block node ?force bytes] tries to insert [bytes]
|
||||||
(supposedly the serialization of a block header) inside
|
(supposedly the serialization of a block header) inside
|
||||||
@ -43,9 +43,9 @@ module RPC : sig
|
|||||||
|
|
||||||
val raw_block_info:
|
val raw_block_info:
|
||||||
t -> Block_hash.t -> block_info Lwt.t
|
t -> Block_hash.t -> block_info Lwt.t
|
||||||
val block_watcher:
|
val block_header_watcher:
|
||||||
t -> (Block_hash.t * Block_header.t) Lwt_stream.t * Watcher.stopper
|
t -> (Block_hash.t * Block_header.t) Lwt_stream.t * Watcher.stopper
|
||||||
val valid_block_watcher:
|
val block_watcher:
|
||||||
t -> (block_info Lwt_stream.t * Watcher.stopper)
|
t -> (block_info Lwt_stream.t * Watcher.stopper)
|
||||||
val heads: t -> block_info Block_hash.Map.t Lwt.t
|
val heads: t -> block_info Block_hash.Map.t Lwt.t
|
||||||
|
|
||||||
@ -58,10 +58,10 @@ module RPC : sig
|
|||||||
val block_info:
|
val block_info:
|
||||||
t -> block -> block_info Lwt.t
|
t -> block -> block_info Lwt.t
|
||||||
|
|
||||||
val operations:
|
val operation_hashes:
|
||||||
t -> block -> Operation_hash.t list list Lwt.t
|
t -> block -> Operation_hash.t list list Lwt.t
|
||||||
val operation_content:
|
val operations:
|
||||||
t -> Operation_hash.t -> Operation.t option Lwt.t
|
t -> block -> Operation.t list list Lwt.t
|
||||||
val operation_watcher:
|
val operation_watcher:
|
||||||
t -> (Operation_hash.t * Operation.t) Lwt_stream.t * Watcher.stopper
|
t -> (Operation_hash.t * Operation.t) Lwt_stream.t * Watcher.stopper
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ module RPC : sig
|
|||||||
val preapply:
|
val preapply:
|
||||||
t -> block ->
|
t -> block ->
|
||||||
timestamp:Time.t -> sort:bool ->
|
timestamp:Time.t -> sort:bool ->
|
||||||
Operation_hash.t list ->
|
Distributed_db.operation list ->
|
||||||
(Fitness.t * error Prevalidation.preapply_result) tzresult Lwt.t
|
(Fitness.t * error Prevalidation.preapply_result) tzresult Lwt.t
|
||||||
|
|
||||||
val validate: t -> Net_id.t -> Block_hash.t -> unit tzresult Lwt.t
|
val validate: t -> Net_id.t -> Block_hash.t -> unit tzresult Lwt.t
|
||||||
|
@ -16,6 +16,29 @@ let filter_bi operations (bi: Services.Blocks.block_info) =
|
|||||||
let bi = if operations then bi else { bi with operations = None } in
|
let bi = if operations then bi else { bi with operations = None } in
|
||||||
bi
|
bi
|
||||||
|
|
||||||
|
let monitor_operations node contents =
|
||||||
|
let stream, stopper = Node.RPC.operation_watcher node in
|
||||||
|
let shutdown () = Watcher.shutdown stopper in
|
||||||
|
let first_request = ref true in
|
||||||
|
let next () =
|
||||||
|
if not !first_request then
|
||||||
|
Lwt_stream.get stream >>= function
|
||||||
|
| None -> Lwt.return_none
|
||||||
|
| Some (h, op) when contents -> Lwt.return (Some [[h, Some op]])
|
||||||
|
| Some (h, _) -> Lwt.return (Some [[h, None]])
|
||||||
|
else begin
|
||||||
|
first_request := false ;
|
||||||
|
Node.RPC.operation_hashes node `Prevalidation >>= fun hashes ->
|
||||||
|
if contents then
|
||||||
|
Node.RPC.operations node `Prevalidation >>= fun ops ->
|
||||||
|
Lwt.return_some @@
|
||||||
|
List.map2 (List.map2 (fun h op -> h, Some op)) hashes ops
|
||||||
|
else
|
||||||
|
Lwt.return_some @@
|
||||||
|
List.map (List.map (fun h -> h, None)) hashes
|
||||||
|
end in
|
||||||
|
RPC.Answer.return_stream { next ; shutdown }
|
||||||
|
|
||||||
let register_bi_dir node dir =
|
let register_bi_dir node dir =
|
||||||
let dir =
|
let dir =
|
||||||
let implementation b include_ops =
|
let implementation b include_ops =
|
||||||
@ -80,9 +103,20 @@ let register_bi_dir node dir =
|
|||||||
RPC.register1 dir
|
RPC.register1 dir
|
||||||
Services.Blocks.test_network implementation in
|
Services.Blocks.test_network implementation in
|
||||||
let dir =
|
let dir =
|
||||||
let implementation b () =
|
let implementation b { Node_rpc_services.Blocks.contents ; monitor } =
|
||||||
Node.RPC.operations node b >>=
|
match b with
|
||||||
RPC.Answer.return in
|
| `Prevalidation when monitor ->
|
||||||
|
monitor_operations node contents
|
||||||
|
| _ ->
|
||||||
|
Node.RPC.operation_hashes node b >>= fun hashes ->
|
||||||
|
if contents then
|
||||||
|
Node.RPC.operations node b >>= fun ops ->
|
||||||
|
RPC.Answer.return @@
|
||||||
|
List.map2 (List.map2 (fun h op -> h, Some op)) hashes ops
|
||||||
|
else
|
||||||
|
RPC.Answer.return @@
|
||||||
|
List.map (List.map (fun h -> h, None)) hashes
|
||||||
|
in
|
||||||
RPC.register1 dir
|
RPC.register1 dir
|
||||||
Services.Blocks.operations implementation in
|
Services.Blocks.operations implementation in
|
||||||
let dir =
|
let dir =
|
||||||
@ -275,7 +309,7 @@ let list_blocks
|
|||||||
requested_blocks in
|
requested_blocks in
|
||||||
RPC.Answer.return infos
|
RPC.Answer.return infos
|
||||||
else begin
|
else begin
|
||||||
let (bi_stream, stopper) = Node.RPC.valid_block_watcher node in
|
let (bi_stream, stopper) = Node.RPC.block_watcher node in
|
||||||
let stream =
|
let stream =
|
||||||
match delay with
|
match delay with
|
||||||
| None ->
|
| None ->
|
||||||
@ -298,47 +332,6 @@ let list_blocks
|
|||||||
RPC.Answer.return_stream { next ; shutdown }
|
RPC.Answer.return_stream { next ; shutdown }
|
||||||
end
|
end
|
||||||
|
|
||||||
let list_operations node {Services.Operations.monitor; contents} =
|
|
||||||
let monitor = match monitor with None -> false | Some x -> x in
|
|
||||||
let include_ops = match contents with None -> false | Some x -> x in
|
|
||||||
Node.RPC.operations node `Prevalidation >>= fun operationss ->
|
|
||||||
let fetch_operations_content operations =
|
|
||||||
if include_ops then
|
|
||||||
Lwt_list.map_s
|
|
||||||
(fun h ->
|
|
||||||
Node.RPC.operation_content node h >>= fun content ->
|
|
||||||
Lwt.return (h, content))
|
|
||||||
operations
|
|
||||||
else
|
|
||||||
Lwt.return @@ ListLabels.map operations ~f:(fun h -> h, None) in
|
|
||||||
Lwt_list.map_p fetch_operations_content operationss >>= fun operations ->
|
|
||||||
if not monitor then
|
|
||||||
RPC.Answer.return operations
|
|
||||||
else
|
|
||||||
let stream, stopper = Node.RPC.operation_watcher node in
|
|
||||||
let shutdown () = Watcher.shutdown stopper in
|
|
||||||
let first_request = ref true in
|
|
||||||
let next () =
|
|
||||||
if not !first_request then
|
|
||||||
Lwt_stream.get stream >>= function
|
|
||||||
| None -> Lwt.return_none
|
|
||||||
| Some (h, op) when include_ops -> Lwt.return (Some [[h, Some op]])
|
|
||||||
| Some (h, _) -> Lwt.return (Some [[h, None]])
|
|
||||||
else begin
|
|
||||||
first_request := false ;
|
|
||||||
Lwt.return (Some operations)
|
|
||||||
end in
|
|
||||||
RPC.Answer.return_stream { next ; shutdown }
|
|
||||||
|
|
||||||
let get_operations node hashes () =
|
|
||||||
Lwt_list.map_p
|
|
||||||
(fun h ->
|
|
||||||
Node.RPC.operation_content node h >>= function
|
|
||||||
| None -> Lwt.fail Not_found
|
|
||||||
| Some h -> Lwt.return h)
|
|
||||||
hashes >>= fun ops ->
|
|
||||||
RPC.Answer.return ops
|
|
||||||
|
|
||||||
let list_protocols node {Services.Protocols.monitor; contents} =
|
let list_protocols node {Services.Protocols.monitor; contents} =
|
||||||
let monitor = match monitor with None -> false | Some x -> x in
|
let monitor = match monitor with None -> false | Some x -> x in
|
||||||
let include_contents = match contents with None -> false | Some x -> x in
|
let include_contents = match contents with None -> false | Some x -> x in
|
||||||
@ -391,10 +384,6 @@ let build_rpc_directory node =
|
|||||||
~descr:
|
~descr:
|
||||||
"All the RPCs which are specific to the protocol version."
|
"All the RPCs which are specific to the protocol version."
|
||||||
dir Services.Blocks.proto_path implementation in
|
dir Services.Blocks.proto_path implementation in
|
||||||
let dir =
|
|
||||||
RPC.register0 dir Services.Operations.list (list_operations node) in
|
|
||||||
let dir =
|
|
||||||
RPC.register1 dir Services.Operations.contents (get_operations node) in
|
|
||||||
let dir =
|
let dir =
|
||||||
RPC.register0 dir Services.Protocols.list (list_protocols node) in
|
RPC.register0 dir Services.Protocols.list (list_protocols node) in
|
||||||
let dir =
|
let dir =
|
||||||
|
@ -46,6 +46,21 @@ module Error = struct
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
type operation = Distributed_db.operation =
|
||||||
|
| Blob of Operation.t
|
||||||
|
| Hash of Operation_hash.t
|
||||||
|
|
||||||
|
let operation_encoding =
|
||||||
|
let open Data_encoding in
|
||||||
|
union [
|
||||||
|
case Operation.encoding
|
||||||
|
(function Blob op -> Some op | Hash _ -> None)
|
||||||
|
(fun op -> Blob op) ;
|
||||||
|
case Operation_hash.encoding
|
||||||
|
(function Hash oph -> Some oph | Blob _ -> None)
|
||||||
|
(fun oph -> Hash oph) ;
|
||||||
|
]
|
||||||
|
|
||||||
module Blocks = struct
|
module Blocks = struct
|
||||||
|
|
||||||
type block = [
|
type block = [
|
||||||
@ -75,28 +90,28 @@ module Blocks = struct
|
|||||||
(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 ; operations_hash ; data ;
|
||||||
operations ; test_network } ->
|
operations ; test_network } ->
|
||||||
({ Block_header.shell =
|
((hash, operations, protocol, test_network),
|
||||||
|
{ Block_header.shell =
|
||||||
{ net_id ; level ; proto_level ; predecessor ;
|
{ net_id ; level ; proto_level ; predecessor ;
|
||||||
timestamp ; operations_hash ; fitness } ;
|
timestamp ; operations_hash ; fitness } ;
|
||||||
proto = data },
|
proto = data }))
|
||||||
(hash, operations, protocol, test_network)))
|
(fun ((hash, operations, protocol, test_network),
|
||||||
(fun ({ Block_header.shell =
|
{ Block_header.shell =
|
||||||
{ net_id ; level ; proto_level ; predecessor ;
|
{ net_id ; level ; proto_level ; predecessor ;
|
||||||
timestamp ; operations_hash ; fitness } ;
|
timestamp ; operations_hash ; fitness } ;
|
||||||
proto = data },
|
proto = data }) ->
|
||||||
(hash, operations, protocol, test_network)) ->
|
|
||||||
{ hash ; net_id ; level ; proto_level ; predecessor ;
|
{ hash ; net_id ; level ; proto_level ; predecessor ;
|
||||||
fitness ; timestamp ; protocol ; operations_hash ; data ;
|
fitness ; timestamp ; protocol ; operations_hash ; data ;
|
||||||
operations ; test_network })
|
operations ; test_network })
|
||||||
(dynamic_size
|
(dynamic_size
|
||||||
(merge_objs
|
(merge_objs
|
||||||
Block_header.encoding
|
|
||||||
(obj4
|
(obj4
|
||||||
(req "hash" Block_hash.encoding)
|
(req "hash" Block_hash.encoding)
|
||||||
(opt "operations" (list (list Operation_hash.encoding)))
|
(opt "operations" (list (list Operation_hash.encoding)))
|
||||||
(req "protocol" Protocol_hash.encoding)
|
(req "protocol" Protocol_hash.encoding)
|
||||||
(dft "test_network"
|
(dft "test_network"
|
||||||
Context.test_network_encoding Context.Not_running))))
|
Context.test_network_encoding Context.Not_running))
|
||||||
|
Block_header.encoding))
|
||||||
|
|
||||||
let parse_block s =
|
let parse_block s =
|
||||||
try
|
try
|
||||||
@ -136,7 +151,7 @@ module Blocks = struct
|
|||||||
RPC.Arg.make ~name ~descr ~construct ~destruct ()
|
RPC.Arg.make ~name ~descr ~construct ~destruct ()
|
||||||
|
|
||||||
type preapply_param = {
|
type preapply_param = {
|
||||||
operations: Operation_hash.t list ;
|
operations: operation list ;
|
||||||
sort: bool ;
|
sort: bool ;
|
||||||
timestamp: Time.t option ;
|
timestamp: Time.t option ;
|
||||||
}
|
}
|
||||||
@ -152,7 +167,7 @@ module Blocks = struct
|
|||||||
| Some x -> x in
|
| Some x -> x in
|
||||||
{ operations ; sort ; timestamp })
|
{ operations ; sort ; timestamp })
|
||||||
(obj3
|
(obj3
|
||||||
(req "operations" (list Operation_hash.encoding))
|
(req "operations" (list (dynamic_size operation_encoding)))
|
||||||
(opt "sort" bool)
|
(opt "sort" bool)
|
||||||
(opt "timestamp" Time.encoding)))
|
(opt "timestamp" Time.encoding)))
|
||||||
|
|
||||||
@ -234,11 +249,31 @@ module Blocks = struct
|
|||||||
~output: (obj1 (req "timestamp" Time.encoding))
|
~output: (obj1 (req "timestamp" Time.encoding))
|
||||||
RPC.Path.(block_path / "timestamp")
|
RPC.Path.(block_path / "timestamp")
|
||||||
|
|
||||||
|
type operations_param = {
|
||||||
|
contents: bool ;
|
||||||
|
monitor: bool ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let operations_param_encoding =
|
||||||
|
let open Data_encoding in
|
||||||
|
conv
|
||||||
|
(fun { contents ; monitor } -> (contents, monitor))
|
||||||
|
(fun (contents, monitor) -> { contents ; monitor })
|
||||||
|
(obj2
|
||||||
|
(dft "contents" bool false)
|
||||||
|
(dft "monitor" bool false))
|
||||||
|
|
||||||
let operations =
|
let operations =
|
||||||
RPC.service
|
RPC.service
|
||||||
~description:"List the block operations."
|
~description:"List the block operations."
|
||||||
~input: empty
|
~input: operations_param_encoding
|
||||||
~output: (obj1 (req "operations" (list (list Operation_hash.encoding))))
|
~output: (obj1
|
||||||
|
(req "operations"
|
||||||
|
(list (list
|
||||||
|
(obj2
|
||||||
|
(req "hash" Operation_hash.encoding)
|
||||||
|
(opt "contents"
|
||||||
|
(dynamic_size Operation.encoding)))))))
|
||||||
RPC.Path.(block_path / "operations")
|
RPC.Path.(block_path / "operations")
|
||||||
|
|
||||||
let protocol =
|
let protocol =
|
||||||
@ -393,58 +428,6 @@ module Blocks = struct
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module Operations = struct
|
|
||||||
|
|
||||||
let operations_arg =
|
|
||||||
let name = "operation_id" in
|
|
||||||
let descr =
|
|
||||||
"A operation identifier in hexadecimal." in
|
|
||||||
let construct ops =
|
|
||||||
String.concat "," (List.map Operation_hash.to_b58check ops) in
|
|
||||||
let destruct h =
|
|
||||||
let ops = split ',' h in
|
|
||||||
try Ok (List.map Operation_hash.of_b58check_exn ops)
|
|
||||||
with _ -> Error "Can't parse hash" in
|
|
||||||
RPC.Arg.make ~name ~descr ~construct ~destruct ()
|
|
||||||
|
|
||||||
let contents =
|
|
||||||
RPC.service
|
|
||||||
~input: empty
|
|
||||||
~output: (list (dynamic_size Operation.encoding))
|
|
||||||
RPC.Path.(root / "operations" /: operations_arg)
|
|
||||||
|
|
||||||
type list_param = {
|
|
||||||
contents: bool option ;
|
|
||||||
monitor: bool option ;
|
|
||||||
}
|
|
||||||
|
|
||||||
let list_param_encoding =
|
|
||||||
conv
|
|
||||||
(fun {contents; monitor} -> (contents, monitor))
|
|
||||||
(fun (contents, monitor) -> {contents; monitor})
|
|
||||||
(obj2
|
|
||||||
(opt "contents" bool)
|
|
||||||
(opt "monitor" bool))
|
|
||||||
|
|
||||||
let list =
|
|
||||||
RPC.service
|
|
||||||
~description:
|
|
||||||
"List operations in the mempool."
|
|
||||||
~input: list_param_encoding
|
|
||||||
~output:
|
|
||||||
(obj1
|
|
||||||
(req "operations"
|
|
||||||
(list
|
|
||||||
(list
|
|
||||||
(obj2
|
|
||||||
(req "hash" Operation_hash.encoding)
|
|
||||||
(opt "contents"
|
|
||||||
(dynamic_size Operation.encoding)))
|
|
||||||
))))
|
|
||||||
RPC.Path.(root / "operations")
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
module Protocols = struct
|
module Protocols = struct
|
||||||
|
|
||||||
let protocols_arg =
|
let protocols_arg =
|
||||||
@ -661,7 +644,7 @@ type inject_block_param = {
|
|||||||
raw: MBytes.t ;
|
raw: MBytes.t ;
|
||||||
blocking: bool ;
|
blocking: bool ;
|
||||||
force: bool ;
|
force: bool ;
|
||||||
operations: Operation_hash.t list list ;
|
operations: operation list list ;
|
||||||
}
|
}
|
||||||
|
|
||||||
let inject_block_param =
|
let inject_block_param =
|
||||||
@ -689,7 +672,7 @@ let inject_block_param =
|
|||||||
(req "operations"
|
(req "operations"
|
||||||
(describe
|
(describe
|
||||||
~description:"..."
|
~description:"..."
|
||||||
(list (list Operation_hash.encoding)))))
|
(list (list (dynamic_size operation_encoding))))))
|
||||||
|
|
||||||
let inject_block =
|
let inject_block =
|
||||||
RPC.service
|
RPC.service
|
||||||
|
@ -13,6 +13,12 @@ module Error : sig
|
|||||||
val wrap: 'a Data_encoding.t -> 'a tzresult Data_encoding.encoding
|
val wrap: 'a Data_encoding.t -> 'a tzresult Data_encoding.encoding
|
||||||
end
|
end
|
||||||
|
|
||||||
|
type operation = Distributed_db.operation =
|
||||||
|
| Blob of Operation.t
|
||||||
|
| Hash of Operation_hash.t
|
||||||
|
|
||||||
|
val operation_encoding: operation Data_encoding.t
|
||||||
|
|
||||||
module Blocks : sig
|
module Blocks : sig
|
||||||
|
|
||||||
type block = [
|
type block = [
|
||||||
@ -57,8 +63,15 @@ module Blocks : sig
|
|||||||
(unit, unit * block, unit, Time.t) RPC.service
|
(unit, unit * block, unit, Time.t) RPC.service
|
||||||
val fitness:
|
val fitness:
|
||||||
(unit, unit * block, unit, MBytes.t list) RPC.service
|
(unit, unit * block, unit, MBytes.t list) RPC.service
|
||||||
|
|
||||||
|
type operations_param = {
|
||||||
|
contents: bool ;
|
||||||
|
monitor: bool ;
|
||||||
|
}
|
||||||
val operations:
|
val operations:
|
||||||
(unit, unit * block, unit, Operation_hash.t list list) RPC.service
|
(unit, unit * block, operations_param,
|
||||||
|
(Operation_hash.t * Operation.t option) list list) RPC.service
|
||||||
|
|
||||||
val protocol:
|
val protocol:
|
||||||
(unit, unit * block, unit, Protocol_hash.t) RPC.service
|
(unit, unit * block, unit, Protocol_hash.t) RPC.service
|
||||||
val test_network:
|
val test_network:
|
||||||
@ -80,7 +93,7 @@ module Blocks : sig
|
|||||||
(unit, unit, list_param, block_info list list) RPC.service
|
(unit, unit, list_param, block_info list list) RPC.service
|
||||||
|
|
||||||
type preapply_param = {
|
type preapply_param = {
|
||||||
operations: Operation_hash.t list ;
|
operations: operation list ;
|
||||||
sort: bool ;
|
sort: bool ;
|
||||||
timestamp: Time.t option ;
|
timestamp: Time.t option ;
|
||||||
}
|
}
|
||||||
@ -98,25 +111,6 @@ module Blocks : sig
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module Operations : sig
|
|
||||||
|
|
||||||
val contents:
|
|
||||||
(unit, unit * Operation_hash.t list,
|
|
||||||
unit, Operation.t list) RPC.service
|
|
||||||
|
|
||||||
|
|
||||||
type list_param = {
|
|
||||||
contents: bool option ;
|
|
||||||
monitor: bool option ;
|
|
||||||
}
|
|
||||||
|
|
||||||
val list:
|
|
||||||
(unit, unit,
|
|
||||||
list_param,
|
|
||||||
(Operation_hash.t * Operation.t option) list list) RPC.service
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
module Protocols : sig
|
module Protocols : sig
|
||||||
|
|
||||||
val contents:
|
val contents:
|
||||||
@ -135,6 +129,7 @@ module Protocols : sig
|
|||||||
end
|
end
|
||||||
|
|
||||||
module Network : sig
|
module Network : sig
|
||||||
|
|
||||||
val stat :
|
val stat :
|
||||||
(unit, unit, unit, P2p.Stat.t) RPC.service
|
(unit, unit, unit, P2p.Stat.t) RPC.service
|
||||||
|
|
||||||
@ -175,6 +170,7 @@ module Network : sig
|
|||||||
val events :
|
val events :
|
||||||
(unit, unit * P2p.Peer_id.t, bool, P2p.RPC.Peer_id.Event.t list) RPC.service
|
(unit, unit * P2p.Peer_id.t, bool, P2p.RPC.Peer_id.Event.t list) RPC.service
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
val forge_block:
|
val forge_block:
|
||||||
@ -190,7 +186,7 @@ type inject_block_param = {
|
|||||||
raw: MBytes.t ;
|
raw: MBytes.t ;
|
||||||
blocking: bool ;
|
blocking: bool ;
|
||||||
force: bool ;
|
force: bool ;
|
||||||
operations: Operation_hash.t list list ;
|
operations: operation list list ;
|
||||||
}
|
}
|
||||||
|
|
||||||
val inject_block:
|
val inject_block:
|
||||||
|
@ -131,16 +131,18 @@ and 'a proto =
|
|||||||
with type validation_state = 'a)
|
with type validation_state = 'a)
|
||||||
|
|
||||||
let start_prevalidation
|
let start_prevalidation
|
||||||
~predecessor:
|
~predecessor
|
||||||
{ State.Valid_block.protocol ;
|
|
||||||
hash = predecessor ;
|
|
||||||
context = predecessor_context ;
|
|
||||||
timestamp = predecessor_timestamp ;
|
|
||||||
fitness = predecessor_fitness ;
|
|
||||||
level = predecessor_level }
|
|
||||||
~timestamp =
|
~timestamp =
|
||||||
|
let { Block_header.shell =
|
||||||
|
{ fitness = predecessor_fitness ;
|
||||||
|
timestamp = predecessor_timestamp ;
|
||||||
|
level = predecessor_level } } =
|
||||||
|
State.Block.header predecessor in
|
||||||
|
State.Block.context predecessor >>= fun predecessor_context ->
|
||||||
|
Context.get_protocol predecessor_context >>= fun protocol ->
|
||||||
|
let predecessor = State.Block.hash predecessor in
|
||||||
let (module Proto) =
|
let (module Proto) =
|
||||||
match protocol with
|
match Updater.get protocol with
|
||||||
| None -> assert false (* FIXME, this should not happen! *)
|
| None -> assert false (* FIXME, this should not happen! *)
|
||||||
| Some protocol -> protocol in
|
| Some protocol -> protocol in
|
||||||
Context.reset_test_network
|
Context.reset_test_network
|
||||||
|
@ -29,7 +29,7 @@ val preapply_result_encoding :
|
|||||||
type prevalidation_state
|
type prevalidation_state
|
||||||
|
|
||||||
val start_prevalidation :
|
val start_prevalidation :
|
||||||
predecessor: State.Valid_block.t ->
|
predecessor: State.Block.t ->
|
||||||
timestamp: Time.t ->
|
timestamp: Time.t ->
|
||||||
prevalidation_state tzresult Lwt.t
|
prevalidation_state tzresult Lwt.t
|
||||||
|
|
||||||
|
@ -9,31 +9,31 @@
|
|||||||
|
|
||||||
open Logging.Node.Prevalidator
|
open Logging.Node.Prevalidator
|
||||||
|
|
||||||
let list_pendings net_db ~from_block ~to_block old_mempool =
|
let list_pendings ~from_block ~to_block old_mempool =
|
||||||
let rec pop_blocks ancestor hash mempool =
|
let rec pop_blocks ancestor block mempool =
|
||||||
|
let hash = State.Block.hash block in
|
||||||
if Block_hash.equal hash ancestor then
|
if Block_hash.equal hash ancestor then
|
||||||
Lwt.return mempool
|
Lwt.return mempool
|
||||||
else
|
else
|
||||||
Distributed_db.Block_header.read_exn net_db hash >>= fun { shell } ->
|
State.Block.all_operation_hashes block >>= fun operations ->
|
||||||
Distributed_db.Operation_list.read_all_exn
|
|
||||||
net_db hash >>= fun operations ->
|
|
||||||
let mempool =
|
let mempool =
|
||||||
List.fold_left
|
List.fold_left
|
||||||
(List.fold_left (fun mempool h -> Operation_hash.Set.add h mempool))
|
(List.fold_left (fun mempool h -> Operation_hash.Set.add h mempool))
|
||||||
mempool operations in
|
mempool operations in
|
||||||
pop_blocks ancestor shell.predecessor mempool
|
State.Block.predecessor block >>= function
|
||||||
|
| None -> assert false
|
||||||
|
| Some predecessor -> pop_blocks ancestor predecessor mempool
|
||||||
in
|
in
|
||||||
let push_block mempool (hash, _shell) =
|
let push_block mempool block =
|
||||||
Distributed_db.Operation_list.read_all_exn
|
State.Block.all_operation_hashes block >|= fun operations ->
|
||||||
net_db hash >|= fun operations ->
|
|
||||||
List.fold_left
|
List.fold_left
|
||||||
(List.fold_left (fun mempool h -> Operation_hash.Set.remove h mempool))
|
(List.fold_left (fun mempool h -> Operation_hash.Set.remove h mempool))
|
||||||
mempool operations
|
mempool operations
|
||||||
in
|
in
|
||||||
let net_state = Distributed_db.state net_db in
|
Chain_traversal.new_blocks ~from_block ~to_block >>= fun (ancestor, path) ->
|
||||||
State.Valid_block.Current.new_blocks
|
pop_blocks
|
||||||
net_state ~from_block ~to_block >>= fun (ancestor, path) ->
|
(State.Block.hash ancestor)
|
||||||
pop_blocks ancestor from_block.hash old_mempool >>= fun mempool ->
|
from_block old_mempool >>= fun mempool ->
|
||||||
Lwt_list.fold_left_s push_block mempool path >>= fun new_mempool ->
|
Lwt_list.fold_left_s push_block mempool path >>= fun new_mempool ->
|
||||||
Lwt.return new_mempool
|
Lwt.return new_mempool
|
||||||
|
|
||||||
@ -45,14 +45,14 @@ exception Invalid_operation of Operation_hash.t
|
|||||||
open Prevalidation
|
open Prevalidation
|
||||||
|
|
||||||
type t = {
|
type t = {
|
||||||
net_db: Distributed_db.net ;
|
net_db: Distributed_db.net_db ;
|
||||||
flush: State.Valid_block.t -> unit;
|
flush: State.Block.t -> unit;
|
||||||
notify_operations: P2p.Peer_id.t -> Operation_hash.t list -> unit ;
|
notify_operations: P2p.Peer_id.t -> Operation_hash.t list -> unit ;
|
||||||
prevalidate_operations:
|
prevalidate_operations:
|
||||||
bool -> Operation.t list ->
|
bool -> Operation.t list ->
|
||||||
(Operation_hash.t list * error preapply_result) tzresult Lwt.t ;
|
(Operation_hash.t list * error preapply_result) tzresult Lwt.t ;
|
||||||
operations: unit -> error preapply_result * Operation_hash.Set.t ;
|
operations: unit -> error preapply_result * Operation_hash.Set.t ;
|
||||||
pending: ?block:State.Valid_block.t -> unit -> Operation_hash.Set.t Lwt.t ;
|
pending: ?block:State.Block.t -> unit -> Operation_hash.Set.t Lwt.t ;
|
||||||
timestamp: unit -> Time.t ;
|
timestamp: unit -> Time.t ;
|
||||||
context: unit -> Updater.validation_result tzresult Lwt.t ;
|
context: unit -> Updater.validation_result tzresult Lwt.t ;
|
||||||
shutdown: unit -> unit Lwt.t ;
|
shutdown: unit -> unit Lwt.t ;
|
||||||
@ -71,15 +71,14 @@ let create net_db =
|
|||||||
let cancelation, cancel, _on_cancel = Lwt_utils.canceler () in
|
let cancelation, cancel, _on_cancel = Lwt_utils.canceler () in
|
||||||
let push_to_worker, worker_waiter = Lwt_utils.queue () in
|
let push_to_worker, worker_waiter = Lwt_utils.queue () in
|
||||||
|
|
||||||
State.Valid_block.Current.head net_state >>= fun head ->
|
Chain.head net_state >>= fun head ->
|
||||||
State.Operation.list_pending net_state >>= fun initial_mempool ->
|
|
||||||
let timestamp = ref (Time.now ()) in
|
let timestamp = ref (Time.now ()) in
|
||||||
(start_prevalidation head !timestamp >|= ref) >>= fun validation_state ->
|
(start_prevalidation head !timestamp >|= ref) >>= fun validation_state ->
|
||||||
let pending = Operation_hash.Table.create 53 in
|
let pending = Operation_hash.Table.create 53 in
|
||||||
let head = ref head in
|
let head = ref head in
|
||||||
let operations = ref empty_result in
|
let operations = ref empty_result in
|
||||||
let running_validation = ref Lwt.return_unit in
|
let running_validation = ref Lwt.return_unit in
|
||||||
let unprocessed = ref initial_mempool in
|
let unprocessed = ref Operation_hash.Set.empty in
|
||||||
let broadcast_unprocessed = ref false in
|
let broadcast_unprocessed = ref false in
|
||||||
|
|
||||||
let set_validation_state state =
|
let set_validation_state state =
|
||||||
@ -92,7 +91,8 @@ let create net_db =
|
|||||||
Lwt.return_unit in
|
Lwt.return_unit in
|
||||||
|
|
||||||
let broadcast_operation ops =
|
let broadcast_operation ops =
|
||||||
Distributed_db.broadcast_head net_db !head.hash ops in
|
let hash = State.Block.hash !head in
|
||||||
|
Distributed_db.broadcast_head net_db hash ops in
|
||||||
|
|
||||||
let handle_unprocessed () =
|
let handle_unprocessed () =
|
||||||
if Operation_hash.Set.is_empty !unprocessed then
|
if Operation_hash.Set.is_empty !unprocessed then
|
||||||
@ -108,7 +108,7 @@ let create net_db =
|
|||||||
begin
|
begin
|
||||||
Lwt_list.map_p
|
Lwt_list.map_p
|
||||||
(fun h ->
|
(fun h ->
|
||||||
Distributed_db.Operation.read net_db h >>= function
|
Distributed_db.Operation.read_opt net_db h >>= function
|
||||||
| None -> Lwt.return_none
|
| None -> Lwt.return_none
|
||||||
| Some po -> Lwt.return_some (h, po))
|
| Some po -> Lwt.return_some (h, po))
|
||||||
(Operation_hash.Set.elements ops) >>= fun rops ->
|
(Operation_hash.Set.elements ops) >>= fun rops ->
|
||||||
@ -184,28 +184,28 @@ let create net_db =
|
|||||||
prevalidate validation_state ~sort:true rops >>=? fun (state, res) ->
|
prevalidate validation_state ~sort:true rops >>=? fun (state, res) ->
|
||||||
let register h =
|
let register h =
|
||||||
let op = Operation_hash.Map.find h ops in
|
let op = Operation_hash.Map.find h ops in
|
||||||
Distributed_db.Operation.inject
|
Distributed_db.inject_operation
|
||||||
net_db h op >>= fun _ ->
|
net_db h op >>=? fun (_ : bool) ->
|
||||||
Lwt.return_unit in
|
return () in
|
||||||
Lwt_list.iter_s
|
iter_s
|
||||||
(fun h ->
|
(fun h ->
|
||||||
register h >>= fun () ->
|
register h >>=? fun () ->
|
||||||
operations :=
|
operations :=
|
||||||
{ !operations with
|
{ !operations with
|
||||||
applied = h :: !operations.applied };
|
applied = h :: !operations.applied };
|
||||||
Lwt.return_unit )
|
return () )
|
||||||
res.applied >>= fun () ->
|
res.applied >>=? fun () ->
|
||||||
broadcast_operation res.applied ;
|
broadcast_operation res.applied ;
|
||||||
begin
|
begin
|
||||||
if force then
|
if force then
|
||||||
Lwt_list.iter_p
|
iter_p
|
||||||
(fun (h, _exns) -> register h)
|
(fun (h, _exns) -> register h)
|
||||||
(Operation_hash.Map.bindings
|
(Operation_hash.Map.bindings
|
||||||
res.branch_delayed) >>= fun () ->
|
res.branch_delayed) >>=? fun () ->
|
||||||
Lwt_list.iter_p
|
iter_p
|
||||||
(fun (h, _exns) -> register h)
|
(fun (h, _exns) -> register h)
|
||||||
(Operation_hash.Map.bindings
|
(Operation_hash.Map.bindings
|
||||||
res.branch_refused) >>= fun () ->
|
res.branch_refused) >>=? fun () ->
|
||||||
operations :=
|
operations :=
|
||||||
{ !operations with
|
{ !operations with
|
||||||
branch_delayed =
|
branch_delayed =
|
||||||
@ -215,10 +215,10 @@ let create net_db =
|
|||||||
Operation_hash.Map.merge merge
|
Operation_hash.Map.merge merge
|
||||||
!operations.branch_refused res.branch_refused ;
|
!operations.branch_refused res.branch_refused ;
|
||||||
} ;
|
} ;
|
||||||
Lwt.return_unit
|
return ()
|
||||||
else
|
else
|
||||||
Lwt.return_unit
|
return ()
|
||||||
end >>= fun () ->
|
end >>=? fun () ->
|
||||||
set_validation_state (Ok state) >>= fun () ->
|
set_validation_state (Ok state) >>= fun () ->
|
||||||
return res
|
return res
|
||||||
in
|
in
|
||||||
@ -236,7 +236,7 @@ let create net_db =
|
|||||||
(fun op -> Operation_hash.Table.mem pending op) new_ops in
|
(fun op -> Operation_hash.Table.mem pending op) new_ops in
|
||||||
let fetch op =
|
let fetch op =
|
||||||
Distributed_db.Operation.fetch
|
Distributed_db.Operation.fetch
|
||||||
net_db ~peer:gid op >>= fun _op ->
|
net_db ~peer:gid op () >>= fun _op ->
|
||||||
push_to_worker (`Handle op) ;
|
push_to_worker (`Handle op) ;
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
in
|
in
|
||||||
@ -245,7 +245,7 @@ let create net_db =
|
|||||||
unknown_ops ;
|
unknown_ops ;
|
||||||
List.iter (fun op ->
|
List.iter (fun op ->
|
||||||
Lwt.ignore_result
|
Lwt.ignore_result
|
||||||
(Distributed_db.Operation.fetch net_db ~peer:gid op))
|
(Distributed_db.Operation.fetch net_db ~peer:gid op ()))
|
||||||
known_ops ;
|
known_ops ;
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
| `Handle op ->
|
| `Handle op ->
|
||||||
@ -255,12 +255,11 @@ let create net_db =
|
|||||||
unprocessed := Operation_hash.Set.singleton op ;
|
unprocessed := Operation_hash.Set.singleton op ;
|
||||||
lwt_debug "register %a" Operation_hash.pp_short op >>= fun () ->
|
lwt_debug "register %a" Operation_hash.pp_short op >>= fun () ->
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
| `Flush (new_head : State.Valid_block.t) ->
|
| `Flush (new_head : State.Block.t) ->
|
||||||
list_pendings
|
list_pendings ~from_block:!head ~to_block:new_head
|
||||||
net_db ~from_block:!head ~to_block:new_head
|
|
||||||
(preapply_result_operations !operations) >>= fun new_mempool ->
|
(preapply_result_operations !operations) >>= fun new_mempool ->
|
||||||
lwt_debug "flush %a (mempool: %d)"
|
lwt_debug "flush %a (mempool: %d)"
|
||||||
Block_hash.pp_short new_head.hash
|
Block_hash.pp_short (State.Block.hash new_head)
|
||||||
(Operation_hash.Set.cardinal new_mempool) >>= fun () ->
|
(Operation_hash.Set.cardinal new_mempool) >>= fun () ->
|
||||||
(* Reset the pre-validation context *)
|
(* Reset the pre-validation context *)
|
||||||
head := new_head ;
|
head := new_head ;
|
||||||
@ -306,8 +305,7 @@ let create net_db =
|
|||||||
let ops = preapply_result_operations !operations in
|
let ops = preapply_result_operations !operations in
|
||||||
match block with
|
match block with
|
||||||
| None -> Lwt.return ops
|
| None -> Lwt.return ops
|
||||||
| Some to_block ->
|
| Some to_block -> list_pendings ~from_block:!head ~to_block ops in
|
||||||
list_pendings net_db ~from_block:!head ~to_block ops in
|
|
||||||
let context () =
|
let context () =
|
||||||
Lwt.return !validation_state >>=? fun prevalidation_state ->
|
Lwt.return !validation_state >>=? fun prevalidation_state ->
|
||||||
Prevalidation.end_prevalidation prevalidation_state in
|
Prevalidation.end_prevalidation prevalidation_state in
|
||||||
@ -345,7 +343,7 @@ let inject_operation pv ?(force = false) (op: Operation.t) =
|
|||||||
end >>=? fun errors ->
|
end >>=? fun errors ->
|
||||||
Lwt.return (Error errors) in
|
Lwt.return (Error errors) in
|
||||||
fail_unless (Net_id.equal net_id op.shell.net_id)
|
fail_unless (Net_id.equal net_id op.shell.net_id)
|
||||||
(Unclassified
|
(failure
|
||||||
"Prevalidator.inject_operation: invalid network") >>=? fun () ->
|
"Prevalidator.inject_operation: invalid network") >>=? fun () ->
|
||||||
pv.prevalidate_operations force [op] >>=? function
|
pv.prevalidate_operations force [op] >>=? function
|
||||||
| ([h], { applied = [h'] }) when Operation_hash.equal h h' ->
|
| ([h], { applied = [h'] }) when Operation_hash.equal h h' ->
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
type t
|
type t
|
||||||
|
|
||||||
(** Creation and destruction of a "prevalidation" worker. *)
|
(** Creation and destruction of a "prevalidation" worker. *)
|
||||||
val create: Distributed_db.net -> t Lwt.t
|
val create: Distributed_db.net_db -> t Lwt.t
|
||||||
val shutdown: t -> unit Lwt.t
|
val shutdown: t -> unit Lwt.t
|
||||||
|
|
||||||
val notify_operations: t -> P2p.Peer_id.t -> Operation_hash.t list -> unit
|
val notify_operations: t -> P2p.Peer_id.t -> Operation_hash.t list -> unit
|
||||||
@ -38,12 +38,11 @@ val notify_operations: t -> P2p.Peer_id.t -> Operation_hash.t list -> unit
|
|||||||
be ignored when it is (strongly) refused This is the
|
be ignored when it is (strongly) refused This is the
|
||||||
entry-point used by the P2P layer. The operation content has been
|
entry-point used by the P2P layer. The operation content has been
|
||||||
previously stored on disk. *)
|
previously stored on disk. *)
|
||||||
val inject_operation:
|
val inject_operation: t -> ?force:bool -> Operation.t -> unit tzresult Lwt.t
|
||||||
t -> ?force:bool -> Operation.t -> unit tzresult Lwt.t
|
|
||||||
|
|
||||||
val flush: t -> State.Valid_block.t -> unit
|
val flush: t -> State.Block.t -> unit
|
||||||
val timestamp: t -> Time.t
|
val timestamp: t -> Time.t
|
||||||
val operations: t -> error Prevalidation.preapply_result * Operation_hash.Set.t
|
val operations: t -> error Prevalidation.preapply_result * Operation_hash.Set.t
|
||||||
val context: t -> Updater.validation_result tzresult Lwt.t
|
val context: t -> Updater.validation_result tzresult Lwt.t
|
||||||
|
|
||||||
val pending: ?block:State.Valid_block.t -> t -> Operation_hash.Set.t Lwt.t
|
val pending: ?block:State.Block.t -> t -> Operation_hash.Set.t Lwt.t
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -7,6 +7,8 @@
|
|||||||
(* *)
|
(* *)
|
||||||
(**************************************************************************)
|
(**************************************************************************)
|
||||||
|
|
||||||
|
type t
|
||||||
|
type global_state = t
|
||||||
(** An abstraction over all the disk storage used by the node.
|
(** An abstraction over all the disk storage used by the node.
|
||||||
|
|
||||||
It encapsulates access to:
|
It encapsulates access to:
|
||||||
@ -14,14 +16,7 @@
|
|||||||
- the index of validation contexts; and
|
- the index of validation contexts; and
|
||||||
- the persistent state of the node:
|
- the persistent state of the node:
|
||||||
- the blockchain and its alternate heads of a "network";
|
- the blockchain and its alternate heads of a "network";
|
||||||
- the pool of pending operations of a "network".
|
- the pool of pending operations of a "network". *)
|
||||||
|
|
||||||
*)
|
|
||||||
type t
|
|
||||||
type global_state = t
|
|
||||||
|
|
||||||
(** Read the internal state of the node and initialize
|
|
||||||
the blocks/operations/contexts databases. *)
|
|
||||||
|
|
||||||
val read:
|
val read:
|
||||||
?patch_context:(Context.t -> Context.t Lwt.t) ->
|
?patch_context:(Context.t -> Context.t Lwt.t) ->
|
||||||
@ -29,6 +24,8 @@ val read:
|
|||||||
context_root:string ->
|
context_root:string ->
|
||||||
unit ->
|
unit ->
|
||||||
global_state tzresult Lwt.t
|
global_state tzresult Lwt.t
|
||||||
|
(** Read the internal state of the node and initialize
|
||||||
|
the databases. *)
|
||||||
|
|
||||||
val close:
|
val close:
|
||||||
global_state -> unit Lwt.t
|
global_state -> unit Lwt.t
|
||||||
@ -36,17 +33,7 @@ val close:
|
|||||||
(** {2 Errors} **************************************************************)
|
(** {2 Errors} **************************************************************)
|
||||||
|
|
||||||
type error +=
|
type error +=
|
||||||
| Invalid_fitness of { block: Block_hash.t ;
|
|
||||||
expected: Fitness.t ;
|
|
||||||
found: Fitness.t }
|
|
||||||
| Invalid_operations of { block: Block_hash.t ;
|
|
||||||
expected: Operation_list_list_hash.t ;
|
|
||||||
found: Operation_hash.t list list }
|
|
||||||
| Unknown_network of Net_id.t
|
| Unknown_network of Net_id.t
|
||||||
| Unknown_operation of Operation_hash.t
|
|
||||||
| Unknown_block of Block_hash.t
|
|
||||||
| Unknown_protocol of Protocol_hash.t
|
|
||||||
| Cannot_parse
|
|
||||||
|
|
||||||
|
|
||||||
(** {2 Network} ************************************************************)
|
(** {2 Network} ************************************************************)
|
||||||
@ -55,7 +42,7 @@ type error +=
|
|||||||
module Net : sig
|
module Net : sig
|
||||||
|
|
||||||
type t
|
type t
|
||||||
type net = t
|
type net_state = t
|
||||||
|
|
||||||
type genesis = {
|
type genesis = {
|
||||||
time: Time.t ;
|
time: Time.t ;
|
||||||
@ -64,329 +51,141 @@ module Net : sig
|
|||||||
}
|
}
|
||||||
val genesis_encoding: genesis Data_encoding.t
|
val genesis_encoding: genesis Data_encoding.t
|
||||||
|
|
||||||
(** Initialize a network for a given [genesis]. By default,
|
|
||||||
the network does accept forking test network. When
|
|
||||||
[~allow_forked_network:true] is provided, test network are allowed. *)
|
|
||||||
val create:
|
val create:
|
||||||
global_state ->
|
global_state ->
|
||||||
?allow_forked_network:bool ->
|
?allow_forked_network:bool ->
|
||||||
genesis -> net Lwt.t
|
genesis -> net_state Lwt.t
|
||||||
|
(** Initialize a network for a given [genesis]. By default,
|
||||||
|
the network does accept forking test network. When
|
||||||
|
[~allow_forked_network:true] is provided, test network are allowed. *)
|
||||||
|
|
||||||
|
val get: global_state -> Net_id.t -> net_state tzresult Lwt.t
|
||||||
(** Look up for a network by the hash of its genesis block. *)
|
(** Look up for a network by the hash of its genesis block. *)
|
||||||
val get: global_state -> Net_id.t -> net tzresult Lwt.t
|
|
||||||
|
|
||||||
|
val all: global_state -> net_state list Lwt.t
|
||||||
(** Returns all the known networks. *)
|
(** Returns all the known networks. *)
|
||||||
val all: global_state -> net list Lwt.t
|
|
||||||
|
|
||||||
|
val destroy: global_state -> net_state -> unit Lwt.t
|
||||||
(** Destroy a network: this completly removes from the local storage all
|
(** Destroy a network: this completly removes from the local storage all
|
||||||
the data associated to the network (this includes blocks and
|
the data associated to the network (this includes blocks and
|
||||||
operations). *)
|
operations). *)
|
||||||
val destroy: global_state -> net -> unit Lwt.t
|
|
||||||
|
|
||||||
|
val id: net_state -> Net_id.t
|
||||||
|
val genesis: net_state -> genesis
|
||||||
|
val expiration: net_state -> Time.t option
|
||||||
|
val allow_forked_network: net_state -> bool
|
||||||
(** Accessors. Respectively access to;
|
(** Accessors. Respectively access to;
|
||||||
- the network id (the hash of its genesis block)
|
- the network id (the hash of its genesis block)
|
||||||
- its optional expiration time
|
- its optional expiration time
|
||||||
- the associated global state. *)
|
- the associated global state. *)
|
||||||
val id: net -> Net_id.t
|
|
||||||
val genesis: net -> genesis
|
|
||||||
val expiration: net -> Time.t option
|
|
||||||
val allow_forked_network: net -> bool
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
(** Shared signature for the databases of block_headers,
|
(** {2 Block database} ********************************************************)
|
||||||
operations and protocols. *)
|
|
||||||
module type DATA_STORE = sig
|
|
||||||
|
|
||||||
type store
|
module Block : sig
|
||||||
type key
|
|
||||||
type value
|
|
||||||
|
|
||||||
(** Is a value stored in the local database ? *)
|
type t
|
||||||
val known: store -> key -> bool Lwt.t
|
type block = t
|
||||||
|
|
||||||
(** Read a value in the local database. *)
|
val known_valid: Net.t -> Block_hash.t -> bool Lwt.t
|
||||||
val read: store -> key -> value tzresult Lwt.t
|
val known_invalid: Net.t -> Block_hash.t -> bool Lwt.t
|
||||||
val read_opt: store -> key -> value option Lwt.t
|
|
||||||
val read_exn: store -> key -> value Lwt.t
|
|
||||||
|
|
||||||
(** Read a value in the local database (without parsing). *)
|
val read: Net.t -> Block_hash.t -> block tzresult Lwt.t
|
||||||
val read_raw: store -> key -> MBytes.t tzresult Lwt.t
|
val read_opt: Net.t -> Block_hash.t -> block option Lwt.t
|
||||||
val read_raw_opt: store -> key -> MBytes.t option Lwt.t
|
val read_exn: Net.t -> Block_hash.t -> block Lwt.t
|
||||||
val read_raw_exn: store -> key -> MBytes.t Lwt.t
|
|
||||||
|
|
||||||
(** Read data discovery time (the time when `store` was called). *)
|
|
||||||
val read_discovery_time: store -> key -> Time.t tzresult Lwt.t
|
|
||||||
val read_discovery_time_opt: store -> key -> Time.t option Lwt.t
|
|
||||||
val read_discovery_time_exn: store -> key -> Time.t Lwt.t
|
|
||||||
|
|
||||||
(** Store a value in the local database (pre-parsed value). It
|
|
||||||
returns [false] when the value is already stored, or [true]
|
|
||||||
otherwise. For a given value, only one call to `store` (or an
|
|
||||||
equivalent call to `store_raw`) might return [true]. *)
|
|
||||||
val store: store -> key -> value -> bool Lwt.t
|
|
||||||
|
|
||||||
(** Store a value in the local database (unparsed data). It returns
|
|
||||||
[Ok None] when the data is already stored, or [Ok (Some (hash,
|
|
||||||
value))] otherwise. For a given data, only one call to
|
|
||||||
`store_raw` (or an equivalent call to `store`) might return [Ok
|
|
||||||
(Some _)]. It may return [Error] when the shell part of the value
|
|
||||||
cannot be parsed. *)
|
|
||||||
val store_raw: store -> key -> MBytes.t -> value option tzresult Lwt.t
|
|
||||||
|
|
||||||
(** Remove a value from the local database. *)
|
|
||||||
val remove: store -> key -> bool Lwt.t
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
(** {2 Block_header database} *************************************************)
|
|
||||||
|
|
||||||
module Block_header : sig
|
|
||||||
|
|
||||||
include DATA_STORE with type store = Net.t
|
|
||||||
and type key = Block_hash.t
|
|
||||||
and type value := Block_header.t
|
|
||||||
|
|
||||||
val mark_invalid: Net.t -> Block_hash.t -> error list -> bool Lwt.t
|
|
||||||
|
|
||||||
val invalid: Net.t -> Block_hash.t -> error list option Lwt.t
|
|
||||||
val pending: Net.t -> Block_hash.t -> bool Lwt.t
|
|
||||||
|
|
||||||
val list_pending: Net.t -> Block_hash.Set.t Lwt.t
|
|
||||||
val list_invalid: Net.t -> Block_hash.Set.t Lwt.t
|
|
||||||
|
|
||||||
module Helpers : sig
|
|
||||||
|
|
||||||
(** If [h1] is an ancestor of [h2] in the current [state],
|
|
||||||
then [path state h1 h2] returns the chain of block from
|
|
||||||
[h1] (excluded) to [h2] (included). *)
|
|
||||||
val path:
|
|
||||||
Net.t -> Block_hash.t -> Block_hash.t ->
|
|
||||||
(Block_hash.t * Block_header.shell_header) list tzresult Lwt.t
|
|
||||||
|
|
||||||
(** [common_ancestor state h1 h2] returns the first common ancestors
|
|
||||||
in the history of blocks [h1] and [h2]. *)
|
|
||||||
val common_ancestor:
|
|
||||||
Net.t -> Block_hash.t -> Block_hash.t ->
|
|
||||||
(Block_hash.t * Block_header.shell_header) tzresult Lwt.t
|
|
||||||
|
|
||||||
(** [block_locator state max_length h] compute the sparse block locator
|
|
||||||
(/à la/ Bitcoin) for the block [h]. *)
|
|
||||||
val block_locator:
|
|
||||||
Net.t -> int -> Block_hash.t -> Block_hash.t list tzresult Lwt.t
|
|
||||||
|
|
||||||
(** [iter_predecessors state blocks f] iter [f] on [blocks] and
|
|
||||||
their recursive (known) predecessors. Blocks are visited with a
|
|
||||||
decreasing fitness (then decreasing timestamp). If the optional
|
|
||||||
argument [max] is provided, the iteration is stopped after [max]
|
|
||||||
visited block. If [min_fitness] id provided, blocks with a
|
|
||||||
fitness lower than [min_fitness] are ignored. If [min_date],
|
|
||||||
blocks with a fitness lower than [min_date] are ignored. *)
|
|
||||||
val iter_predecessors:
|
|
||||||
Net.t ->
|
|
||||||
?max:int ->
|
|
||||||
?min_fitness:Fitness.t ->
|
|
||||||
?min_date:Time.t ->
|
|
||||||
Block_header.t list ->
|
|
||||||
f:(Block_header.t -> unit Lwt.t) ->
|
|
||||||
unit tzresult Lwt.t
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
module Operation_list : sig
|
|
||||||
|
|
||||||
type store = Net.t
|
|
||||||
type key = Block_hash.t * int
|
|
||||||
type value = Operation_hash.t list * Operation_list_list_hash.path
|
|
||||||
|
|
||||||
val known: store -> key -> bool Lwt.t
|
|
||||||
val read: store -> key -> value tzresult Lwt.t
|
|
||||||
val read_opt: store -> key -> value option Lwt.t
|
|
||||||
val read_exn: store -> key -> value Lwt.t
|
|
||||||
val store: store -> key -> value -> bool Lwt.t
|
|
||||||
val remove: store -> key -> bool Lwt.t
|
|
||||||
|
|
||||||
val read_count: store -> Block_hash.t -> int tzresult Lwt.t
|
|
||||||
val read_count_opt: store -> Block_hash.t -> int option Lwt.t
|
|
||||||
val read_count_exn: store -> Block_hash.t -> int Lwt.t
|
|
||||||
val store_count: store -> Block_hash.t -> int -> unit Lwt.t
|
|
||||||
|
|
||||||
val read_all:
|
|
||||||
store -> Block_hash.t -> Operation_hash.t list list tzresult Lwt.t
|
|
||||||
val store_all:
|
|
||||||
store -> Block_hash.t -> Operation_hash.t list list -> unit Lwt.t
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
(** {2 Valid block} ***********************************************************)
|
|
||||||
|
|
||||||
(** The local database of known-valid blocks. *)
|
|
||||||
module Valid_block : sig
|
|
||||||
|
|
||||||
(** A validated block. *)
|
|
||||||
type t = private {
|
|
||||||
net_id: Net_id.t ;
|
|
||||||
(** The genesis of the chain this block belongs to. *)
|
|
||||||
hash: Block_hash.t ;
|
|
||||||
(** The block hash. *)
|
|
||||||
level: Int32.t ;
|
|
||||||
(** The number of preceding block in the chain. *)
|
|
||||||
proto_level: int ;
|
|
||||||
(** The number of protocol amendment block in the chain (modulo 256) *)
|
|
||||||
predecessor: Block_hash.t ;
|
|
||||||
(** The preceding block in the chain. *)
|
|
||||||
timestamp: Time.t ;
|
|
||||||
(** The date at which this block has been forged. *)
|
|
||||||
fitness: Fitness.t ;
|
|
||||||
(** The (validated) score of the block. *)
|
|
||||||
operations_hash: Operation_list_list_hash.t ;
|
|
||||||
operation_hashes: Operation_hash.t list list Lwt.t Lazy.t ;
|
|
||||||
operations: Operation.t list list Lwt.t Lazy.t ;
|
|
||||||
(** The sequence of operations and its (Merkle-)hash. *)
|
|
||||||
discovery_time: Time.t ;
|
|
||||||
(** The data at which the block was discorevered on the P2P network. *)
|
|
||||||
protocol_hash: Protocol_hash.t ;
|
|
||||||
(** The protocol to be used for validating the following blocks. *)
|
|
||||||
protocol: (module Updater.REGISTRED_PROTOCOL) option ;
|
|
||||||
(** The actual implementation of the protocol to be used for
|
|
||||||
validating the following blocks. *)
|
|
||||||
test_network: Context.test_network ;
|
|
||||||
(** The current test network associated to the block. *)
|
|
||||||
context: Context.t ;
|
|
||||||
(** The validation context that was produced by the block validation. *)
|
|
||||||
proto_header: MBytes.t;
|
|
||||||
(** The uninterpreted protocol dependent part of the header. *)
|
|
||||||
}
|
|
||||||
type valid_block = t
|
|
||||||
|
|
||||||
val known: Net.t -> Block_hash.t -> bool Lwt.t
|
|
||||||
val read: Net.t -> Block_hash.t -> valid_block tzresult Lwt.t
|
|
||||||
val read_opt: Net.t -> Block_hash.t -> valid_block option Lwt.t
|
|
||||||
val read_exn: Net.t -> Block_hash.t -> valid_block Lwt.t
|
|
||||||
val store:
|
val store:
|
||||||
Net.t -> Block_hash.t -> Updater.validation_result ->
|
Net.t ->
|
||||||
valid_block option tzresult Lwt.t
|
Block_header.t ->
|
||||||
|
Operation.t list list ->
|
||||||
|
Updater.validation_result ->
|
||||||
|
block option tzresult Lwt.t
|
||||||
|
|
||||||
val watcher: Net.t -> valid_block Lwt_stream.t * Watcher.stopper
|
val store_invalid:
|
||||||
|
Net.t ->
|
||||||
|
Block_header.t ->
|
||||||
|
bool tzresult Lwt.t
|
||||||
|
|
||||||
(** The known valid heads of the network's blockchain. *)
|
val compare: t -> t -> int
|
||||||
val known_heads: Net.t -> valid_block list Lwt.t
|
val equal: t -> t -> bool
|
||||||
|
|
||||||
val fork_testnet:
|
val hash: t -> Block_hash.t
|
||||||
global_state ->
|
val header: t -> Block_header.t
|
||||||
Net.t -> valid_block ->
|
val shell_header: t -> Block_header.shell_header
|
||||||
Protocol_hash.t -> Time.t ->
|
val timestamp: t -> Time.t
|
||||||
Net.t tzresult Lwt.t
|
val fitness: t -> Fitness.t
|
||||||
|
val operation_list_count: t -> int
|
||||||
|
val net_id: t -> Net_id.t
|
||||||
|
val level: t -> Int32.t
|
||||||
|
val message: t -> string
|
||||||
|
|
||||||
module Current : sig
|
val predecessor: t -> block option Lwt.t
|
||||||
|
|
||||||
(** The genesis block of the network's blockchain. On a test network,
|
val context: t -> Context.t Lwt.t
|
||||||
the test protocol has been promoted as "main" protocol. *)
|
val protocol_hash: t -> Protocol_hash.t Lwt.t
|
||||||
val genesis: Net.t -> valid_block Lwt.t
|
val test_network: t -> Context.test_network Lwt.t
|
||||||
|
|
||||||
(** The current head of the network's blockchain. *)
|
val operation_hashes:
|
||||||
val head: Net.t -> valid_block Lwt.t
|
t -> int ->
|
||||||
|
(Operation_hash.t list * Operation_list_list_hash.path) Lwt.t
|
||||||
|
val all_operation_hashes: t -> Operation_hash.t list list Lwt.t
|
||||||
|
|
||||||
(** The current protocol of the network's blockchain. *)
|
val operations:
|
||||||
val protocol: Net.t -> (module Updater.REGISTRED_PROTOCOL) Lwt.t
|
t -> int -> (Operation.t list * Operation_list_list_hash.path) Lwt.t
|
||||||
|
val all_operations: t -> Operation.t list list Lwt.t
|
||||||
|
|
||||||
(** Record a block as the current head of the network's blockchain. *)
|
val watcher: Net.t -> block Lwt_stream.t * Watcher.stopper
|
||||||
val set_head: Net.t -> valid_block -> unit Lwt.t
|
|
||||||
|
|
||||||
val mem: Net.t -> Block_hash.t -> bool Lwt.t
|
|
||||||
|
|
||||||
(** Atomically change the current head of the network's blockchain.
|
|
||||||
This returns [true] whenever the change succeeded, or [false]
|
|
||||||
when the current head os not equal to the [old] argument. *)
|
|
||||||
val test_and_set_head:
|
|
||||||
Net.t -> old:valid_block -> valid_block -> bool Lwt.t
|
|
||||||
|
|
||||||
(** [find_new net locator max_length], where [locator] is a sparse block
|
|
||||||
locator (/à la/ Bitcoin), returns the missing block when compared
|
|
||||||
with the current branch of [net]. *)
|
|
||||||
val find_new:
|
|
||||||
Net.t -> Block_hash.t list -> int -> Block_hash.t list tzresult Lwt.t
|
|
||||||
|
|
||||||
val new_blocks:
|
|
||||||
Net.t -> from_block:valid_block -> to_block:valid_block ->
|
|
||||||
(Block_hash.t * (Block_hash.t * Tezos_data.Block_header.shell_header) list) Lwt.t
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
module Helpers : sig
|
|
||||||
|
|
||||||
(** If [h1] is an ancestor of [h2] in the current [state],
|
|
||||||
then [path state h1 h2] returns the chain of block from
|
|
||||||
[h1] (excluded) to [h2] (included). Returns [None] otherwise. *)
|
|
||||||
val path:
|
|
||||||
Net.t -> valid_block -> valid_block -> valid_block list option Lwt.t
|
|
||||||
|
|
||||||
(** [common_ancestor state h1 h2] returns the first common ancestors
|
|
||||||
in the history of blocks [h1] and [h2]. *)
|
|
||||||
val common_ancestor:
|
|
||||||
Net.t -> valid_block -> valid_block -> valid_block Lwt.t
|
|
||||||
|
|
||||||
(** [block_locator state max_length h] compute the sparse block locator
|
|
||||||
(/à la/ Bitcoin) for the block [h]. *)
|
|
||||||
val block_locator: Net.t -> int -> valid_block -> Block_hash.t list Lwt.t
|
|
||||||
|
|
||||||
(** [iter_predecessors state blocks f] iter [f] on [blocks] and
|
|
||||||
their recursive predecessors. Blocks are visited with a
|
|
||||||
decreasing fitness (then decreasing timestamp). If the optional
|
|
||||||
argument [max] is provided, the iteration is stopped after [max]
|
|
||||||
visited block. If [min_fitness] id provided, blocks with a
|
|
||||||
fitness lower than [min_fitness] are ignored. If [min_date],
|
|
||||||
blocks with a fitness lower than [min_date] are ignored. *)
|
|
||||||
val iter_predecessors:
|
|
||||||
Net.t ->
|
|
||||||
?max:int ->
|
|
||||||
?min_fitness:Fitness.t ->
|
|
||||||
?min_date:Time.t ->
|
|
||||||
valid_block list ->
|
|
||||||
f:(valid_block -> unit Lwt.t) ->
|
|
||||||
unit tzresult Lwt.t
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
val read_block:
|
||||||
|
global_state -> Block_hash.t -> Block.t option Lwt.t
|
||||||
|
|
||||||
(** {2 Operation database} ****************************************************)
|
val read_block_exn:
|
||||||
|
global_state -> Block_hash.t -> Block.t Lwt.t
|
||||||
|
|
||||||
module Operation : sig
|
val fork_testnet:
|
||||||
|
global_state -> Block.t -> Protocol_hash.t -> Time.t ->
|
||||||
|
Net.t tzresult Lwt.t
|
||||||
|
|
||||||
include DATA_STORE with type store = Net.t
|
type chain_data = {
|
||||||
and type key = Operation_hash.t
|
current_head: Block.t ;
|
||||||
and type value := Operation.t
|
}
|
||||||
|
|
||||||
val mark_invalid: Net.t -> Operation_hash.t -> error list -> bool Lwt.t
|
val read_chain_store:
|
||||||
|
Net.t ->
|
||||||
val in_chain: Net.t -> Operation_hash.t -> bool Lwt.t
|
(Store.Chain.store -> chain_data -> 'a Lwt.t) ->
|
||||||
val pending: Net.t -> Operation_hash.t -> bool Lwt.t
|
'a Lwt.t
|
||||||
val invalid: Net.t -> Operation_hash.t -> error list option Lwt.t
|
|
||||||
|
|
||||||
val list_pending: Net.t -> Operation_hash.Set.t Lwt.t
|
|
||||||
|
|
||||||
val list_invalid: Net.t -> Operation_hash.Set.t Lwt.t
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
val update_chain_store:
|
||||||
|
Net.t ->
|
||||||
|
(Store.Chain.store -> chain_data -> (chain_data option * 'a) Lwt.t) ->
|
||||||
|
'a Lwt.t
|
||||||
|
|
||||||
(** {2 Protocol database} ***************************************************)
|
(** {2 Protocol database} ***************************************************)
|
||||||
|
|
||||||
module Protocol : sig
|
module Protocol : sig
|
||||||
include DATA_STORE with type store = global_state
|
|
||||||
and type key = Protocol_hash.t
|
(** Is a value stored in the local database ? *)
|
||||||
and type value := Protocol.t
|
val known: global_state -> Protocol_hash.t -> bool Lwt.t
|
||||||
|
|
||||||
|
(** Read a value in the local database. *)
|
||||||
|
val read: global_state -> Protocol_hash.t -> Protocol.t tzresult Lwt.t
|
||||||
|
val read_opt: global_state -> Protocol_hash.t -> Protocol.t option Lwt.t
|
||||||
|
val read_exn: global_state -> Protocol_hash.t -> Protocol.t Lwt.t
|
||||||
|
|
||||||
|
(** Read a value in the local database (without parsing). *)
|
||||||
|
val read_raw: global_state -> Protocol_hash.t -> MBytes.t tzresult Lwt.t
|
||||||
|
val read_raw_opt: global_state -> Protocol_hash.t -> MBytes.t option Lwt.t
|
||||||
|
val read_raw_exn: global_state -> Protocol_hash.t -> MBytes.t Lwt.t
|
||||||
|
|
||||||
|
val store: global_state -> Protocol.t -> Protocol_hash.t option Lwt.t
|
||||||
|
|
||||||
|
(** Remove a value from the local database. *)
|
||||||
|
val remove: global_state -> Protocol_hash.t -> bool Lwt.t
|
||||||
|
|
||||||
val list: global_state -> Protocol_hash.Set.t Lwt.t
|
val list: global_state -> Protocol_hash.Set.t Lwt.t
|
||||||
|
|
||||||
(* val mark_invalid: Net.t -> Protocol_hash.t -> error list -> bool Lwt.t *)
|
|
||||||
(* val list_invalid: Net.t -> Protocol_hash.Set.t Lwt.t *)
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -16,11 +16,11 @@ type worker = {
|
|||||||
deactivate: t -> unit Lwt.t ;
|
deactivate: t -> unit Lwt.t ;
|
||||||
inject_block:
|
inject_block:
|
||||||
?force:bool ->
|
?force:bool ->
|
||||||
MBytes.t -> Operation_hash.t list list ->
|
MBytes.t -> Distributed_db.operation list list ->
|
||||||
(Block_hash.t * State.Valid_block.t tzresult Lwt.t) tzresult Lwt.t ;
|
(Block_hash.t * State.Block.t tzresult Lwt.t) tzresult Lwt.t ;
|
||||||
notify_block: Block_hash.t -> Block_header.t -> unit Lwt.t ;
|
notify_block: Block_hash.t -> Block_header.t -> unit Lwt.t ;
|
||||||
shutdown: unit -> unit Lwt.t ;
|
shutdown: unit -> unit Lwt.t ;
|
||||||
valid_block_input: State.Valid_block.t Watcher.input ;
|
valid_block_input: State.Block.t Watcher.input ;
|
||||||
db: Distributed_db.t ;
|
db: Distributed_db.t ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,18 +30,18 @@ and t = {
|
|||||||
parent: t option ;
|
parent: t option ;
|
||||||
mutable child: t option ;
|
mutable child: t option ;
|
||||||
prevalidator: Prevalidator.t ;
|
prevalidator: Prevalidator.t ;
|
||||||
net_db: Distributed_db.net ;
|
net_db: Distributed_db.net_db ;
|
||||||
notify_block: Block_hash.t -> Block_header.t -> unit Lwt.t ;
|
notify_block: Block_hash.t -> Block_header.t -> unit Lwt.t ;
|
||||||
fetch_block: Block_hash.t -> State.Valid_block.t tzresult Lwt.t ;
|
fetch_block: Block_hash.t -> State.Block.t tzresult Lwt.t ;
|
||||||
create_child:
|
create_child:
|
||||||
State.Valid_block.t -> Protocol_hash.t -> Time.t -> unit tzresult Lwt.t ;
|
State.Block.t -> Protocol_hash.t -> Time.t -> unit tzresult Lwt.t ;
|
||||||
check_child:
|
check_child:
|
||||||
Block_hash.t -> Protocol_hash.t -> Time.t -> Time.t -> unit tzresult Lwt.t ;
|
Block_hash.t -> Protocol_hash.t -> Time.t -> Time.t -> unit tzresult Lwt.t ;
|
||||||
deactivate_child: unit -> unit Lwt.t ;
|
deactivate_child: unit -> unit Lwt.t ;
|
||||||
test_validator: unit -> (t * Distributed_db.net) option ;
|
test_validator: unit -> (t * Distributed_db.net_db) option ;
|
||||||
shutdown: unit -> unit Lwt.t ;
|
shutdown: unit -> unit Lwt.t ;
|
||||||
valid_block_input: State.Valid_block.t Watcher.input ;
|
valid_block_input_for_net: State.Block.t Watcher.input ;
|
||||||
new_head_input: State.Valid_block.t Watcher.input ;
|
new_head_input: State.Block.t Watcher.input ;
|
||||||
bootstrapped: unit Lwt.t ;
|
bootstrapped: unit Lwt.t ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,13 +66,12 @@ let bootstrapped v = v.bootstrapped
|
|||||||
let fetch_protocol v hash =
|
let fetch_protocol v hash =
|
||||||
lwt_log_notice "Fetching protocol %a"
|
lwt_log_notice "Fetching protocol %a"
|
||||||
Protocol_hash.pp_short hash >>= fun () ->
|
Protocol_hash.pp_short hash >>= fun () ->
|
||||||
Distributed_db.Protocol.fetch v.worker.db hash >>= fun protocol ->
|
Distributed_db.Protocol.fetch v.worker.db hash () >>= fun protocol ->
|
||||||
Updater.compile hash protocol >>= fun valid ->
|
Updater.compile hash protocol >>= fun valid ->
|
||||||
if valid then begin
|
if valid then begin
|
||||||
lwt_log_notice "Successfully compiled protocol %a"
|
lwt_log_notice "Successfully compiled protocol %a"
|
||||||
Protocol_hash.pp_short hash >>= fun () ->
|
Protocol_hash.pp_short hash >>= fun () ->
|
||||||
Distributed_db.Protocol.commit
|
Distributed_db.commit_protocol v.worker.db hash >>=? fun _ ->
|
||||||
v.worker.db hash >>= fun () ->
|
|
||||||
return true
|
return true
|
||||||
end else begin
|
end else begin
|
||||||
lwt_log_error "Failed to compile protocol %a"
|
lwt_log_error "Failed to compile protocol %a"
|
||||||
@ -80,43 +79,49 @@ let fetch_protocol v hash =
|
|||||||
failwith "Cannot compile the protocol %a" Protocol_hash.pp_short hash
|
failwith "Cannot compile the protocol %a" Protocol_hash.pp_short hash
|
||||||
end
|
end
|
||||||
|
|
||||||
let fetch_protocols v (block: State.Valid_block.t) =
|
let fetch_protocols v (block: State.Block.t) =
|
||||||
|
State.Block.context block >>= fun context ->
|
||||||
let proto_updated =
|
let proto_updated =
|
||||||
match block.protocol with
|
Context.get_protocol context >>= fun protocol_hash ->
|
||||||
|
match Updater.get protocol_hash with
|
||||||
| Some _ -> return false
|
| Some _ -> return false
|
||||||
| None -> fetch_protocol v block.protocol_hash
|
| None -> fetch_protocol v protocol_hash
|
||||||
and test_proto_updated =
|
and test_proto_updated =
|
||||||
match block.test_network with
|
Context.get_test_network context >>= function
|
||||||
| Not_running -> return false
|
| Not_running -> return false
|
||||||
| Forking { protocol }
|
| Forking { protocol }
|
||||||
| Running { protocol } ->
|
| Running { protocol } ->
|
||||||
Distributed_db.Protocol.known v.worker.db protocol >>= fun known ->
|
match Updater.get protocol with
|
||||||
if known then return false
|
| Some _ -> return false
|
||||||
else fetch_protocol v protocol in
|
| None -> fetch_protocol v protocol in
|
||||||
proto_updated >>=? fun proto_updated ->
|
proto_updated >>=? fun proto_updated ->
|
||||||
test_proto_updated >>=? fun _test_proto_updated ->
|
test_proto_updated >>=? fun test_proto_updated ->
|
||||||
if proto_updated then
|
return (proto_updated && test_proto_updated)
|
||||||
State.Valid_block.read_exn v.net block.hash >>= return
|
|
||||||
else
|
|
||||||
return block
|
|
||||||
|
|
||||||
let rec may_set_head v (block: State.Valid_block.t) =
|
let rec may_set_head v (block: State.Block.t) =
|
||||||
State.Valid_block.Current.head v.net >>= fun head ->
|
Chain.head v.net >>= fun head ->
|
||||||
if Fitness.compare head.fitness block.fitness >= 0 then
|
let head_header = State.Block.header head
|
||||||
|
and head_hash = State.Block.hash head
|
||||||
|
and block_header = State.Block.header block
|
||||||
|
and block_hash = State.Block.hash block in
|
||||||
|
if
|
||||||
|
Fitness.compare
|
||||||
|
head_header.shell.fitness block_header.shell.fitness >= 0
|
||||||
|
then
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
else begin
|
else begin
|
||||||
State.Valid_block.Current.test_and_set_head v.net
|
Chain.test_and_set_head v.net ~old:head block >>= function
|
||||||
~old:head block >>= function
|
|
||||||
| false -> may_set_head v block
|
| false -> may_set_head v block
|
||||||
| true ->
|
| true ->
|
||||||
Distributed_db.broadcast_head v.net_db block.hash [] ;
|
Distributed_db.broadcast_head v.net_db block_hash [] ;
|
||||||
Prevalidator.flush v.prevalidator block ;
|
Prevalidator.flush v.prevalidator block ;
|
||||||
begin
|
begin
|
||||||
begin
|
begin
|
||||||
match block.test_network with
|
State.Block.test_network block >>= function
|
||||||
| Not_running -> v.deactivate_child () >>= return
|
| Not_running -> v.deactivate_child () >>= return
|
||||||
| Running { genesis ; protocol ; expiration } ->
|
| Running { genesis ; protocol ; expiration } ->
|
||||||
v.check_child genesis protocol expiration block.timestamp
|
v.check_child genesis protocol expiration
|
||||||
|
block_header.shell.timestamp
|
||||||
| Forking { protocol ; expiration } ->
|
| Forking { protocol ; expiration } ->
|
||||||
v.create_child block protocol expiration
|
v.create_child block protocol expiration
|
||||||
end >>= function
|
end >>= function
|
||||||
@ -127,11 +132,11 @@ let rec may_set_head v (block: State.Valid_block.t) =
|
|||||||
end >>= fun () ->
|
end >>= fun () ->
|
||||||
Watcher.notify v.new_head_input block ;
|
Watcher.notify v.new_head_input block ;
|
||||||
lwt_log_notice "update current head %a %a %a(%t)"
|
lwt_log_notice "update current head %a %a %a(%t)"
|
||||||
Block_hash.pp_short block.hash
|
Block_hash.pp_short block_hash
|
||||||
Fitness.pp block.fitness
|
Fitness.pp block_header.shell.fitness
|
||||||
Time.pp_hum block.timestamp
|
Time.pp_hum block_header.shell.timestamp
|
||||||
(fun ppf ->
|
(fun ppf ->
|
||||||
if Block_hash.equal head.hash block.predecessor then
|
if Block_hash.equal head_hash block_header.shell.predecessor then
|
||||||
Format.fprintf ppf "same branch"
|
Format.fprintf ppf "same branch"
|
||||||
else
|
else
|
||||||
Format.fprintf ppf "changing branch") >>= fun () ->
|
Format.fprintf ppf "changing branch") >>= fun () ->
|
||||||
@ -142,12 +147,38 @@ let rec may_set_head v (block: State.Valid_block.t) =
|
|||||||
|
|
||||||
type error +=
|
type error +=
|
||||||
| Invalid_operation of Operation_hash.t
|
| Invalid_operation of Operation_hash.t
|
||||||
|
| Invalid_fitness of { block: Block_hash.t ;
|
||||||
|
expected: Fitness.t ;
|
||||||
|
found: Fitness.t }
|
||||||
|
| Unknown_protocol
|
||||||
| Non_increasing_timestamp
|
| Non_increasing_timestamp
|
||||||
| Non_increasing_fitness
|
| Non_increasing_fitness
|
||||||
| Wrong_level of Int32.t * Int32.t
|
| Wrong_level of Int32.t * Int32.t
|
||||||
| Wrong_proto_level of int * int
|
| Wrong_proto_level of int * int
|
||||||
|
|
||||||
let () =
|
let () =
|
||||||
|
Error_monad.register_error_kind
|
||||||
|
`Permanent
|
||||||
|
~id:"validator.invalid_fitness"
|
||||||
|
~title:"Invalid fitness"
|
||||||
|
~description:"The computed fitness differs from the fitness found \
|
||||||
|
\ in the block header."
|
||||||
|
~pp:(fun ppf (block, expected, found) ->
|
||||||
|
Format.fprintf ppf
|
||||||
|
"@[<v 2>Invalid fitness for block %a@ \
|
||||||
|
\ expected %a@ \
|
||||||
|
\ found %a"
|
||||||
|
Block_hash.pp_short block
|
||||||
|
Fitness.pp expected
|
||||||
|
Fitness.pp found)
|
||||||
|
Data_encoding.(obj3
|
||||||
|
(req "block" Block_hash.encoding)
|
||||||
|
(req "expected" Fitness.encoding)
|
||||||
|
(req "found" Fitness.encoding))
|
||||||
|
(function Invalid_fitness { block ; expected ; found } ->
|
||||||
|
Some (block, expected, found) | _ -> None)
|
||||||
|
(fun (block, expected, found) ->
|
||||||
|
Invalid_fitness { block ; expected ; found }) ;
|
||||||
register_error_kind
|
register_error_kind
|
||||||
`Permanent
|
`Permanent
|
||||||
~id:"validator.wrong_level"
|
~id:"validator.wrong_level"
|
||||||
@ -175,47 +206,50 @@ let () =
|
|||||||
(function Wrong_proto_level (e, g) -> Some (e, g) | _ -> None)
|
(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))
|
||||||
|
|
||||||
let apply_block net db
|
let apply_block net_state db
|
||||||
(pred: State.Valid_block.t) hash (block: Block_header.t) =
|
(pred: State.Block.t) hash (block: Block_header.t) =
|
||||||
let id = State.Net.id net in
|
let pred_header = State.Block.header pred
|
||||||
|
and pred_hash = State.Block.hash pred in
|
||||||
|
State.Block.context pred >>= fun pred_context ->
|
||||||
|
let id = State.Net.id net_state in
|
||||||
lwt_log_notice "validate block %a (after %a), net %a"
|
lwt_log_notice "validate block %a (after %a), net %a"
|
||||||
Block_hash.pp_short hash
|
Block_hash.pp_short hash
|
||||||
Block_hash.pp_short block.shell.predecessor
|
Block_hash.pp_short block.shell.predecessor
|
||||||
Net_id.pp id
|
Net_id.pp id
|
||||||
>>= fun () ->
|
>>= fun () ->
|
||||||
fail_unless
|
fail_unless
|
||||||
(Int32.succ pred.level = block.shell.level)
|
(Int32.succ pred_header.shell.level = block.shell.level)
|
||||||
(Wrong_level (Int32.succ pred.level, block.shell.level)) >>=? fun () ->
|
(Wrong_level (Int32.succ pred_header.shell.level,
|
||||||
|
block.shell.level)) >>=? fun () ->
|
||||||
lwt_log_info "validation of %a: looking for dependencies..."
|
lwt_log_info "validation of %a: looking for dependencies..."
|
||||||
Block_hash.pp_short hash >>= fun () ->
|
Block_hash.pp_short hash >>= fun () ->
|
||||||
Distributed_db.Operation_list.fetch
|
Distributed_db.Operations.fetch
|
||||||
db (hash, 0) block.shell.operations_hash >>= fun operation_hashes ->
|
db (hash, 0) block.shell.operations_hash >>= fun operations ->
|
||||||
Lwt_list.map_p
|
let operation_hashes = List.map Operation.hash operations in
|
||||||
(fun op -> Distributed_db.Operation.fetch db op)
|
|
||||||
operation_hashes >>= fun operations ->
|
|
||||||
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 () ->
|
||||||
begin (* Are we validating a block in an expired test network ? *)
|
begin (* Are we validating a block in an expired test network ? *)
|
||||||
match State.Net.expiration net with
|
match State.Net.expiration net_state with
|
||||||
| Some eol when Time.(eol <= block.shell.timestamp) ->
|
| Some eol when Time.(eol <= block.shell.timestamp) ->
|
||||||
failwith "This test network expired..."
|
failwith "This test network expired..."
|
||||||
| None | Some _ -> return ()
|
| None | Some _ -> return ()
|
||||||
end >>=? fun () ->
|
end >>=? fun () ->
|
||||||
begin
|
begin
|
||||||
if Time.(pred.timestamp >= block.shell.timestamp) then
|
if Time.(pred_header.shell.timestamp >= block.shell.timestamp) then
|
||||||
fail Non_increasing_timestamp
|
fail Non_increasing_timestamp
|
||||||
else
|
else
|
||||||
return ()
|
return ()
|
||||||
end >>=? fun () ->
|
end >>=? fun () ->
|
||||||
begin
|
begin
|
||||||
if Fitness.compare pred.fitness block.shell.fitness >= 0 then
|
if Fitness.compare pred_header.shell.fitness block.shell.fitness >= 0 then
|
||||||
fail Non_increasing_fitness
|
fail Non_increasing_fitness
|
||||||
else
|
else
|
||||||
return ()
|
return ()
|
||||||
end >>=? fun () ->
|
end >>=? fun () ->
|
||||||
|
Context.get_protocol pred_context >>= fun pred_protocol_hash ->
|
||||||
begin
|
begin
|
||||||
match pred.protocol with
|
match Updater.get pred_protocol_hash with
|
||||||
| None -> fail (State.Unknown_protocol pred.protocol_hash)
|
| None -> fail Unknown_protocol
|
||||||
| Some p -> return p
|
| Some p -> return p
|
||||||
end >>=? fun (module Proto) ->
|
end >>=? fun (module Proto) ->
|
||||||
lwt_debug "validation of %a: Proto %a"
|
lwt_debug "validation of %a: Proto %a"
|
||||||
@ -234,11 +268,11 @@ let apply_block net db
|
|||||||
lwt_debug "validation of %a: applying block..."
|
lwt_debug "validation of %a: applying block..."
|
||||||
Block_hash.pp_short hash >>= fun () ->
|
Block_hash.pp_short hash >>= fun () ->
|
||||||
Context.reset_test_network
|
Context.reset_test_network
|
||||||
pred.context pred.hash block.shell.timestamp >>= fun context ->
|
pred_context pred_hash block.shell.timestamp >>= fun context ->
|
||||||
Proto.begin_application
|
Proto.begin_application
|
||||||
~predecessor_context:context
|
~predecessor_context:context
|
||||||
~predecessor_timestamp:pred.timestamp
|
~predecessor_timestamp:pred_header.shell.timestamp
|
||||||
~predecessor_fitness:pred.fitness
|
~predecessor_fitness:pred_header.shell.fitness
|
||||||
block >>=? fun state ->
|
block >>=? fun state ->
|
||||||
fold_left_s (fun state op ->
|
fold_left_s (fun state op ->
|
||||||
Proto.apply_operation state op >>=? fun state ->
|
Proto.apply_operation state op >>=? fun state ->
|
||||||
@ -247,13 +281,20 @@ let apply_block net db
|
|||||||
Proto.finalize_block state >>=? fun new_context ->
|
Proto.finalize_block state >>=? fun new_context ->
|
||||||
Context.get_protocol new_context.context >>= fun new_protocol ->
|
Context.get_protocol new_context.context >>= fun new_protocol ->
|
||||||
let expected_proto_level =
|
let expected_proto_level =
|
||||||
if Protocol_hash.equal new_protocol pred.protocol_hash then
|
if Protocol_hash.equal new_protocol pred_protocol_hash then
|
||||||
pred.proto_level
|
pred_header.shell.proto_level
|
||||||
else
|
else
|
||||||
(pred.proto_level + 1) mod 256 in
|
(pred_header.shell.proto_level + 1) mod 256 in
|
||||||
fail_when (block.shell.proto_level <> expected_proto_level)
|
fail_when (block.shell.proto_level <> expected_proto_level)
|
||||||
(Wrong_proto_level (block.shell.proto_level, expected_proto_level))
|
(Wrong_proto_level (block.shell.proto_level, expected_proto_level))
|
||||||
>>=? fun () ->
|
>>=? fun () ->
|
||||||
|
fail_unless
|
||||||
|
(Fitness.equal new_context.fitness block.shell.fitness)
|
||||||
|
(Invalid_fitness
|
||||||
|
{ block = hash ;
|
||||||
|
expected = block.shell.fitness ;
|
||||||
|
found = new_context.fitness ;
|
||||||
|
}) >>=? fun () ->
|
||||||
lwt_log_info "validation of %a: success"
|
lwt_log_info "validation of %a: success"
|
||||||
Block_hash.pp_short hash >>= fun () ->
|
Block_hash.pp_short hash >>= fun () ->
|
||||||
return new_context
|
return new_context
|
||||||
@ -263,14 +304,14 @@ let apply_block net db
|
|||||||
module Context_db = struct
|
module Context_db = struct
|
||||||
|
|
||||||
type key = Block_hash.t
|
type key = Block_hash.t
|
||||||
type value = State.Valid_block.t
|
type value = State.Block.t
|
||||||
|
|
||||||
type data =
|
type data =
|
||||||
{ validator: t ;
|
{ validator: t ;
|
||||||
state: [ `Inited of Block_header.t tzresult
|
state: [ `Inited of Block_header.t tzresult
|
||||||
| `Initing of Block_header.t tzresult Lwt.t
|
| `Initing of Block_header.t tzresult Lwt.t
|
||||||
| `Running of State.Valid_block.t tzresult Lwt.t ] ;
|
| `Running of State.Block.t tzresult Lwt.t ] ;
|
||||||
wakener: State.Valid_block.t tzresult Lwt.u }
|
wakener: State.Block.t tzresult Lwt.u }
|
||||||
|
|
||||||
type context =
|
type context =
|
||||||
{ tbl : data Block_hash.Table.t ;
|
{ tbl : data Block_hash.Table.t ;
|
||||||
@ -278,7 +319,7 @@ module Context_db = struct
|
|||||||
worker_trigger: unit -> unit;
|
worker_trigger: unit -> unit;
|
||||||
worker_waiter: unit -> unit Lwt.t ;
|
worker_waiter: unit -> unit Lwt.t ;
|
||||||
worker: unit Lwt.t ;
|
worker: unit Lwt.t ;
|
||||||
net_db : Distributed_db.net ;
|
net_db : Distributed_db.net_db ;
|
||||||
net_state : State.Net.t }
|
net_state : State.Net.t }
|
||||||
|
|
||||||
let pending_requests { tbl } =
|
let pending_requests { tbl } =
|
||||||
@ -296,7 +337,7 @@ module Context_db = struct
|
|||||||
assert (not (Block_hash.Table.mem tbl hash));
|
assert (not (Block_hash.Table.mem tbl hash));
|
||||||
let waiter, wakener = Lwt.wait () in
|
let waiter, wakener = Lwt.wait () in
|
||||||
let data =
|
let data =
|
||||||
Distributed_db.Block_header.fetch net_db hash >>= return in
|
Distributed_db.Block_header.fetch net_db hash () >>= return in
|
||||||
match Lwt.state data with
|
match Lwt.state data with
|
||||||
| Lwt.Return data ->
|
| Lwt.Return data ->
|
||||||
let state = `Inited data in
|
let state = `Inited data in
|
||||||
@ -317,71 +358,61 @@ module Context_db = struct
|
|||||||
|
|
||||||
let prefetch validator ({ net_state ; tbl } as session) hash =
|
let prefetch validator ({ net_state ; tbl } as session) hash =
|
||||||
Lwt.ignore_result
|
Lwt.ignore_result
|
||||||
(State.Valid_block.known net_state hash >>= fun exists ->
|
(State.Block.known_valid net_state hash >>= fun exists ->
|
||||||
if not exists && not (Block_hash.Table.mem tbl hash) then
|
if not exists && not (Block_hash.Table.mem tbl hash) then
|
||||||
request validator session hash >>= fun _ -> Lwt.return_unit
|
request validator session hash >>= fun _ -> Lwt.return_unit
|
||||||
else
|
else
|
||||||
Lwt.return_unit)
|
Lwt.return_unit)
|
||||||
|
|
||||||
let known { net_state } hash =
|
let known { net_state } hash =
|
||||||
State.Valid_block.known net_state hash
|
State.Block.known_valid net_state hash
|
||||||
|
|
||||||
let read { net_state } hash =
|
let read { net_state } hash =
|
||||||
State.Valid_block.read net_state hash
|
State.Block.read net_state hash
|
||||||
|
|
||||||
let fetch ({ net_state ; tbl } as session) validator hash =
|
let fetch ({ net_state ; tbl } as session) validator hash =
|
||||||
try Lwt.waiter_of_wakener (Block_hash.Table.find tbl hash).wakener
|
try Lwt.waiter_of_wakener (Block_hash.Table.find tbl hash).wakener
|
||||||
with Not_found ->
|
with Not_found ->
|
||||||
State.Valid_block.read_opt net_state hash >>= function
|
State.Block.known_invalid net_state hash >>= fun known_invalid ->
|
||||||
| Some op ->
|
if known_invalid then
|
||||||
Lwt.return (Ok op)
|
Lwt.return (Error [failure "Invalid predecessor"])
|
||||||
| None ->
|
else
|
||||||
try Lwt.waiter_of_wakener (Block_hash.Table.find tbl hash).wakener
|
State.Block.read_opt net_state hash >>= function
|
||||||
with Not_found -> request validator session hash
|
| Some op ->
|
||||||
|
Lwt.return (Ok op)
|
||||||
|
| None ->
|
||||||
|
try Lwt.waiter_of_wakener (Block_hash.Table.find tbl hash).wakener
|
||||||
|
with Not_found -> request validator session hash
|
||||||
|
|
||||||
let store { net_state ; net_db ; tbl } hash data =
|
let store { net_db ; tbl } hash data =
|
||||||
begin
|
begin
|
||||||
match data with
|
match data with
|
||||||
| Ok data ->
|
| Ok data -> begin
|
||||||
Distributed_db.Block_header.commit net_db hash >>= fun () ->
|
Distributed_db.commit_block net_db hash 1 data >>=? function
|
||||||
Distributed_db.Operation_list.commit_all
|
| None ->
|
||||||
net_db hash 1 >>= fun () ->
|
(* Should not happen if the block is not validated twice *)
|
||||||
begin
|
assert false
|
||||||
State.Valid_block.store net_state hash data >>=? function
|
| Some block ->
|
||||||
| None ->
|
return (Ok block)
|
||||||
State.Valid_block.read net_state hash >>=? fun block ->
|
|
||||||
Lazy.force block.operation_hashes >>= fun ophs ->
|
|
||||||
Lwt_list.iter_p
|
|
||||||
(Lwt_list.iter_p (fun hash ->
|
|
||||||
Distributed_db.Operation.commit net_db hash))
|
|
||||||
ophs >>= fun () ->
|
|
||||||
return (Ok block, false)
|
|
||||||
| Some block ->
|
|
||||||
Lazy.force block.operation_hashes >>= fun ophs ->
|
|
||||||
Lwt_list.iter_p
|
|
||||||
(Lwt_list.iter_p (fun hash ->
|
|
||||||
Distributed_db.Operation.commit net_db hash))
|
|
||||||
ophs >>= fun () ->
|
|
||||||
return (Ok block, true)
|
|
||||||
end
|
end
|
||||||
| Error err ->
|
| Error err ->
|
||||||
State.Block_header.mark_invalid
|
Distributed_db.commit_invalid_block net_db hash 1 >>=? fun changed ->
|
||||||
net_state hash err >>= fun changed ->
|
assert changed ;
|
||||||
return (Error err, changed)
|
return (Error err)
|
||||||
end >>= function
|
end >>= function
|
||||||
| Ok (block, changed) ->
|
| Ok block ->
|
||||||
let wakener = (Block_hash.Table.find tbl hash).wakener in
|
let wakener = (Block_hash.Table.find tbl hash).wakener in
|
||||||
Block_hash.Table.remove tbl hash;
|
Block_hash.Table.remove tbl hash;
|
||||||
Lwt.wakeup wakener block ;
|
Lwt.wakeup wakener block ;
|
||||||
Lwt.return changed
|
Lwt.return_unit
|
||||||
| Error _ as err ->
|
| Error _ as err ->
|
||||||
let wakener = (Block_hash.Table.find tbl hash).wakener in
|
let wakener = (Block_hash.Table.find tbl hash).wakener in
|
||||||
Block_hash.Table.remove tbl hash;
|
Block_hash.Table.remove tbl hash;
|
||||||
Lwt.wakeup wakener err ;
|
Lwt.wakeup wakener err ;
|
||||||
Lwt.return false
|
Lwt.return_unit
|
||||||
|
|
||||||
let process (v:t) ~get_context ~set_context hash block =
|
let process (v:t) ~get_context ~set_context hash block =
|
||||||
let state = Distributed_db.state v.net_db in
|
let net_state = Distributed_db.state v.net_db in
|
||||||
get_context v block.Block_header.shell.predecessor >>= function
|
get_context v block.Block_header.shell.predecessor >>= function
|
||||||
| Error _ as error ->
|
| Error _ as error ->
|
||||||
set_context v hash (Error [(* TODO *)]) >>= fun () ->
|
set_context v hash (Error [(* TODO *)]) >>= fun () ->
|
||||||
@ -389,14 +420,15 @@ module Context_db = struct
|
|||||||
| Ok _context ->
|
| Ok _context ->
|
||||||
lwt_debug "process %a" Block_hash.pp_short hash >>= fun () ->
|
lwt_debug "process %a" Block_hash.pp_short hash >>= fun () ->
|
||||||
begin
|
begin
|
||||||
State.Valid_block.Current.genesis state >>= fun genesis ->
|
Chain.genesis net_state >>= fun genesis ->
|
||||||
if Block_hash.equal genesis.hash block.shell.predecessor then
|
if Block_hash.equal (State.Block.hash genesis)
|
||||||
|
block.shell.predecessor then
|
||||||
Lwt.return genesis
|
Lwt.return genesis
|
||||||
else
|
else
|
||||||
State.Valid_block.read_exn state block.shell.predecessor
|
State.Block.read_exn net_state block.shell.predecessor
|
||||||
end >>= fun pred ->
|
end >>= fun pred ->
|
||||||
apply_block state v.net_db pred hash block >>= function
|
apply_block net_state v.net_db pred hash block >>= function
|
||||||
| Error ([State.Unknown_protocol _] as err) as error ->
|
| Error ([Unknown_protocol] as err) as error ->
|
||||||
lwt_log_error
|
lwt_log_error
|
||||||
"@[<v 2>Ignoring block %a@ %a@]"
|
"@[<v 2>Ignoring block %a@ %a@]"
|
||||||
Block_hash.pp_short hash
|
Block_hash.pp_short hash
|
||||||
@ -411,10 +443,10 @@ module Context_db = struct
|
|||||||
| Ok new_context ->
|
| Ok new_context ->
|
||||||
(* The sanity check `set_context` detects differences
|
(* The sanity check `set_context` detects differences
|
||||||
between the computed fitness and the fitness announced
|
between the computed fitness and the fitness announced
|
||||||
in the block header. Then `Valid_block.read` will
|
in the block header. Then `Block.read` will
|
||||||
return an error. *)
|
return an error. *)
|
||||||
set_context v hash (Ok new_context) >>= fun () ->
|
set_context v hash (Ok new_context) >>= fun () ->
|
||||||
State.Valid_block.read state hash >>= function
|
State.Block.read net_state hash >>= function
|
||||||
| Error err as error ->
|
| Error err as error ->
|
||||||
lwt_log_error
|
lwt_log_error
|
||||||
"@[<v 2>Ignoring block %a@ %a@]"
|
"@[<v 2>Ignoring block %a@ %a@]"
|
||||||
@ -426,8 +458,8 @@ module Context_db = struct
|
|||||||
"validation of %a: reevaluate current block"
|
"validation of %a: reevaluate current block"
|
||||||
Block_hash.pp_short hash >>= fun () ->
|
Block_hash.pp_short hash >>= fun () ->
|
||||||
Watcher.notify v.worker.valid_block_input block ;
|
Watcher.notify v.worker.valid_block_input block ;
|
||||||
Watcher.notify v.valid_block_input block ;
|
Watcher.notify v.valid_block_input_for_net block ;
|
||||||
fetch_protocols v block >>=? fun block ->
|
fetch_protocols v block >>=? fun _fetched ->
|
||||||
may_set_head v block >>= fun () ->
|
may_set_head v block >>= fun () ->
|
||||||
return block
|
return block
|
||||||
|
|
||||||
@ -523,15 +555,15 @@ let rec create_validator ?max_ttl ?parent worker state db net =
|
|||||||
Lwt.async (fun () -> Lwt_pipe.push queue (`Branch (gid, locator)))
|
Lwt.async (fun () -> Lwt_pipe.push queue (`Branch (gid, locator)))
|
||||||
end ;
|
end ;
|
||||||
current_branch = begin fun size ->
|
current_branch = begin fun size ->
|
||||||
State.Valid_block.Current.head net >>= fun head ->
|
Chain.head net >>= fun head ->
|
||||||
State.Valid_block.Helpers.block_locator net size head
|
Chain_traversal.block_locator head size
|
||||||
end ;
|
end ;
|
||||||
notify_head = begin fun gid block ops ->
|
notify_head = begin fun gid block ops ->
|
||||||
Lwt.async (fun () -> Lwt_pipe.push queue (`Head (gid, block, ops))) ;
|
Lwt.async (fun () -> Lwt_pipe.push queue (`Head (gid, block, ops))) ;
|
||||||
end ;
|
end ;
|
||||||
current_head = begin fun size ->
|
current_head = begin fun size ->
|
||||||
State.Valid_block.Current.head net >>= fun head ->
|
Chain.head net >>= fun head ->
|
||||||
Lwt.return (head.hash, Utils.list_sub (!current_ops ()) size)
|
Lwt.return (State.Block.hash head, Utils.list_sub (!current_ops ()) size)
|
||||||
end ;
|
end ;
|
||||||
disconnection = (fun _gid -> ()) ;
|
disconnection = (fun _gid -> ()) ;
|
||||||
} in
|
} in
|
||||||
@ -558,24 +590,24 @@ let rec create_validator ?max_ttl ?parent worker state db net =
|
|||||||
]
|
]
|
||||||
in
|
in
|
||||||
|
|
||||||
let valid_block_input = Watcher.create_input () in
|
let valid_block_input_for_net = Watcher.create_input () in
|
||||||
let new_head_input = Watcher.create_input () in
|
let new_head_input = Watcher.create_input () in
|
||||||
|
|
||||||
let bootstrapped =
|
let bootstrapped =
|
||||||
(* TODO improve by taking current peers count and current
|
(* TODO improve by taking current peers count and current
|
||||||
locators into account... *)
|
locators into account... *)
|
||||||
let stream, stopper =
|
let stream, stopper =
|
||||||
Watcher.create_stream valid_block_input in
|
Watcher.create_stream valid_block_input_for_net in
|
||||||
let rec wait () =
|
let rec wait () =
|
||||||
Lwt.pick [ ( Lwt_stream.get stream ) ;
|
Lwt.pick [ ( Lwt_stream.get stream ) ;
|
||||||
( Lwt_unix.sleep 30. >|= fun () -> None) ] >>= function
|
( Lwt_unix.sleep 30. >|= fun () -> None) ] >>= function
|
||||||
| Some block
|
| Some block when
|
||||||
when Time.(block.State.Valid_block.timestamp < add (Time.now ()) (-60L)) ->
|
Time.((State.Block.header block).shell.timestamp < add (Time.now ()) (-60L)) ->
|
||||||
wait ()
|
wait ()
|
||||||
| _ ->
|
| _ ->
|
||||||
State.Valid_block.Current.head net >>= fun head ->
|
Chain.head net >>= fun head ->
|
||||||
State.Valid_block.Current.genesis net >>= fun genesis ->
|
Chain.genesis net >>= fun genesis ->
|
||||||
if Block_hash.equal head.hash genesis.hash then
|
if State.Block.equal head genesis then
|
||||||
wait ()
|
wait ()
|
||||||
else
|
else
|
||||||
Lwt.return_unit in
|
Lwt.return_unit in
|
||||||
@ -602,14 +634,15 @@ let rec create_validator ?max_ttl ?parent worker state db net =
|
|||||||
test_validator ;
|
test_validator ;
|
||||||
bootstrapped ;
|
bootstrapped ;
|
||||||
new_head_input ;
|
new_head_input ;
|
||||||
valid_block_input ;
|
valid_block_input_for_net ;
|
||||||
}
|
}
|
||||||
|
|
||||||
and notify_block hash block =
|
and notify_block hash block =
|
||||||
lwt_debug "-> Validator.notify_block %a"
|
lwt_debug "-> Validator.notify_block %a"
|
||||||
Block_hash.pp_short hash >>= fun () ->
|
Block_hash.pp_short hash >>= fun () ->
|
||||||
State.Valid_block.Current.head net >>= fun head ->
|
Chain.head net >>= fun head ->
|
||||||
if Fitness.compare head.fitness block.shell.fitness <= 0 then
|
let head_header = State.Block.header head in
|
||||||
|
if Fitness.compare head_header.shell.fitness block.shell.fitness <= 0 then
|
||||||
Context_db.prefetch v session hash ;
|
Context_db.prefetch v session hash ;
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
|
|
||||||
@ -623,9 +656,9 @@ let rec create_validator ?max_ttl ?parent worker state db net =
|
|||||||
State.Net.get state net_id >>= function
|
State.Net.get state net_id >>= function
|
||||||
| Ok net_store -> return net_store
|
| Ok net_store -> return net_store
|
||||||
| Error _ ->
|
| Error _ ->
|
||||||
State.Valid_block.fork_testnet
|
State.fork_testnet
|
||||||
state net block protocol expiration >>=? fun net_store ->
|
state block protocol expiration >>=? fun net_store ->
|
||||||
State.Valid_block.Current.head net_store >>= fun block ->
|
Chain.head net_store >>= fun block ->
|
||||||
Watcher.notify v.worker.valid_block_input block ;
|
Watcher.notify v.worker.valid_block_input block ;
|
||||||
return net_store
|
return net_store
|
||||||
end >>=? fun net_store ->
|
end >>=? fun net_store ->
|
||||||
@ -654,7 +687,7 @@ let rec create_validator ?max_ttl ?parent worker state db net =
|
|||||||
match max_ttl with
|
match max_ttl with
|
||||||
| None -> Lwt.return expiration
|
| None -> Lwt.return expiration
|
||||||
| Some ttl ->
|
| Some ttl ->
|
||||||
Distributed_db.Block_header.fetch net_db genesis >>= fun genesis ->
|
Distributed_db.Block_header.fetch net_db genesis () >>= fun genesis ->
|
||||||
Lwt.return
|
Lwt.return
|
||||||
(Time.min expiration
|
(Time.min expiration
|
||||||
(Time.add genesis.shell.timestamp (Int64.of_int ttl)))
|
(Time.add genesis.shell.timestamp (Int64.of_int ttl)))
|
||||||
@ -796,29 +829,23 @@ let create_worker ?max_ttl state db =
|
|||||||
let inject_block ?(force = false) bytes operations =
|
let inject_block ?(force = false) bytes operations =
|
||||||
Distributed_db.inject_block db bytes operations >>=? fun (hash, block) ->
|
Distributed_db.inject_block db bytes operations >>=? fun (hash, block) ->
|
||||||
get block.shell.net_id >>=? fun net ->
|
get block.shell.net_id >>=? fun net ->
|
||||||
(*
|
|
||||||
Lwt_list.filter_map_s
|
|
||||||
(fun bytes ->
|
|
||||||
let hash = Operation_hash.hash_bytes [bytes] in
|
|
||||||
match Data_encoding.
|
|
||||||
Distributed_db.Operation.inject net.net_db hash bytes >>= function
|
|
||||||
| false -> Lwt.return_none
|
|
||||||
| true ->
|
|
||||||
if List.exists
|
|
||||||
(List.exists (Operation_hash.equal hash))
|
|
||||||
operations then
|
|
||||||
Lwt.return (Some hash)
|
|
||||||
else
|
|
||||||
Lwt.return_none)
|
|
||||||
injected_operations >>= fun injected_operations ->
|
|
||||||
*)
|
|
||||||
let validation =
|
let validation =
|
||||||
State.Valid_block.Current.head net.net >>= fun head ->
|
protect
|
||||||
if force
|
~on_error: begin fun err ->
|
||||||
|| Fitness.compare head.fitness block.shell.fitness <= 0 then
|
Distributed_db.remove_block
|
||||||
fetch_block net hash
|
net.net_db hash (List.length operations) >>= fun () ->
|
||||||
else
|
Lwt.return (Error err)
|
||||||
failwith "Fitness is below the current one" in
|
end
|
||||||
|
begin fun () ->
|
||||||
|
Chain.head net.net >>= fun head ->
|
||||||
|
let head_header = State.Block.header head in
|
||||||
|
if force ||
|
||||||
|
Fitness.compare head_header.shell.fitness block.shell.fitness <= 0
|
||||||
|
then
|
||||||
|
fetch_block net hash
|
||||||
|
else
|
||||||
|
failwith "Fitness is below the current one"
|
||||||
|
end in
|
||||||
return (hash, validation) in
|
return (hash, validation) in
|
||||||
|
|
||||||
let rec activate ?parent net =
|
let rec activate ?parent net =
|
||||||
@ -846,11 +873,11 @@ let create_worker ?max_ttl state db =
|
|||||||
|
|
||||||
worker
|
worker
|
||||||
|
|
||||||
let new_head_watcher ({ new_head_input } : t) =
|
let new_head_watcher { new_head_input } =
|
||||||
Watcher.create_stream new_head_input
|
Watcher.create_stream new_head_input
|
||||||
|
|
||||||
let watcher ({ valid_block_input } : t) =
|
let watcher { valid_block_input_for_net } =
|
||||||
Watcher.create_stream valid_block_input
|
Watcher.create_stream valid_block_input_for_net
|
||||||
|
|
||||||
let global_watcher ({ valid_block_input } : worker) =
|
let global_watcher ({ valid_block_input } : worker) =
|
||||||
Watcher.create_stream valid_block_input
|
Watcher.create_stream valid_block_input
|
||||||
|
@ -26,21 +26,21 @@ val get_exn: worker -> Net_id.t -> t Lwt.t
|
|||||||
val deactivate: t -> unit Lwt.t
|
val deactivate: t -> unit Lwt.t
|
||||||
|
|
||||||
val net_state: t -> State.Net.t
|
val net_state: t -> State.Net.t
|
||||||
val net_db: t -> Distributed_db.net
|
val net_db: t -> Distributed_db.net_db
|
||||||
|
|
||||||
val fetch_block:
|
val fetch_block:
|
||||||
t -> Block_hash.t -> State.Valid_block.t tzresult Lwt.t
|
t -> Block_hash.t -> State.Block.t tzresult Lwt.t
|
||||||
|
|
||||||
val inject_block:
|
val inject_block:
|
||||||
worker -> ?force:bool ->
|
worker -> ?force:bool ->
|
||||||
MBytes.t -> Operation_hash.t list list ->
|
MBytes.t -> Distributed_db.operation list list ->
|
||||||
(Block_hash.t * State.Valid_block.t tzresult Lwt.t) tzresult Lwt.t
|
(Block_hash.t * State.Block.t tzresult Lwt.t) tzresult Lwt.t
|
||||||
|
|
||||||
val prevalidator: t -> Prevalidator.t
|
val prevalidator: t -> Prevalidator.t
|
||||||
val test_validator: t -> (t * Distributed_db.net) option
|
val test_validator: t -> (t * Distributed_db.net_db) option
|
||||||
|
|
||||||
val watcher: t -> State.Valid_block.t Lwt_stream.t * Watcher.stopper
|
val watcher: t -> State.Block.t Lwt_stream.t * Watcher.stopper
|
||||||
val new_head_watcher: t -> State.Valid_block.t Lwt_stream.t * Watcher.stopper
|
val new_head_watcher: t -> State.Block.t Lwt_stream.t * Watcher.stopper
|
||||||
val global_watcher: worker -> State.Valid_block.t Lwt_stream.t * Watcher.stopper
|
val global_watcher: worker -> State.Block.t Lwt_stream.t * Watcher.stopper
|
||||||
|
|
||||||
val bootstrapped: t -> unit Lwt.t
|
val bootstrapped: t -> unit Lwt.t
|
||||||
|
@ -210,6 +210,17 @@ module Make() = struct
|
|||||||
map_s f t >>=? fun rt ->
|
map_s f t >>=? fun rt ->
|
||||||
return (rh :: rt)
|
return (rh :: rt)
|
||||||
|
|
||||||
|
let mapi_s f l =
|
||||||
|
let rec mapi_s f i l =
|
||||||
|
match l with
|
||||||
|
| [] -> return []
|
||||||
|
| h :: t ->
|
||||||
|
f i h >>=? fun rh ->
|
||||||
|
mapi_s f (i+1) t >>=? fun rt ->
|
||||||
|
return (rh :: rt)
|
||||||
|
in
|
||||||
|
mapi_s f 0 l
|
||||||
|
|
||||||
let rec map_p f l =
|
let rec map_p f l =
|
||||||
match l with
|
match l with
|
||||||
| [] ->
|
| [] ->
|
||||||
@ -224,6 +235,22 @@ module Make() = struct
|
|||||||
| Ok _, Error exn
|
| Ok _, Error exn
|
||||||
| Error exn, Ok _ -> Lwt.return (Error exn)
|
| Error exn, Ok _ -> Lwt.return (Error exn)
|
||||||
|
|
||||||
|
let mapi_p f l =
|
||||||
|
let rec mapi_p f i l =
|
||||||
|
match l with
|
||||||
|
| [] ->
|
||||||
|
return []
|
||||||
|
| x :: l ->
|
||||||
|
let tx = f i x and tl = mapi_p f (i+1) l in
|
||||||
|
tx >>= fun x ->
|
||||||
|
tl >>= fun l ->
|
||||||
|
match x, l with
|
||||||
|
| Ok x, Ok l -> Lwt.return (Ok (x :: l))
|
||||||
|
| Error exn1, Error exn2 -> Lwt.return (Error (exn1 @ exn2))
|
||||||
|
| Ok _, Error exn
|
||||||
|
| Error exn, Ok _ -> Lwt.return (Error exn) in
|
||||||
|
mapi_p f 0 l
|
||||||
|
|
||||||
let rec map2_s f l1 l2 =
|
let rec map2_s f l1 l2 =
|
||||||
match l1, l2 with
|
match l1, l2 with
|
||||||
| [], [] -> return []
|
| [], [] -> return []
|
||||||
|
@ -122,6 +122,8 @@ module type S = sig
|
|||||||
(** A {!List.map} in the monad *)
|
(** A {!List.map} in the monad *)
|
||||||
val map_s : ('a -> 'b tzresult Lwt.t) -> 'a list -> 'b list tzresult Lwt.t
|
val map_s : ('a -> 'b tzresult Lwt.t) -> 'a list -> 'b list tzresult Lwt.t
|
||||||
val map_p : ('a -> 'b tzresult Lwt.t) -> 'a list -> 'b list tzresult Lwt.t
|
val map_p : ('a -> 'b tzresult Lwt.t) -> 'a list -> 'b list tzresult Lwt.t
|
||||||
|
val mapi_s : (int -> 'a -> 'b tzresult Lwt.t) -> 'a list -> 'b list tzresult Lwt.t
|
||||||
|
val mapi_p : (int -> 'a -> 'b tzresult Lwt.t) -> 'a list -> 'b list tzresult Lwt.t
|
||||||
|
|
||||||
(** A {!List.map2} in the monad *)
|
(** A {!List.map2} in the monad *)
|
||||||
val map2 :
|
val map2 :
|
||||||
|
@ -52,11 +52,38 @@ CLIENTLIB := ${SRCDIR}/client.cmxa \
|
|||||||
${MINUTILSLIB} ${UTILSLIB} ${COMPILERLIB} ${NODELIB} ${CLIENTLIB}:
|
${MINUTILSLIB} ${UTILSLIB} ${COMPILERLIB} ${NODELIB} ${CLIENTLIB}:
|
||||||
${MAKE} -C ${SRCDIR} $@
|
${MAKE} -C ${SRCDIR} $@
|
||||||
|
|
||||||
${SRCDIR}/minutils/%: ${MINUTILSLIB}
|
${SRCDIR}/minutils/%.cmi: ${SRCDIR}/minutils/%.mli
|
||||||
${SRCDIR}/utils/%: ${UTILSLIB}
|
${MAKE} -C ${SRCDIR} minutils.cmxa
|
||||||
${SRCDIR}/compiler/%: ${COMPILERLIB}
|
${SRCDIR}/minutils/%.cmx : ${SRCDIR}/minutils/%.ml
|
||||||
${SRCDIR}/node/%: ${NODELIB}
|
${MAKE} -C ${SRCDIR} minutils.cmxa
|
||||||
${SRCDIR}/client/%: ${CLIENTLIB}
|
${SRCDIR}/utils/%.cmi: ${SRCDIR}/utils/%.mli
|
||||||
|
${MAKE} -C ${SRCDIR} utils.cmxa
|
||||||
|
${SRCDIR}/utils/%.cmx : ${SRCDIR}/utils/%.ml
|
||||||
|
${MAKE} -C ${SRCDIR} utils.cmxa
|
||||||
|
${SRCDIR}/compiler/%.cmi: ${SRCDIR}/compiler/%.mli
|
||||||
|
${MAKE} -C ${SRCDIR} compiler.cmxa
|
||||||
|
${SRCDIR}/compiler/%.cmx : ${SRCDIR}/compiler/%.ml
|
||||||
|
${MAKE} -C ${SRCDIR} compiler.cmxa
|
||||||
|
${SRCDIR}/node/db/%.cmi: ${SRCDIR}/node/db/%.mli
|
||||||
|
${MAKE} -C ${SRCDIR} node.cmxa
|
||||||
|
${SRCDIR}/node/db/%.cmx : ${SRCDIR}/node/db/%.ml
|
||||||
|
${MAKE} -C ${SRCDIR} node.cmxa
|
||||||
|
${SRCDIR}/node/net/%.cmi: ${SRCDIR}/node/net/%.mli
|
||||||
|
${MAKE} -C ${SRCDIR} node.cmxa
|
||||||
|
${SRCDIR}/node/net/%.cmx : ${SRCDIR}/node/net/%.ml
|
||||||
|
${MAKE} -C ${SRCDIR} node.cmxa
|
||||||
|
${SRCDIR}/node/shell/%.cmi: ${SRCDIR}/node/shell/%.mli
|
||||||
|
${MAKE} -C ${SRCDIR} node.cmxa
|
||||||
|
${SRCDIR}/node/shell/%.cmx : ${SRCDIR}/node/shell/%.ml
|
||||||
|
${MAKE} -C ${SRCDIR} node.cmxa
|
||||||
|
${SRCDIR}/node/updater/%.cmi: ${SRCDIR}/node/updater/%.mli
|
||||||
|
${MAKE} -C ${SRCDIR} node.cmxa
|
||||||
|
${SRCDIR}/node/updater/%.cmx : ${SRCDIR}/node/updater/%.ml
|
||||||
|
${MAKE} -C ${SRCDIR} node.cmxa
|
||||||
|
${SRCDIR}/client/%.cmi: ${SRCDIR}/client/%.mli
|
||||||
|
${MAKE} -C ${SRCDIR} client.cmxa
|
||||||
|
${SRCDIR}/client/%.cmx : ${SRCDIR}/client/%.ml
|
||||||
|
${MAKE} -C ${SRCDIR} client.cmxa
|
||||||
|
|
||||||
############################################################################
|
############################################################################
|
||||||
## Generic rules
|
## Generic rules
|
||||||
@ -82,7 +109,7 @@ partial-clean::
|
|||||||
-find . \( -name \*.cm\* -or -name \*.cmp -or -name \*.out -or -name \*~ -or -name \*.o -or -name \*.a \) -delete
|
-find . \( -name \*.cm\* -or -name \*.cmp -or -name \*.out -or -name \*~ -or -name \*.o -or -name \*.a \) -delete
|
||||||
|
|
||||||
-include .depend
|
-include .depend
|
||||||
.depend: $(shell find . -name \*.ml -or -name \*.ml)
|
.depend: $(shell find . -name \*.mli -or -name \*.ml)
|
||||||
@echo OCAMLDEP "(test/$(notdir $(shell echo $$PWD)))"
|
@echo OCAMLDEP "(test/$(notdir $(shell echo $$PWD)))"
|
||||||
@$(OCAMLDEP) -native $(INCLUDES) $^ > .depend
|
@$(OCAMLDEP) -native $(INCLUDES) $^ > .depend
|
||||||
|
|
||||||
|
@ -29,6 +29,15 @@ OPENED_MODULES := \
|
|||||||
${CLIENT_OPENED_MODULES} \
|
${CLIENT_OPENED_MODULES} \
|
||||||
Environment Client_embedded_proto_alpha Tezos_context
|
Environment Client_embedded_proto_alpha Tezos_context
|
||||||
|
|
||||||
|
${SRCDIR}/client/embedded/alpha/_tzbuild/%.cmi: ${SRCDIR}/proto/alpha/%.mli
|
||||||
|
${MAKE} -C ${SRCDIR} proto/client_embedded_proto_alpha.cmxa
|
||||||
|
${SRCDIR}/client/embedded/alpha/_tzbuild/%.cmx: ${SRCDIR}/proto/alpha/%.ml
|
||||||
|
${MAKE} -C ${SRCDIR} proto/client_embedded_proto_alpha.cmxa
|
||||||
|
${SRCDIR}/client/embedded/alpha/%.cmi: ${SRCDIR}/client/embedded/alpha/%.mli
|
||||||
|
${MAKE} -C ${SRCDIR} client/embedded/client_alpha.cmx
|
||||||
|
${SRCDIR}/client/embedded/alpha/%.cmx: ${SRCDIR}/client/embedded/alpha/%.ml
|
||||||
|
${MAKE} -C ${SRCDIR} client/embedded/client_alpha.cmx
|
||||||
|
|
||||||
############################################################################
|
############################################################################
|
||||||
## Transactions
|
## Transactions
|
||||||
|
|
||||||
@ -37,11 +46,11 @@ run-test-transaction:
|
|||||||
@echo
|
@echo
|
||||||
./test-transaction
|
./test-transaction
|
||||||
|
|
||||||
TEST_CONNECTION_IMPLS := \
|
TEST_TRANSACTION_IMPLS := \
|
||||||
proto_alpha_helpers.ml \
|
proto_alpha_helpers.ml \
|
||||||
test_transaction.ml
|
test_transaction.ml
|
||||||
|
|
||||||
test-transaction: ${LIB} ${TEST_CONNECTION_IMPLS:.ml=.cmx}
|
test-transaction: ${LIB} ${TEST_TRANSACTION_IMPLS:.ml=.cmx}
|
||||||
@echo COMPILE $(notdir $@)
|
@echo COMPILE $(notdir $@)
|
||||||
@${OCAMLOPT} -linkall -linkpkg ${OCAMLFLAGS} -o $@ $^
|
@${OCAMLOPT} -linkall -linkpkg ${OCAMLFLAGS} -o $@ $^
|
||||||
|
|
||||||
@ -56,11 +65,11 @@ run-test-origination:
|
|||||||
@echo
|
@echo
|
||||||
./test-origination
|
./test-origination
|
||||||
|
|
||||||
TEST_CONNECTION_IMPLS := \
|
TEST_ORIGINATION_IMPLS := \
|
||||||
proto_alpha_helpers.ml \
|
proto_alpha_helpers.ml \
|
||||||
test_origination.ml
|
test_origination.ml
|
||||||
|
|
||||||
test-origination: ${LIB} ${TEST_CONNECTION_IMPLS:.ml=.cmx}
|
test-origination: ${LIB} ${TEST_ORIGINATION_IMPLS:.ml=.cmx}
|
||||||
@echo COMPILE $(notdir $@)
|
@echo COMPILE $(notdir $@)
|
||||||
@${OCAMLOPT} -linkall -linkpkg ${OCAMLFLAGS} -o $@ $^
|
@${OCAMLOPT} -linkall -linkpkg ${OCAMLFLAGS} -o $@ $^
|
||||||
|
|
||||||
@ -75,11 +84,11 @@ run-test-endorsement:
|
|||||||
@echo
|
@echo
|
||||||
./test-endorsement
|
./test-endorsement
|
||||||
|
|
||||||
TEST_CONNECTION_IMPLS := \
|
TEST_ENDORSEMENT_IMPLS := \
|
||||||
proto_alpha_helpers.ml \
|
proto_alpha_helpers.ml \
|
||||||
test_endorsement.ml
|
test_endorsement.ml
|
||||||
|
|
||||||
test-endorsement: ${LIB} ${TEST_CONNECTION_IMPLS:.ml=.cmx}
|
test-endorsement: ${LIB} ${TEST_ENDORSEMENT_IMPLS:.ml=.cmx}
|
||||||
@echo COMPILE $(notdir $@)
|
@echo COMPILE $(notdir $@)
|
||||||
@${OCAMLOPT} -linkall -linkpkg ${OCAMLFLAGS} -o $@ $^
|
@${OCAMLOPT} -linkall -linkpkg ${OCAMLFLAGS} -o $@ $^
|
||||||
|
|
||||||
@ -94,11 +103,11 @@ run-test-vote:
|
|||||||
@echo
|
@echo
|
||||||
./test-vote
|
./test-vote
|
||||||
|
|
||||||
TEST_CONNECTION_IMPLS := \
|
TEST_VOTE_IMPLS := \
|
||||||
proto_alpha_helpers.ml \
|
proto_alpha_helpers.ml \
|
||||||
test_vote.ml
|
test_vote.ml
|
||||||
|
|
||||||
test-vote: ${LIB} ${TEST_CONNECTION_IMPLS:.ml=.cmx}
|
test-vote: ${LIB} ${TEST_VOTE_IMPLS:.ml=.cmx}
|
||||||
@echo COMPILE $(notdir $@)
|
@echo COMPILE $(notdir $@)
|
||||||
@${OCAMLOPT} -linkall -linkpkg ${OCAMLFLAGS} -o $@ $^
|
@${OCAMLOPT} -linkall -linkpkg ${OCAMLFLAGS} -o $@ $^
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ let (//) = Filename.concat
|
|||||||
|
|
||||||
let rpc_config : Client_rpcs.config = {
|
let rpc_config : Client_rpcs.config = {
|
||||||
host = "localhost" ;
|
host = "localhost" ;
|
||||||
port = 18732 ;
|
port = 8192 + Random.int 8192 ;
|
||||||
tls = false ;
|
tls = false ;
|
||||||
logger = Client_rpcs.null_logger ;
|
logger = Client_rpcs.null_logger ;
|
||||||
}
|
}
|
||||||
@ -476,7 +476,7 @@ module Mining = struct
|
|||||||
() >>=? fun unsigned_header ->
|
() >>=? fun unsigned_header ->
|
||||||
let signed_header = Environment.Ed25519.Signature.append src_sk unsigned_header in
|
let signed_header = Environment.Ed25519.Signature.append src_sk unsigned_header in
|
||||||
Client_node_rpcs.inject_block rpc_config
|
Client_node_rpcs.inject_block rpc_config
|
||||||
?force signed_header [operation_list] >>=? fun block_hash ->
|
?force signed_header [List.map (fun h -> Client_node_rpcs.Hash h) operation_list] >>=? fun block_hash ->
|
||||||
return block_hash
|
return block_hash
|
||||||
|
|
||||||
let mine
|
let mine
|
||||||
|
@ -102,81 +102,42 @@ let equal_block ?msg st1 st2 =
|
|||||||
Hash.Block_hash.to_hex (Block_header.hash st) in
|
Hash.Block_hash.to_hex (Block_header.hash st) in
|
||||||
Assert.equal ?msg ~prn ~eq st1 st2
|
Assert.equal ?msg ~prn ~eq st1 st2
|
||||||
|
|
||||||
let build_chain state tbl otbl pred names =
|
let block _state ?(operations = []) (pred: State.Block.t) name
|
||||||
Lwt_list.fold_left_s
|
|
||||||
(fun (pred_hash, pred) name ->
|
|
||||||
begin
|
|
||||||
let oph, op, _bytes = operation name in
|
|
||||||
State.Operation.store state oph op >>= fun created ->
|
|
||||||
Assert.is_true ~msg:__LOC__ created ;
|
|
||||||
State.Operation.read_opt state oph >>= fun op' ->
|
|
||||||
equal_operation ~msg:__LOC__ (Some op) op' ;
|
|
||||||
State.Operation.mark_invalid state oph [] >>= fun store_invalid ->
|
|
||||||
Assert.is_true ~msg:__LOC__ store_invalid ;
|
|
||||||
Hashtbl.add otbl name (oph, Error []) ;
|
|
||||||
let block = block ~operations:[oph] state pred_hash pred name in
|
|
||||||
let hash = Block_header.hash block in
|
|
||||||
State.Block_header.store state hash block >>= fun created ->
|
|
||||||
Assert.is_true ~msg:__LOC__ created ;
|
|
||||||
State.Block_header.read_opt state hash >>= fun block' ->
|
|
||||||
equal_block ~msg:__LOC__ (Some block) block' ;
|
|
||||||
State.Block_header.mark_invalid state hash [] >>= fun store_invalid ->
|
|
||||||
Assert.is_true ~msg:__LOC__ store_invalid ;
|
|
||||||
Hashtbl.add tbl name (hash, block) ;
|
|
||||||
return (hash, block)
|
|
||||||
end >>= function
|
|
||||||
| Ok v -> Lwt.return v
|
|
||||||
| Error err ->
|
|
||||||
Error_monad.pp_print_error Format.err_formatter err ;
|
|
||||||
assert false)
|
|
||||||
pred
|
|
||||||
names >>= fun _ ->
|
|
||||||
Lwt.return ()
|
|
||||||
|
|
||||||
let block _state ?(operations = []) (pred: State.Valid_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
|
||||||
[Operation_list_hash.compute operations] in
|
[Operation_list_hash.compute operations] in
|
||||||
let fitness = incr_fitness pred.fitness in
|
let pred_header = State.Block.shell_header pred in
|
||||||
let timestamp = incr_timestamp pred.timestamp in
|
let fitness = incr_fitness pred_header.fitness in
|
||||||
{ shell = { net_id = pred.net_id ;
|
let timestamp = incr_timestamp pred_header.timestamp in
|
||||||
level = Int32.succ pred.level ;
|
{ shell = { net_id = pred_header.net_id ;
|
||||||
proto_level = pred.proto_level ;
|
level = Int32.succ pred_header.level ;
|
||||||
predecessor = pred.hash ;
|
proto_level = pred_header.proto_level ;
|
||||||
|
predecessor = State.Block.hash pred ;
|
||||||
timestamp ; operations_hash ; fitness } ;
|
timestamp ; operations_hash ; fitness } ;
|
||||||
proto = MBytes.of_string name ;
|
proto = MBytes.of_string name ;
|
||||||
}
|
}
|
||||||
|
|
||||||
let build_valid_chain state tbl vtbl otbl 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 ->
|
||||||
begin
|
begin
|
||||||
let oph, op, _bytes = operation name in
|
let oph, op, _bytes = operation name in
|
||||||
State.Operation.store state oph op >>= fun created ->
|
|
||||||
Assert.is_true ~msg:__LOC__ created ;
|
|
||||||
State.Operation.read_opt state oph >>= fun op' ->
|
|
||||||
equal_operation ~msg:__LOC__ (Some op) op' ;
|
|
||||||
Hashtbl.add otbl name (oph, Ok op) ;
|
|
||||||
let block = block state ~operations:[oph] pred name in
|
let block = block state ~operations:[oph] pred name in
|
||||||
let hash = Tezos_data.Block_header.hash block in
|
let hash = Block_header.hash block in
|
||||||
State.Block_header.store state hash block >>= fun created ->
|
let pred_header = State.Block.header pred in
|
||||||
Assert.is_true ~msg:__LOC__ created ;
|
State.Block.context pred >>= fun predecessor_context ->
|
||||||
State.Operation_list.store_all state hash [[oph]] >>= fun () ->
|
|
||||||
State.Block_header.read_opt state hash >>= fun block' ->
|
|
||||||
equal_block ~msg:__LOC__ (Some block) block' ;
|
|
||||||
Hashtbl.add tbl name (hash, block) ;
|
|
||||||
begin
|
begin
|
||||||
Proto.begin_application
|
Proto.begin_application
|
||||||
~predecessor_context: pred.context
|
~predecessor_context
|
||||||
~predecessor_timestamp: pred.timestamp
|
~predecessor_timestamp: pred_header.shell.timestamp
|
||||||
~predecessor_fitness: pred.fitness
|
~predecessor_fitness: pred_header.shell.fitness
|
||||||
block >>=? fun vstate ->
|
block >>=? fun vstate ->
|
||||||
(* no operations *)
|
(* no operations *)
|
||||||
Proto.finalize_block vstate
|
Proto.finalize_block vstate
|
||||||
end >>=? fun ctxt ->
|
end >>=? fun ctxt ->
|
||||||
State.Valid_block.store state hash ctxt >>=? fun _vblock ->
|
State.Block.store state block [[op]] ctxt >>=? fun _vblock ->
|
||||||
State.Valid_block.read state hash >>=? fun vblock ->
|
State.Block.read state hash >>=? fun vblock ->
|
||||||
Hashtbl.add vtbl name vblock ;
|
Hashtbl.add vtbl name vblock ;
|
||||||
return vblock
|
return vblock
|
||||||
end >>= function
|
end >>= function
|
||||||
@ -189,63 +150,31 @@ let build_valid_chain state tbl vtbl otbl pred names =
|
|||||||
Lwt.return ()
|
Lwt.return ()
|
||||||
|
|
||||||
let build_example_tree net =
|
let build_example_tree net =
|
||||||
let tbl = Hashtbl.create 23 in
|
|
||||||
let vtbl = Hashtbl.create 23 in
|
let vtbl = Hashtbl.create 23 in
|
||||||
let otbl = Hashtbl.create 23 in
|
Chain.genesis net >>= fun genesis ->
|
||||||
State.Valid_block.Current.genesis net >>= fun genesis ->
|
|
||||||
State.Block_header.read_exn net genesis.hash >>= fun genesis_header ->
|
|
||||||
Hashtbl.add vtbl "Genesis" genesis ;
|
Hashtbl.add vtbl "Genesis" genesis ;
|
||||||
Hashtbl.add tbl "Genesis" (genesis.hash, genesis_header ) ;
|
|
||||||
let chain = [ "A1" ; "A2" ; "A3" ; "A4" ; "A5" ; "A6" ; "A7" ; "A8" ] in
|
let chain = [ "A1" ; "A2" ; "A3" ; "A4" ; "A5" ; "A6" ; "A7" ; "A8" ] in
|
||||||
build_valid_chain net tbl vtbl otbl genesis chain >>= fun () ->
|
build_valid_chain net vtbl genesis chain >>= fun () ->
|
||||||
let a3 = Hashtbl.find vtbl "A3" in
|
let a3 = Hashtbl.find vtbl "A3" in
|
||||||
let chain = [ "B1" ; "B2" ; "B3" ; "B4" ; "B5" ; "B6" ; "B7" ; "B8" ] in
|
let chain = [ "B1" ; "B2" ; "B3" ; "B4" ; "B5" ; "B6" ; "B7" ; "B8" ] in
|
||||||
build_valid_chain net tbl vtbl otbl a3 chain >>= fun () ->
|
build_valid_chain net vtbl a3 chain >>= fun () ->
|
||||||
let b7 = Hashtbl.find tbl "B7" in
|
Lwt.return vtbl
|
||||||
let chain = [ "C1" ; "C2" ; "C3" ; "C4" ; "C5" ; "C6" ; "C7" ; "C8" ] in
|
|
||||||
build_chain net tbl otbl b7 chain >>= fun () ->
|
|
||||||
let pending_op = "PP" in
|
|
||||||
let oph, op, _bytes = operation pending_op in
|
|
||||||
State.Operation.store net oph op >>= fun _ ->
|
|
||||||
State.Operation.read_opt net oph >>= fun op' ->
|
|
||||||
equal_operation ~msg:__LOC__ (Some op) op' ;
|
|
||||||
Hashtbl.add otbl pending_op (oph, Ok op) ;
|
|
||||||
Lwt.return (tbl, vtbl, otbl)
|
|
||||||
|
|
||||||
type state = {
|
type state = {
|
||||||
block: (string, Block_hash.t * Block_header.t) Hashtbl.t ;
|
vblock: (string, State.Block.t) Hashtbl.t ;
|
||||||
operation: (string, Operation_hash.t * Operation.t tzresult) Hashtbl.t ;
|
|
||||||
vblock: (string, State.Valid_block.t) Hashtbl.t ;
|
|
||||||
state: State.t ;
|
state: State.t ;
|
||||||
net: State.Net.t ;
|
net: State.Net.t ;
|
||||||
init: unit -> State.t tzresult Lwt.t;
|
init: unit -> State.t tzresult Lwt.t;
|
||||||
}
|
}
|
||||||
|
|
||||||
let block s = Hashtbl.find s.block
|
|
||||||
let vblock s = Hashtbl.find s.vblock
|
let vblock s = Hashtbl.find s.vblock
|
||||||
let operation s = Hashtbl.find s.operation
|
|
||||||
|
|
||||||
exception Found of string
|
exception Found of string
|
||||||
let rev_find s h =
|
|
||||||
try
|
|
||||||
Hashtbl.iter (fun k (bh,_) ->
|
|
||||||
if Block_hash.equal bh h then raise (Found k))
|
|
||||||
s.block ;
|
|
||||||
Format.asprintf "genesis(%a)" Block_hash.pp_short h
|
|
||||||
with Found s -> s
|
|
||||||
|
|
||||||
let blocks s =
|
|
||||||
Hashtbl.fold (fun k v acc -> (k,v) :: acc) s.block []
|
|
||||||
|> List.sort Pervasives.compare
|
|
||||||
|
|
||||||
let vblocks s =
|
let vblocks s =
|
||||||
Hashtbl.fold (fun k v acc -> (k,v) :: acc) s.vblock []
|
Hashtbl.fold (fun k v acc -> (k,v) :: acc) s.vblock []
|
||||||
|> List.sort Pervasives.compare
|
|> List.sort Pervasives.compare
|
||||||
|
|
||||||
let operations s =
|
|
||||||
Hashtbl.fold (fun k v acc -> (k,v) :: acc) s.operation []
|
|
||||||
|> List.sort Pervasives.compare
|
|
||||||
|
|
||||||
let wrap_state_init f base_dir =
|
let wrap_state_init f base_dir =
|
||||||
begin
|
begin
|
||||||
let store_root = base_dir // "store" in
|
let store_root = base_dir // "store" in
|
||||||
@ -257,81 +186,36 @@ let wrap_state_init f base_dir =
|
|||||||
() in
|
() in
|
||||||
init () >>=? fun state ->
|
init () >>=? fun state ->
|
||||||
State.Net.create state genesis >>= fun net ->
|
State.Net.create state genesis >>= fun net ->
|
||||||
build_example_tree net >>= fun (block, vblock, operation) ->
|
build_example_tree net >>= fun vblock ->
|
||||||
f { state ; net ; block ; vblock ; operation ; init } >>=? fun () ->
|
f { state ; net ; vblock ; init } >>=? fun () ->
|
||||||
return ()
|
return ()
|
||||||
end
|
end
|
||||||
|
|
||||||
let test_init (_ : state) =
|
let test_init (_ : state) =
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
let test_read_operation (s: state) =
|
|
||||||
Lwt_list.iter_s (fun (name, (oph, op)) ->
|
|
||||||
State.Operation.invalid s.net oph >>= function
|
|
||||||
| Some err ->
|
|
||||||
begin match op with
|
|
||||||
| Ok _ ->
|
|
||||||
Assert.fail_msg "Incorrect invalid operation read %s" name
|
|
||||||
| Error e ->
|
|
||||||
if e <> err then
|
|
||||||
Assert.fail_msg "Incorrect operation read %s" name ;
|
|
||||||
Lwt.return_unit
|
|
||||||
end
|
|
||||||
| None ->
|
|
||||||
State.Operation.read_opt s.net oph >>= function
|
|
||||||
| None ->
|
|
||||||
Assert.fail_msg "Cannot read block %s" name
|
|
||||||
| Some data ->
|
|
||||||
begin match op with
|
|
||||||
| Error _ ->
|
|
||||||
Assert.fail_msg "Incorrect valid operation read %s" name
|
|
||||||
| Ok op ->
|
|
||||||
if op.Operation.proto <> data.proto then
|
|
||||||
Assert.fail_msg "Incorrect operation read %s %s" name
|
|
||||||
(MBytes.to_string data.Operation.proto) ;
|
|
||||||
Lwt.return_unit
|
|
||||||
end)
|
|
||||||
(operations s) >>= fun () ->
|
|
||||||
return ()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(****************************************************************************)
|
(****************************************************************************)
|
||||||
|
|
||||||
(** State. *)
|
(** State.Block.read *)
|
||||||
|
|
||||||
let test_read_block (s: state) =
|
let test_read_block (s: state) =
|
||||||
Lwt_list.iter_s (fun (name, (hash, block)) ->
|
Lwt_list.iter_s (fun (name, vblock) ->
|
||||||
begin
|
let hash = State.Block.hash vblock in
|
||||||
State.Block_header.read_opt s.net hash >>= function
|
State.Block.read s.net hash >>= function
|
||||||
| None ->
|
|
||||||
Assert.fail_msg "Cannot read block %s" name
|
|
||||||
| Some block' ->
|
|
||||||
if not (Block_header.equal block block') then
|
|
||||||
Assert.fail_msg "Error while reading block %s" name ;
|
|
||||||
Lwt.return_unit
|
|
||||||
end >>= fun () ->
|
|
||||||
let vblock =
|
|
||||||
try Some (vblock s name)
|
|
||||||
with Not_found -> None in
|
|
||||||
State.Valid_block.read s.net hash >>= function
|
|
||||||
| Error _ ->
|
| Error _ ->
|
||||||
if vblock <> None then
|
Assert.fail_msg "Error while reading valid block %s" name
|
||||||
Assert.fail_msg "Error while reading valid block %s" name ;
|
|
||||||
Lwt.return_unit
|
|
||||||
| Ok _vblock' ->
|
| Ok _vblock' ->
|
||||||
match vblock with
|
(* FIXME COMPARE read operations ??? *)
|
||||||
| None ->
|
Lwt.return_unit
|
||||||
Assert.fail_msg "Error while reading invalid block %s" name
|
) (vblocks s) >>= fun () ->
|
||||||
| Some _vblock ->
|
|
||||||
Lwt.return_unit
|
|
||||||
) (blocks s) >>= fun () ->
|
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
|
|
||||||
(****************************************************************************)
|
(****************************************************************************)
|
||||||
|
|
||||||
(** State.path *)
|
(** Chain_traversal.path *)
|
||||||
|
|
||||||
let rec compare_path p1 p2 = match p1, p2 with
|
let rec compare_path p1 p2 = match p1, p2 with
|
||||||
| [], [] -> true
|
| [], [] -> true
|
||||||
@ -340,32 +224,12 @@ let rec compare_path p1 p2 = match p1, p2 with
|
|||||||
|
|
||||||
let test_path (s: state) =
|
let test_path (s: state) =
|
||||||
let check_path h1 h2 p2 =
|
let check_path h1 h2 p2 =
|
||||||
State.Block_header.Helpers.path s.net (fst @@ block s h1) (fst @@ block s h2) >>= function
|
Chain_traversal.path (vblock s h1) (vblock s h2) >>= function
|
||||||
| Error _ ->
|
|
||||||
Assert.fail_msg "cannot compute path %s -> %s" h1 h2
|
|
||||||
| Ok p1 ->
|
|
||||||
let p1 = List.map (fun b -> fst b) p1 in
|
|
||||||
let p2 = List.map (fun b -> fst (block s b)) p2 in
|
|
||||||
if not (compare_path p1 p2) then
|
|
||||||
Assert.fail_msg "bad path %s -> %s" h1 h2 ;
|
|
||||||
Lwt.return_unit in
|
|
||||||
check_path "Genesis" "Genesis" [] >>= fun () ->
|
|
||||||
check_path "A1" "A1" [] >>= fun () ->
|
|
||||||
check_path "A2" "A6" ["A3"; "A4"; "A5"; "A6"] >>= fun () ->
|
|
||||||
check_path "B2" "B6" ["B3"; "B4"; "B5"; "B6"] >>= fun () ->
|
|
||||||
check_path "A1" "B3" ["A2"; "A3"; "B1"; "B2"; "B3"] >>= fun () ->
|
|
||||||
check_path "A1" "C2" ["A2"; "A3"; "B1"; "B2"; "B3" ; "B4" ;
|
|
||||||
"B5" ; "B6" ; "B7" ; "C1" ; "C2" ] >>= fun () ->
|
|
||||||
return ()
|
|
||||||
|
|
||||||
let test_valid_path (s: state) =
|
|
||||||
let check_path h1 h2 p2 =
|
|
||||||
State.Valid_block.Helpers.path s.net (vblock s h1) (vblock s h2) >>= function
|
|
||||||
| None ->
|
| None ->
|
||||||
Assert.fail_msg "cannot compute path %s -> %s" h1 h2 ;
|
Assert.fail_msg "cannot compute path %s -> %s" h1 h2 ;
|
||||||
| Some (p: State.Valid_block.t list) ->
|
| Some (p: State.Block.t list) ->
|
||||||
let p = List.map (fun b -> b.State.Valid_block.hash) p in
|
let p = List.map State.Block.hash p in
|
||||||
let p2 = List.map (fun b -> (vblock s b).hash) p2 in
|
let p2 = List.map (fun b -> State.Block.hash (vblock s b)) p2 in
|
||||||
if not (compare_path p p2) then
|
if not (compare_path p p2) then
|
||||||
Assert.fail_msg "bad path %s -> %s" h1 h2 ;
|
Assert.fail_msg "bad path %s -> %s" h1 h2 ;
|
||||||
Lwt.return_unit in
|
Lwt.return_unit in
|
||||||
@ -379,107 +243,59 @@ let test_valid_path (s: state) =
|
|||||||
|
|
||||||
(****************************************************************************)
|
(****************************************************************************)
|
||||||
|
|
||||||
(** State.ancestor *)
|
(** Chain_traversal.common_ancestor *)
|
||||||
|
|
||||||
let test_ancestor s =
|
let test_ancestor s =
|
||||||
let check_ancestor h1 h2 expected =
|
let check_ancestor h1 h2 expected =
|
||||||
State.Block_header.Helpers.common_ancestor
|
Chain_traversal.common_ancestor
|
||||||
s.net (fst @@ block s h1) (fst @@ block s h2) >>= function
|
(vblock s h1) (vblock s h2) >>= fun a ->
|
||||||
| Error _ ->
|
if not (Block_hash.equal (State.Block.hash a) (State.Block.hash expected)) then
|
||||||
Assert.fail_msg "Cannot compure ancestor for %s %s" h1 h2 ;
|
|
||||||
| Ok (a, _) ->
|
|
||||||
if not (Block_hash.equal a (fst expected)) then
|
|
||||||
Assert.fail_msg
|
|
||||||
"bad ancestor %s %s: found %s, expected %s"
|
|
||||||
h1 h2 (rev_find s a) (rev_find s @@ fst expected) ;
|
|
||||||
Lwt.return_unit in
|
|
||||||
let check_valid_ancestor h1 h2 expected =
|
|
||||||
State.Valid_block.Helpers.common_ancestor
|
|
||||||
s.net (vblock s h1) (vblock s h2) >>= fun a ->
|
|
||||||
if not (Block_hash.equal a.hash expected.State.Valid_block.hash) then
|
|
||||||
Assert.fail_msg "bad ancestor %s %s" h1 h2 ;
|
Assert.fail_msg "bad ancestor %s %s" h1 h2 ;
|
||||||
Lwt.return_unit in
|
Lwt.return_unit in
|
||||||
check_ancestor "Genesis" "Genesis" (block s "Genesis") >>= fun () ->
|
check_ancestor "Genesis" "Genesis" (vblock s "Genesis") >>= fun () ->
|
||||||
check_ancestor "Genesis" "A3" (block s "Genesis") >>= fun () ->
|
check_ancestor "Genesis" "A3" (vblock s "Genesis") >>= fun () ->
|
||||||
check_ancestor "A3" "Genesis" (block s "Genesis") >>= fun () ->
|
check_ancestor "A3" "Genesis" (vblock s "Genesis") >>= fun () ->
|
||||||
check_ancestor "A1" "A1" (block s "A1") >>= fun () ->
|
check_ancestor "A1" "A1" (vblock s "A1") >>= fun () ->
|
||||||
check_ancestor "A1" "A3" (block s "A1") >>= fun () ->
|
check_ancestor "A1" "A3" (vblock s "A1") >>= fun () ->
|
||||||
check_ancestor "A3" "A1" (block s "A1") >>= fun () ->
|
check_ancestor "A3" "A1" (vblock s "A1") >>= fun () ->
|
||||||
check_ancestor "A6" "B6" (block s "A3") >>= fun () ->
|
check_ancestor "A6" "B6" (vblock s "A3") >>= fun () ->
|
||||||
check_ancestor "B6" "A6" (block s "A3") >>= fun () ->
|
check_ancestor "B6" "A6" (vblock s "A3") >>= fun () ->
|
||||||
check_ancestor "A4" "B1" (block s "A3") >>= fun () ->
|
check_ancestor "A4" "B1" (vblock s "A3") >>= fun () ->
|
||||||
check_ancestor "B1" "A4" (block s "A3") >>= fun () ->
|
check_ancestor "B1" "A4" (vblock s "A3") >>= fun () ->
|
||||||
check_ancestor "A3" "B1" (block s "A3") >>= fun () ->
|
check_ancestor "A3" "B1" (vblock s "A3") >>= fun () ->
|
||||||
check_ancestor "B1" "A3" (block s "A3") >>= fun () ->
|
check_ancestor "B1" "A3" (vblock s "A3") >>= fun () ->
|
||||||
check_ancestor "A2" "B1" (block s "A2") >>= fun () ->
|
check_ancestor "A2" "B1" (vblock s "A2") >>= fun () ->
|
||||||
check_ancestor "B1" "A2" (block s "A2") >>= fun () ->
|
check_ancestor "B1" "A2" (vblock s "A2") >>= fun () ->
|
||||||
check_ancestor "C4" "B8" (block s "B7") >>= fun () ->
|
|
||||||
check_ancestor "B8" "C4" (block s "B7") >>= fun () ->
|
|
||||||
check_ancestor "C4" "A8" (block s "A3") >>= fun () ->
|
|
||||||
check_ancestor "A8" "C4" (block s "A3") >>= fun () ->
|
|
||||||
check_valid_ancestor "A6" "B6" (vblock s "A3") >>= fun () ->
|
|
||||||
check_valid_ancestor "B6" "A6" (vblock s "A3") >>= fun () ->
|
|
||||||
check_valid_ancestor "A4" "B1" (vblock s "A3") >>= fun () ->
|
|
||||||
check_valid_ancestor "B1" "A4" (vblock s "A3") >>= fun () ->
|
|
||||||
check_valid_ancestor "A3" "B1" (vblock s "A3") >>= fun () ->
|
|
||||||
check_valid_ancestor "B1" "A3" (vblock s "A3") >>= fun () ->
|
|
||||||
check_valid_ancestor "A2" "B1" (vblock s "A2") >>= fun () ->
|
|
||||||
check_valid_ancestor "B1" "A2" (vblock s "A2") >>= fun () ->
|
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
|
|
||||||
(****************************************************************************)
|
(****************************************************************************)
|
||||||
|
|
||||||
(** State.locator *)
|
(** Chain_traversal.block_locator *)
|
||||||
|
|
||||||
let test_locator s =
|
let test_locator s =
|
||||||
let check_locator h1 expected =
|
let check_locator h1 expected =
|
||||||
State.Block_header.Helpers.block_locator
|
Chain_traversal.block_locator
|
||||||
s.net (List.length expected) (fst @@ block s h1) >>= function
|
(vblock s h1) (List.length expected) >>= fun l ->
|
||||||
| Error _ ->
|
|
||||||
Assert.fail_msg "Cannot compute locator for %s" h1
|
|
||||||
| Ok l ->
|
|
||||||
if List.length l <> List.length expected then
|
|
||||||
Assert.fail_msg
|
|
||||||
"Invalid locator length %s (found: %d, expected: %d)"
|
|
||||||
h1 (List.length l) (List.length expected) ;
|
|
||||||
List.iter2
|
|
||||||
(fun h h2 ->
|
|
||||||
if not (Block_hash.equal h (fst @@ block s h2)) then
|
|
||||||
Assert.fail_msg "Invalid locator %s (expectd: %s)" h1 h2)
|
|
||||||
l expected;
|
|
||||||
Lwt.return_unit in
|
|
||||||
let check_valid_locator h1 expected =
|
|
||||||
State.Valid_block.Helpers.block_locator
|
|
||||||
s.net (List.length expected) (vblock s h1) >>= fun l ->
|
|
||||||
if List.length l <> List.length expected then
|
if List.length l <> List.length expected then
|
||||||
Assert.fail_msg
|
Assert.fail_msg
|
||||||
"Invalid locator length %s (found: %d, expected: %d)"
|
"Invalid locator length %s (found: %d, expected: %d)"
|
||||||
h1 (List.length l) (List.length expected) ;
|
h1 (List.length l) (List.length expected) ;
|
||||||
List.iter2
|
List.iter2
|
||||||
(fun h h2 ->
|
(fun h h2 ->
|
||||||
if not (Block_hash.equal h (fst @@ block s h2)) then
|
if not (Block_hash.equal h (State.Block.hash @@ vblock s h2)) then
|
||||||
Assert.fail_msg "Invalid locator %s (expectd: %s)" h1 h2)
|
Assert.fail_msg "Invalid locator %s (expectd: %s)" h1 h2)
|
||||||
l expected ;
|
l expected ;
|
||||||
Lwt.return_unit in
|
Lwt.return_unit in
|
||||||
check_locator "A8" ["A8";"A7";"A6";"A5";"A4";"A3";"A2";"A1"] >>= fun () ->
|
check_locator "A8" ["A8";"A7";"A6";"A5";"A4";"A3";"A2"] >>= fun () ->
|
||||||
check_locator "B8"
|
check_locator "B8" ["B8";"B7";"B6";"B5";"B4";"B3";"B2";"B1";"A3"] >>= fun () ->
|
||||||
["B8";"B7";"B6";"B5";"B4";"B3";"B2";"B1";"A3"] >>= fun () ->
|
check_locator "B8" ["B8";"B7";"B6";"B5";"B4"] >>= fun () ->
|
||||||
check_locator "C8"
|
|
||||||
["C8";"C7";"C6";"C5";"C4";"C3";"C2";"C1";
|
|
||||||
"B7";"B6";"B4";"B2";"A3";"A1"] >>= fun () ->
|
|
||||||
check_locator "C8" ["C8";"C7";"C6";"C5";"C4"] >>= fun () ->
|
|
||||||
check_valid_locator "A8"
|
|
||||||
["A8";"A7";"A6";"A5";"A4";"A3";"A2"] >>= fun () ->
|
|
||||||
check_valid_locator "B8"
|
|
||||||
["B8";"B7";"B6";"B5";"B4";"B3";"B2";"B1";"A3"] >>= fun () ->
|
|
||||||
check_valid_locator "B8" ["B8";"B7";"B6";"B5";"B4"] >>= fun () ->
|
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
|
|
||||||
(****************************************************************************)
|
(****************************************************************************)
|
||||||
|
|
||||||
(** State.known_heads *)
|
(** Chain.known_heads *)
|
||||||
|
|
||||||
let compare s name heads l =
|
let compare s name heads l =
|
||||||
if List.length heads <> List.length l then
|
if List.length heads <> List.length l then
|
||||||
@ -488,39 +304,39 @@ let compare s name heads l =
|
|||||||
name (List.length heads) (List.length l) ;
|
name (List.length heads) (List.length l) ;
|
||||||
List.iter
|
List.iter
|
||||||
(fun bname ->
|
(fun bname ->
|
||||||
let hash = (vblock s bname).hash in
|
let hash = State.Block.hash (vblock s bname) in
|
||||||
if not (List.exists (fun b -> Block_hash.equal hash b.State.Valid_block.hash) heads) then
|
if not (List.exists (fun b -> Block_hash.equal hash (State.Block.hash b)) heads) then
|
||||||
Assert.fail_msg "missing block in known_heads (%s: %s)" name bname)
|
Assert.fail_msg "missing block in known_heads (%s: %s)" name bname)
|
||||||
l
|
l
|
||||||
|
|
||||||
let test_known_heads s =
|
let test_known_heads s =
|
||||||
State.Valid_block.known_heads s.net >>= fun heads ->
|
Chain.known_heads s.net >>= fun heads ->
|
||||||
compare s "initial" heads ["A8";"B8"] ;
|
compare s "initial" heads ["A8";"B8"] ;
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
|
|
||||||
(****************************************************************************)
|
(****************************************************************************)
|
||||||
|
|
||||||
(** State.head/set_head *)
|
(** Chain.head/set_head *)
|
||||||
|
|
||||||
let test_head s =
|
let test_head s =
|
||||||
State.Valid_block.Current.head s.net >>= fun head ->
|
Chain.head s.net >>= fun head ->
|
||||||
if not (Block_hash.equal head.hash genesis_block) then
|
if not (Block_hash.equal (State.Block.hash head) genesis_block) then
|
||||||
Assert.fail_msg "unexpected head" ;
|
Assert.fail_msg "unexpected head" ;
|
||||||
State.Valid_block.Current.set_head s.net (vblock s "A6") >>= fun _ ->
|
Chain.set_head s.net (vblock s "A6") >>= fun _ ->
|
||||||
State.Valid_block.Current.head s.net >>= fun head ->
|
Chain.head s.net >>= fun head ->
|
||||||
if not (Block_hash.equal head.hash (vblock s "A6").hash) then
|
if not (Block_hash.equal (State.Block.hash head) (State.Block.hash @@ vblock s "A6")) then
|
||||||
Assert.fail_msg "unexpected head" ;
|
Assert.fail_msg "unexpected head" ;
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
|
|
||||||
(****************************************************************************)
|
(****************************************************************************)
|
||||||
|
|
||||||
(** State.mem *)
|
(** Chain.mem *)
|
||||||
|
|
||||||
let test_mem s =
|
let test_mem s =
|
||||||
let mem s x =
|
let mem s x =
|
||||||
State.Valid_block.Current.mem s.net (fst @@ block s x) in
|
Chain.mem s.net (State.Block.hash @@ vblock s x) in
|
||||||
let test_mem s x =
|
let test_mem s x =
|
||||||
mem s x >>= function
|
mem s x >>= function
|
||||||
| true -> Lwt.return_unit
|
| true -> Lwt.return_unit
|
||||||
@ -535,21 +351,21 @@ let test_mem s =
|
|||||||
test_not_mem s "B1" >>= fun () ->
|
test_not_mem s "B1" >>= fun () ->
|
||||||
test_not_mem s "B6" >>= fun () ->
|
test_not_mem s "B6" >>= fun () ->
|
||||||
test_not_mem s "B8" >>= fun () ->
|
test_not_mem s "B8" >>= fun () ->
|
||||||
State.Valid_block.Current.set_head s.net (vblock s "A8") >>= fun _ ->
|
Chain.set_head s.net (vblock s "A8") >>= fun _ ->
|
||||||
test_mem s "A3" >>= fun () ->
|
test_mem s "A3" >>= fun () ->
|
||||||
test_mem s "A6" >>= fun () ->
|
test_mem s "A6" >>= fun () ->
|
||||||
test_mem s "A8" >>= fun () ->
|
test_mem s "A8" >>= fun () ->
|
||||||
test_not_mem s "B1" >>= fun () ->
|
test_not_mem s "B1" >>= fun () ->
|
||||||
test_not_mem s "B6" >>= fun () ->
|
test_not_mem s "B6" >>= fun () ->
|
||||||
test_not_mem s "B8" >>= fun () ->
|
test_not_mem s "B8" >>= fun () ->
|
||||||
State.Valid_block.Current.set_head s.net (vblock s "A6") >>= fun _ ->
|
Chain.set_head s.net (vblock s "A6") >>= fun _ ->
|
||||||
test_mem s "A3" >>= fun () ->
|
test_mem s "A3" >>= fun () ->
|
||||||
test_mem s "A6" >>= fun () ->
|
test_mem s "A6" >>= fun () ->
|
||||||
test_not_mem s "A8" >>= fun () ->
|
test_not_mem s "A8" >>= fun () ->
|
||||||
test_not_mem s "B1" >>= fun () ->
|
test_not_mem s "B1" >>= fun () ->
|
||||||
test_not_mem s "B6" >>= fun () ->
|
test_not_mem s "B6" >>= fun () ->
|
||||||
test_not_mem s "B8" >>= fun () ->
|
test_not_mem s "B8" >>= fun () ->
|
||||||
State.Valid_block.Current.set_head s.net (vblock s "B6") >>= fun _ ->
|
Chain.set_head s.net (vblock s "B6") >>= fun _ ->
|
||||||
test_mem s "A3" >>= fun () ->
|
test_mem s "A3" >>= fun () ->
|
||||||
test_not_mem s "A4" >>= fun () ->
|
test_not_mem s "A4" >>= fun () ->
|
||||||
test_not_mem s "A6" >>= fun () ->
|
test_not_mem s "A6" >>= fun () ->
|
||||||
@ -557,7 +373,7 @@ let test_mem s =
|
|||||||
test_mem s "B1" >>= fun () ->
|
test_mem s "B1" >>= fun () ->
|
||||||
test_mem s "B6" >>= fun () ->
|
test_mem s "B6" >>= fun () ->
|
||||||
test_not_mem s "B8" >>= fun () ->
|
test_not_mem s "B8" >>= fun () ->
|
||||||
State.Valid_block.Current.set_head s.net (vblock s "B8") >>= fun _ ->
|
Chain.set_head s.net (vblock s "B8") >>= fun _ ->
|
||||||
test_mem s "A3" >>= fun () ->
|
test_mem s "A3" >>= fun () ->
|
||||||
test_not_mem s "A4" >>= fun () ->
|
test_not_mem s "A4" >>= fun () ->
|
||||||
test_not_mem s "A6" >>= fun () ->
|
test_not_mem s "A6" >>= fun () ->
|
||||||
@ -570,28 +386,53 @@ let test_mem s =
|
|||||||
|
|
||||||
(****************************************************************************)
|
(****************************************************************************)
|
||||||
|
|
||||||
(** State.new *)
|
(** Chain_traversal.new_blocks *)
|
||||||
|
|
||||||
let test_new s =
|
let test_new_blocks s =
|
||||||
|
let test s head h expected_ancestor expected =
|
||||||
|
let to_block = vblock s head
|
||||||
|
and from_block = vblock s h in
|
||||||
|
Chain_traversal.new_blocks ~from_block ~to_block >>= fun (ancestor, blocks) ->
|
||||||
|
if not (Block_hash.equal (State.Block.hash ancestor) (State.Block.hash @@ vblock s expected_ancestor)) then
|
||||||
|
Assert.fail_msg "Invalid locator %s (expected: %s)" h expected_ancestor ;
|
||||||
|
if List.length blocks <> List.length expected then
|
||||||
|
Assert.fail_msg
|
||||||
|
"Invalid locator length %s (found: %d, expected: %d)"
|
||||||
|
h (List.length blocks) (List.length expected) ;
|
||||||
|
List.iter2
|
||||||
|
(fun h1 h2 ->
|
||||||
|
if not (Block_hash.equal (State.Block.hash h1) (State.Block.hash @@ vblock s h2)) then
|
||||||
|
Assert.fail_msg "Invalid locator %s (expected: %s)" h h2)
|
||||||
|
blocks expected ;
|
||||||
|
Lwt.return_unit
|
||||||
|
in
|
||||||
|
test s "A6" "A6" "A6" [] >>= fun () ->
|
||||||
|
test s "A8" "A6" "A6" ["A7";"A8"] >>= fun () ->
|
||||||
|
test s "A8" "B7" "A3" ["A4";"A5";"A6";"A7";"A8"] >>= fun () ->
|
||||||
|
return ()
|
||||||
|
|
||||||
|
|
||||||
|
(****************************************************************************)
|
||||||
|
|
||||||
|
(** Chain.find_new *)
|
||||||
|
|
||||||
|
let test_find_new s =
|
||||||
let test s h expected =
|
let test s h expected =
|
||||||
State.Valid_block.Helpers.block_locator s.net 50 (vblock s h) >>= fun loc ->
|
Chain_traversal.block_locator (vblock s h) 50 >>= fun loc ->
|
||||||
State.Valid_block.Current.find_new s.net loc (List.length expected) >>= function
|
Chain.find_new s.net loc (List.length expected) >>= fun blocks ->
|
||||||
| Error _ ->
|
if List.length blocks <> List.length expected then
|
||||||
Assert.fail_msg "Failed to compute new blocks %s" h
|
Assert.fail_msg
|
||||||
| Ok blocks ->
|
"Invalid locator length %s (found: %d, expected: %d)"
|
||||||
if List.length blocks <> List.length expected then
|
h (List.length blocks) (List.length expected) ;
|
||||||
Assert.fail_msg
|
List.iter2
|
||||||
"Invalid locator length %s (found: %d, expected: %d)"
|
(fun h1 h2 ->
|
||||||
h (List.length blocks) (List.length expected) ;
|
if not (Block_hash.equal h1 (State.Block.hash @@ vblock s h2)) then
|
||||||
List.iter2
|
Assert.fail_msg "Invalid locator %s (expected: %s)" h h2)
|
||||||
(fun h1 h2 ->
|
blocks expected ;
|
||||||
if not (Block_hash.equal h1 (vblock s h2).hash) then
|
Lwt.return_unit
|
||||||
Assert.fail_msg "Invalid locator %s (expected: %s)" h h2)
|
|
||||||
blocks expected ;
|
|
||||||
Lwt.return_unit
|
|
||||||
in
|
in
|
||||||
test s "A6" [] >>= fun () ->
|
test s "A6" [] >>= fun () ->
|
||||||
State.Valid_block.Current.set_head s.net (vblock s "A8") >>= fun _ ->
|
Chain.set_head s.net (vblock s "A8") >>= fun _ ->
|
||||||
test s "A6" ["A7";"A8"] >>= fun () ->
|
test s "A6" ["A7";"A8"] >>= fun () ->
|
||||||
test s "A6" ["A7"] >>= fun () ->
|
test s "A6" ["A7"] >>= fun () ->
|
||||||
test s "B4" ["A4"] >>= fun () ->
|
test s "B4" ["A4"] >>= fun () ->
|
||||||
@ -601,74 +442,18 @@ let test_new s =
|
|||||||
|
|
||||||
(****************************************************************************)
|
(****************************************************************************)
|
||||||
|
|
||||||
(** State.mempool *)
|
|
||||||
|
|
||||||
let compare s name mempool l =
|
|
||||||
let mempool_sz = Operation_hash.Set.cardinal mempool in
|
|
||||||
let l_sz = List.length l in
|
|
||||||
if mempool_sz <> l_sz then
|
|
||||||
Assert.fail
|
|
||||||
(string_of_int mempool_sz)
|
|
||||||
(string_of_int l_sz)
|
|
||||||
"unexpected mempool size (%s)" name ;
|
|
||||||
List.iter
|
|
||||||
(fun oname ->
|
|
||||||
try
|
|
||||||
let oph = fst @@ operation s oname in
|
|
||||||
if not (Operation_hash.Set.mem oph mempool) then
|
|
||||||
Assert.fail_msg "missing operation in mempool (%s: %s)" name oname
|
|
||||||
with Not_found ->
|
|
||||||
Assert.fail_msg "Read value not found in mempool (%s: %s)" name oname)
|
|
||||||
l
|
|
||||||
|
|
||||||
let test_mempool s =
|
|
||||||
State.Operation.list_pending s.net >>= fun mempool ->
|
|
||||||
compare s "initial" mempool
|
|
||||||
["PP";
|
|
||||||
"A1" ; "A2" ; "A3" ; "A4" ; "A5" ; "A6" ; "A7" ; "A8" ;
|
|
||||||
"B1" ; "B2" ; "B3" ; "B4" ; "B5" ; "B6" ; "B7" ; "B8" ] ;
|
|
||||||
State.Valid_block.Current.set_head s.net (vblock s "A8") >>= fun _ ->
|
|
||||||
State.Operation.list_pending s.net >>= fun mempool ->
|
|
||||||
compare s "A8" mempool
|
|
||||||
["PP"; "B1" ; "B2" ; "B3" ; "B4" ; "B5" ; "B6" ; "B7" ; "B8" ] ;
|
|
||||||
State.Valid_block.Current.set_head s.net (vblock s "A6") >>= fun _ ->
|
|
||||||
State.Operation.list_pending s.net >>= fun mempool ->
|
|
||||||
compare s "A6" mempool
|
|
||||||
["PP";
|
|
||||||
"A7" ; "A8" ;
|
|
||||||
"B1" ; "B2" ; "B3" ; "B4" ; "B5" ; "B6" ; "B7" ; "B8" ] ;
|
|
||||||
State.Valid_block.Current.set_head s.net (vblock s "B6") >>= fun _ ->
|
|
||||||
State.Operation.list_pending s.net >>= fun mempool ->
|
|
||||||
compare s "B6" mempool
|
|
||||||
["PP";
|
|
||||||
"A4" ; "A5" ; "A6" ; "A7" ; "A8" ;
|
|
||||||
"B7" ; "B8" ] ;
|
|
||||||
State.Operation.mark_invalid s.net (fst @@ operation s "PP") [] >>= fun rm_status ->
|
|
||||||
Assert.is_true ~msg:__LOC__ rm_status ;
|
|
||||||
State.Operation.mark_invalid s.net (fst @@ operation s "PP") [] >>= fun rm_status ->
|
|
||||||
Assert.is_false ~msg:__LOC__ rm_status ;
|
|
||||||
State.Operation.list_pending s.net >>= fun mempool ->
|
|
||||||
compare s "B6.remove" mempool
|
|
||||||
["A4" ; "A5" ; "A6" ; "A7" ; "A8" ;
|
|
||||||
"B7" ; "B8" ] ;
|
|
||||||
return ()
|
|
||||||
|
|
||||||
(****************************************************************************)
|
|
||||||
|
|
||||||
|
|
||||||
let tests : (string * (state -> unit tzresult Lwt.t)) list = [
|
let tests : (string * (state -> unit tzresult Lwt.t)) list = [
|
||||||
"init", test_init ;
|
"init", test_init ;
|
||||||
"read_operation", test_read_operation;
|
|
||||||
"read_block", test_read_block ;
|
"read_block", test_read_block ;
|
||||||
"path", test_path ;
|
"path", test_path ;
|
||||||
"valid_path", test_valid_path ;
|
|
||||||
"ancestor", test_ancestor ;
|
"ancestor", test_ancestor ;
|
||||||
"locator", test_locator ;
|
"locator", test_locator ;
|
||||||
"known_heads", test_known_heads ;
|
"known_heads", test_known_heads ;
|
||||||
"head", test_head ;
|
"head", test_head ;
|
||||||
"mem", test_mem ;
|
"mem", test_mem ;
|
||||||
"new", test_new ;
|
"new_blocks", test_new_blocks ;
|
||||||
"mempool", test_mempool;
|
"find_new", test_find_new ;
|
||||||
]
|
]
|
||||||
|
|
||||||
let () =
|
let () =
|
||||||
|
@ -70,21 +70,6 @@ let oph1 = Tezos_data.Operation.hash op1
|
|||||||
let op2 = make (MBytes.of_string "Kivu")
|
let op2 = make (MBytes.of_string "Kivu")
|
||||||
let oph2 = Tezos_data.Operation.hash op2
|
let oph2 = Tezos_data.Operation.hash op2
|
||||||
|
|
||||||
let check_operation s h b =
|
|
||||||
Operation.Contents.read (s, h) >>= function
|
|
||||||
| Ok b' when Tezos_data.Operation.equal b b' -> Lwt.return_unit
|
|
||||||
| _ ->
|
|
||||||
Printf.eprintf "Error while reading operation %s\n%!"
|
|
||||||
(Operation_hash.to_hex h);
|
|
||||||
exit 1
|
|
||||||
|
|
||||||
let test_operation s =
|
|
||||||
let s = Store.Net.get s net_id in
|
|
||||||
let s = Store.Operation.get s in
|
|
||||||
Operation.Contents.store (s, oph1) op1 >>= fun () ->
|
|
||||||
Operation.Contents.store (s, oph2) op2 >>= fun () ->
|
|
||||||
check_operation s oph1 op1 >>= fun () ->
|
|
||||||
check_operation s oph2 op2
|
|
||||||
|
|
||||||
(** Block store *)
|
(** Block store *)
|
||||||
|
|
||||||
@ -92,57 +77,67 @@ let lolblock ?(operations = []) header =
|
|||||||
let operations_hash =
|
let operations_hash =
|
||||||
Operation_list_list_hash.compute
|
Operation_list_list_hash.compute
|
||||||
[Operation_list_hash.compute operations] in
|
[Operation_list_hash.compute operations] in
|
||||||
{ Tezos_data.Block_header.shell =
|
{ Store.Block.header =
|
||||||
{ timestamp = Time.of_seconds (Random.int64 1500L) ;
|
{ Block_header.shell =
|
||||||
level = 0l ; (* dummy *)
|
{ timestamp = Time.of_seconds (Random.int64 1500L) ;
|
||||||
proto_level = 0 ; (* dummy *)
|
level = 0l ; (* dummy *)
|
||||||
net_id ;
|
proto_level = 0 ; (* dummy *)
|
||||||
predecessor = genesis_block ; operations_hash ;
|
net_id ;
|
||||||
fitness = [MBytes.of_string @@ string_of_int @@ String.length header;
|
predecessor = genesis_block ; operations_hash ;
|
||||||
MBytes.of_string @@ string_of_int @@ 12] } ;
|
fitness = [MBytes.of_string @@ string_of_int @@ String.length header;
|
||||||
proto = MBytes.of_string header ;
|
MBytes.of_string @@ string_of_int @@ 12] } ;
|
||||||
|
proto = MBytes.of_string header ;
|
||||||
|
} ;
|
||||||
|
operation_list_count = Random.int 32 ;
|
||||||
|
message = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
let b1 = lolblock "Blop !"
|
let b1 = lolblock "Blop !"
|
||||||
let bh1 = Tezos_data.Block_header.hash b1
|
let bh1 = Block_header.hash b1.header
|
||||||
let b2 = lolblock "Tacatlopo"
|
let b2 = lolblock "Tacatlopo"
|
||||||
let bh2 = Tezos_data.Block_header.hash b2
|
let bh2 = Block_header.hash b2.header
|
||||||
let b3 = lolblock ~operations:[oph1;oph2] "Persil"
|
let b3 = lolblock ~operations:[oph1;oph2] "Persil"
|
||||||
let bh3 = Tezos_data.Block_header.hash b3
|
let bh3 = Block_header.hash b3.header
|
||||||
let bh3' =
|
let bh3' =
|
||||||
let raw = Bytes.of_string @@ Block_hash.to_string bh3 in
|
let raw = Bytes.of_string @@ Block_hash.to_string bh3 in
|
||||||
Bytes.set raw 31 '\000' ;
|
Bytes.set raw 31 '\000' ;
|
||||||
Bytes.set raw 30 '\000' ;
|
Bytes.set raw 30 '\000' ;
|
||||||
Block_hash.of_string_exn @@ Bytes.to_string raw
|
Block_hash.of_string_exn @@ Bytes.to_string raw
|
||||||
|
|
||||||
|
let equal (b1: Store.Block.contents) (b2: Store.Block.contents) =
|
||||||
|
Block_header.equal b1.header b2.header &&
|
||||||
|
b1.message = b2.message &&
|
||||||
|
b1.operation_list_count = b2.operation_list_count
|
||||||
|
|
||||||
let check_block s h b =
|
let check_block s h b =
|
||||||
Block_header.Contents.read_opt (s, h) >>= function
|
Store.Block.Contents.read (s, h) >>= function
|
||||||
| Some b' when Tezos_data.Block_header.equal b b' -> Lwt.return_unit
|
| Ok b' when equal b b' -> Lwt.return_unit
|
||||||
| Some _ ->
|
| Ok _ ->
|
||||||
Printf.eprintf "Error while reading block %s\n%!" (Block_hash.to_hex h);
|
Printf.eprintf "Error while reading block %s\n%!" (Block_hash.to_hex h);
|
||||||
exit 1
|
exit 1
|
||||||
| None ->
|
| Error err ->
|
||||||
Printf.eprintf "Error while reading block %s (not found)\n%!"
|
Format.eprintf "@[Error while reading block %s:@ %a\n@]"
|
||||||
(Block_hash.to_hex h);
|
(Block_hash.to_hex h)
|
||||||
|
pp_print_error err;
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
let test_block s =
|
let test_block s =
|
||||||
let s = Store.Net.get s net_id in
|
let s = Store.Net.get s net_id in
|
||||||
let s = Store.Block_header.get s in
|
let s = Store.Block.get s in
|
||||||
Block_header.Contents.store (s, bh1) b1 >>= fun () ->
|
Block.Contents.store (s, bh1) b1 >>= fun () ->
|
||||||
Block_header.Contents.store (s, bh2) b2 >>= fun () ->
|
Block.Contents.store (s, bh2) b2 >>= fun () ->
|
||||||
Block_header.Contents.store (s, bh3) b3 >>= fun () ->
|
Block.Contents.store (s, bh3) b3 >>= fun () ->
|
||||||
check_block s bh1 b1 >>= fun () ->
|
check_block s bh1 b1 >>= fun () ->
|
||||||
check_block s bh2 b2 >>= fun () ->
|
check_block s bh2 b2 >>= fun () ->
|
||||||
check_block s bh3 b3
|
check_block s bh3 b3
|
||||||
|
|
||||||
let test_expand s =
|
let test_expand s =
|
||||||
let s = Store.Net.get s net_id in
|
let s = Store.Net.get s net_id in
|
||||||
let s = Store.Block_header.get s in
|
let s = Store.Block.get s in
|
||||||
Block_header.Contents.store (s, bh1) b1 >>= fun () ->
|
Block.Contents.store (s, bh1) b1 >>= fun () ->
|
||||||
Block_header.Contents.store (s, bh2) b2 >>= fun () ->
|
Block.Contents.store (s, bh2) b2 >>= fun () ->
|
||||||
Block_header.Contents.store (s, bh3) b3 >>= fun () ->
|
Block.Contents.store (s, bh3) b3 >>= fun () ->
|
||||||
Block_header.Contents.store (s, bh3') b3 >>= fun () ->
|
Block.Contents.store (s, bh3') b3 >>= fun () ->
|
||||||
Base58.complete (Block_hash.to_short_b58check bh1) >>= fun res ->
|
Base58.complete (Block_hash.to_short_b58check bh1) >>= fun res ->
|
||||||
Assert.equal_string_list ~msg:__LOC__ res [Block_hash.to_b58check bh1] ;
|
Assert.equal_string_list ~msg:__LOC__ res [Block_hash.to_b58check bh1] ;
|
||||||
Base58.complete (Block_hash.to_short_b58check bh2) >>= fun res ->
|
Base58.complete (Block_hash.to_short_b58check bh2) >>= fun res ->
|
||||||
@ -434,10 +429,8 @@ let tests_raw : (string * (Raw_store.t -> unit Lwt.t)) list = [
|
|||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
let tests : (string * (Store.t -> unit Lwt.t)) list = [
|
let tests : (string * (Store.t -> unit Lwt.t)) list = [
|
||||||
"expand", test_expand ;
|
"expand", test_expand ;
|
||||||
"operation", test_operation ;
|
|
||||||
"block", test_block ;
|
"block", test_block ;
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ TESTS := \
|
|||||||
|
|
||||||
include ../Makefile.shared
|
include ../Makefile.shared
|
||||||
|
|
||||||
SOURCE_DIRECTORIES := ${UTILS_SOURCE_DIRECTORIES} ../lib
|
SOURCE_DIRECTORIES := ${COMPILER_SOURCE_DIRECTORIES} ../lib
|
||||||
|
|
||||||
LIB := ${MINUTILSLIB} ${UTILSLIB} ${TESTLIB}
|
LIB := ${MINUTILSLIB} ${UTILSLIB} ${TESTLIB}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user