Merge branch 'level_in_block_header' into 'master'

Move the `level` in the shell part of the block header

See merge request !177
This commit is contained in:
Grégoire Henry 2017-04-12 16:36:49 +02:00
commit f9f5bca5a0
84 changed files with 1253 additions and 1240 deletions

View File

@ -247,7 +247,7 @@ ${TZCLIENT}: minutils.cmxa utils.cmxa compiler.cmxa node.cmxa \
${EMBEDDED_CLIENT_VERSIONS} \ ${EMBEDDED_CLIENT_VERSIONS} \
${CLIENT_IMPLS:.ml=.cmx} ${CLIENT_IMPLS:.ml=.cmx}
@echo LINK $(notdir $@) @echo LINK $(notdir $@)
@${OCAMLOPT} -linkpkg ${OCAMLFLAGS} -o $@ $^ @${OCAMLOPT} -linkall -linkpkg ${OCAMLFLAGS} -o $@ $^
clean:: clean::
-rm -f ${TZCLIENT} -rm -f ${TZCLIENT}
@ -413,7 +413,6 @@ client/embedded/client_%.cmx: \
$(patsubst %.ml, %.cmx, $(NODE_LIB_IMPLS) $(CLIENT_LIB_IMPLS)) \ $(patsubst %.ml, %.cmx, $(NODE_LIB_IMPLS) $(CLIENT_LIB_IMPLS)) \
proto/client_embedded_proto_%.cmxa \ proto/client_embedded_proto_%.cmxa \
$$(shell find client/embedded/% \( -name webclient -or -name _tzbuild \) -prune -or \( -name \*.ml -print -or -name \*.mli -print \)) $$(shell find client/embedded/% \( -name webclient -or -name _tzbuild \) -prune -or \( -name \*.ml -print -or -name \*.mli -print \))
@echo $^
@$(MAKE) -C client/embedded/$* ../client_$*.cmx @$(MAKE) -C client/embedded/$* ../client_$*.cmx
client/embedded/webclient_%.cmx: \ client/embedded/webclient_%.cmx: \

View File

@ -15,9 +15,9 @@ module Services = Node_rpc_services
let errors cctxt = let errors cctxt =
call_service0 cctxt Services.Error.service () call_service0 cctxt Services.Error.service ()
let forge_block cctxt ?net ?predecessor ?timestamp fitness ops header = let forge_block cctxt ?net_id ?level ?predecessor ?timestamp fitness ops header =
call_service0 cctxt Services.forge_block call_service0 cctxt Services.forge_block
(net, predecessor, timestamp, fitness, ops, header) (net_id, level, predecessor, timestamp, fitness, ops, header)
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)
@ -53,16 +53,16 @@ module Blocks = struct
type block_info = Services.Blocks.block_info = { type block_info = Services.Blocks.block_info = {
hash: Block_hash.t ; hash: Block_hash.t ;
net_id: Net_id.t ;
level: Int32.t ;
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
fitness: MBytes.t list ;
timestamp: Time.t ; timestamp: Time.t ;
protocol: Protocol_hash.t option ;
operations_hash: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ;
data: MBytes.t ;
operations: Operation_hash.t list list option ; operations: Operation_hash.t list list option ;
data: MBytes.t option ; protocol: Protocol_hash.t ;
net: Net_id.t ; test_network: Context.test_network;
test_protocol: Protocol_hash.t option ;
test_network: (Net_id.t * Time.t) option ;
} }
type preapply_param = Services.Blocks.preapply_param = { type preapply_param = Services.Blocks.preapply_param = {
operations: Operation_hash.t list ; operations: Operation_hash.t list ;
@ -76,6 +76,8 @@ module Blocks = struct
} }
let net cctxt h = let net cctxt h =
call_service1 cctxt Services.Blocks.net h () call_service1 cctxt Services.Blocks.net h ()
let level cctxt h =
call_service1 cctxt Services.Blocks.level h ()
let predecessor cctxt h = let predecessor cctxt h =
call_service1 cctxt Services.Blocks.predecessor h () call_service1 cctxt Services.Blocks.predecessor h ()
let predecessors cctxt h l = let predecessors cctxt h l =
@ -90,29 +92,28 @@ module Blocks = struct
call_service1 cctxt Services.Blocks.operations h () call_service1 cctxt Services.Blocks.operations h ()
let protocol cctxt h = let protocol cctxt h =
call_service1 cctxt Services.Blocks.protocol h () call_service1 cctxt Services.Blocks.protocol h ()
let test_protocol cctxt h =
call_service1 cctxt Services.Blocks.test_protocol h ()
let test_network cctxt h = let test_network cctxt h =
call_service1 cctxt Services.Blocks.test_network h () call_service1 cctxt Services.Blocks.test_network h ()
let preapply cctxt h ?timestamp ?(sort = false) operations = let preapply cctxt h ?timestamp ?(sort = false) operations =
call_err_service1 call_err_service1
cctxt Services.Blocks.preapply h cctxt Services.Blocks.preapply h
{ operations ; sort ; timestamp } { operations ; sort ; timestamp }
let pending_operations cctxt block = let pending_operations cctxt block =
call_service1 cctxt Services.Blocks.pending_operations block () call_service1 cctxt Services.Blocks.pending_operations block ()
let info cctxt ?(operations = true) ?(data = true) h = let info cctxt ?(include_ops = true) h =
call_service1 cctxt Services.Blocks.info h (operations, data) call_service1 cctxt Services.Blocks.info h include_ops
let complete cctxt block prefix = let complete cctxt block prefix =
call_service2 cctxt Services.Blocks.complete block prefix () call_service2 cctxt Services.Blocks.complete block prefix ()
let list cctxt ?(operations = false) ?(data = false) let list cctxt ?(include_ops = false)
?length ?heads ?delay ?min_date ?min_heads () = ?length ?heads ?delay ?min_date ?min_heads () =
call_service0 cctxt Services.Blocks.list call_service0 cctxt Services.Blocks.list
{ operations ; data ; length ; heads ; monitor = Some false ; delay ; { include_ops ; length ; heads ; monitor = Some false ; delay ;
min_date ; min_heads } min_date ; min_heads }
let monitor cctxt ?(operations = false) ?(data = false) let monitor cctxt ?(include_ops = false)
?length ?heads ?delay ?min_date ?min_heads () = ?length ?heads ?delay ?min_date ?min_heads () =
call_streamed_service0 cctxt Services.Blocks.list call_streamed_service0 cctxt Services.Blocks.list
{ operations ; data ; length ; heads ; monitor = Some true ; delay ; { include_ops ; length ; heads ; monitor = Some true ; delay ;
min_date ; min_heads } min_date ; min_heads }
end end

View File

@ -14,7 +14,8 @@ val errors:
val forge_block: val forge_block:
config -> config ->
?net:Net_id.t -> ?net_id:Net_id.t ->
?level:Int32.t ->
?predecessor:Block_hash.t -> ?predecessor:Block_hash.t ->
?timestamp:Time.t -> ?timestamp:Time.t ->
Fitness.fitness -> Fitness.fitness ->
@ -67,6 +68,9 @@ module Blocks : sig
val net: val net:
config -> config ->
block -> Net_id.t tzresult Lwt.t block -> Net_id.t tzresult Lwt.t
val level:
config ->
block -> Int32.t tzresult Lwt.t
val predecessor: val predecessor:
config -> config ->
block -> Block_hash.t tzresult Lwt.t block -> Block_hash.t tzresult Lwt.t
@ -88,12 +92,9 @@ module Blocks : sig
val protocol: val protocol:
config -> config ->
block -> Protocol_hash.t tzresult Lwt.t block -> Protocol_hash.t tzresult Lwt.t
val test_protocol:
config ->
block -> Protocol_hash.t option tzresult Lwt.t
val test_network: val test_network:
config -> config ->
block -> (Net_id.t * Time.t) option tzresult Lwt.t block -> Context.test_network tzresult Lwt.t
val pending_operations: val pending_operations:
config -> config ->
@ -102,31 +103,31 @@ module Blocks : sig
type block_info = { type block_info = {
hash: Block_hash.t ; hash: Block_hash.t ;
net_id: Net_id.t ;
level: Int32.t ;
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
fitness: MBytes.t list ;
timestamp: Time.t ; timestamp: Time.t ;
protocol: Protocol_hash.t option ;
operations_hash: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ;
data: MBytes.t ;
operations: Operation_hash.t list list option ; operations: Operation_hash.t list list option ;
data: MBytes.t option ; protocol: Protocol_hash.t ;
net: Net_id.t ; test_network: Context.test_network;
test_protocol: Protocol_hash.t option ;
test_network: (Net_id.t * Time.t) option ;
} }
val info: val info:
config -> config ->
?operations:bool -> ?data:bool -> block -> block_info tzresult Lwt.t ?include_ops:bool -> block -> block_info tzresult Lwt.t
val list: val list:
config -> config ->
?operations:bool -> ?data:bool -> ?length:int -> ?heads:Block_hash.t list -> ?include_ops:bool -> ?length:int -> ?heads:Block_hash.t list ->
?delay:int -> ?min_date:Time.t -> ?min_heads:int -> ?delay:int -> ?min_date:Time.t -> ?min_heads:int ->
unit -> block_info list list tzresult Lwt.t unit -> block_info list list tzresult Lwt.t
val monitor: val monitor:
config -> config ->
?operations:bool -> ?data:bool -> ?length:int -> ?heads:Block_hash.t list -> ?include_ops:bool -> ?length:int -> ?heads:Block_hash.t list ->
?delay:int -> ?min_date:Time.t -> ?min_heads:int -> ?delay:int -> ?min_date:Time.t -> ?min_heads:int ->
unit -> block_info list list tzresult Lwt_stream.t tzresult Lwt.t unit -> block_info list list tzresult Lwt_stream.t tzresult Lwt.t

View File

@ -12,7 +12,7 @@ type block_info = {
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
fitness: MBytes.t list ; fitness: MBytes.t list ;
timestamp: Time.t ; timestamp: Time.t ;
protocol: Protocol_hash.t option ; protocol: Protocol_hash.t ;
level: Level.t ; level: Level.t ;
} }
@ -21,7 +21,8 @@ let convert_block_info cctxt
: Client_node_rpcs.Blocks.block_info ) = : Client_node_rpcs.Blocks.block_info ) =
Client_proto_rpcs.Context.level cctxt (`Hash hash) >>= function Client_proto_rpcs.Context.level cctxt (`Hash hash) >>= function
| Ok level -> | Ok level ->
Lwt.return (Some { hash ; predecessor ; fitness ; timestamp ; protocol ; level }) Lwt.return
(Some { hash ; predecessor ; fitness ; timestamp ; protocol ; level })
| Error _ -> | Error _ ->
(* TODO log error *) (* TODO log error *)
Lwt.return_none Lwt.return_none
@ -32,8 +33,8 @@ let convert_block_info_err cctxt
Client_proto_rpcs.Context.level cctxt (`Hash hash) >>=? fun level -> Client_proto_rpcs.Context.level cctxt (`Hash hash) >>=? fun level ->
return { hash ; predecessor ; fitness ; timestamp ; protocol ; level } return { hash ; predecessor ; fitness ; timestamp ; protocol ; level }
let info cctxt ?operations block = let info cctxt ?include_ops block =
Client_node_rpcs.Blocks.info cctxt ?operations block >>=? fun block -> Client_node_rpcs.Blocks.info cctxt ?include_ops block >>=? fun block ->
convert_block_info_err cctxt block convert_block_info_err cctxt block
let compare (bi1 : block_info) (bi2 : block_info) = let compare (bi1 : block_info) (bi2 : block_info) =
@ -54,10 +55,10 @@ let sort_blocks cctxt ?(compare = compare) blocks =
List.sort compare blocks List.sort compare blocks
let monitor cctxt let monitor cctxt
?operations ?length ?heads ?delay ?include_ops ?length ?heads ?delay
?min_date ?min_heads ?compare () = ?min_date ?min_heads ?compare () =
Client_node_rpcs.Blocks.monitor cctxt Client_node_rpcs.Blocks.monitor cctxt
?operations ?length ?heads ?delay ?min_date ?min_heads ?include_ops ?length ?heads ?delay ?min_date ?min_heads
() >>=? fun block_stream -> () >>=? fun block_stream ->
let convert blocks = let convert blocks =
Lwt.return blocks >>=? fun blocks -> Lwt.return blocks >>=? fun blocks ->

View File

@ -12,20 +12,20 @@ type block_info = {
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
fitness: MBytes.t list ; fitness: MBytes.t list ;
timestamp: Time.t ; timestamp: Time.t ;
protocol: Protocol_hash.t option ; protocol: Protocol_hash.t ;
level: Level.t ; level: Level.t ;
} }
val info: val info:
Client_rpcs.config -> Client_rpcs.config ->
?operations:bool -> Client_node_rpcs.Blocks.block -> block_info tzresult Lwt.t ?include_ops:bool -> Client_node_rpcs.Blocks.block -> block_info tzresult Lwt.t
val compare: val compare:
block_info -> block_info -> int block_info -> block_info -> int
val monitor: val monitor:
Client_rpcs.config -> Client_rpcs.config ->
?operations:bool -> ?length:int -> ?heads:Block_hash.t list -> ?include_ops:bool -> ?length:int -> ?heads:Block_hash.t list ->
?delay:int -> ?min_date:Time.t -> ?min_heads:int -> ?delay:int -> ?min_date:Time.t -> ?min_heads:int ->
?compare:(block_info -> block_info -> int) -> ?compare:(block_info -> block_info -> int) ->
unit -> block_info list tzresult Lwt_stream.t tzresult Lwt.t unit -> block_info list tzresult Lwt_stream.t tzresult Lwt.t

View File

@ -22,14 +22,14 @@ let generate_seed_nonce () =
| Ok nonce -> nonce | Ok nonce -> nonce
let rec compute_stamp let rec compute_stamp
cctxt block delegate_sk shell mining_slot seed_nonce_hash = cctxt block delegate_sk shell priority seed_nonce_hash =
Client_proto_rpcs.Constants.stamp_threshold Client_proto_rpcs.Constants.stamp_threshold
cctxt block >>=? fun stamp_threshold -> cctxt block >>=? fun stamp_threshold ->
let rec loop () = let rec loop () =
let proof_of_work_nonce = generate_proof_of_work_nonce () in let proof_of_work_nonce = generate_proof_of_work_nonce () in
let unsigned_header = let unsigned_header =
Tezos_context.Block.forge_header Tezos_context.Block.forge_header
shell { mining_slot ; seed_nonce_hash ; proof_of_work_nonce } in shell { priority ; seed_nonce_hash ; proof_of_work_nonce } in
let signed_header = let signed_header =
Ed25519.Signature.append delegate_sk unsigned_header in Ed25519.Signature.append delegate_sk unsigned_header in
let block_hash = Block_hash.hash_bytes [signed_header] in let block_hash = Block_hash.hash_bytes [signed_header] in
@ -42,28 +42,26 @@ let rec compute_stamp
let inject_block cctxt block let inject_block cctxt block
?force ?force
~priority ~timestamp ~fitness ~seed_nonce ~priority ~timestamp ~fitness ~seed_nonce
~src_sk operation_list = ~src_sk operations =
let block = match block with `Prevalidation -> `Head 0 | block -> block in let block = match block with `Prevalidation -> `Head 0 | block -> block in
Client_node_rpcs.Blocks.info cctxt block >>=? fun bi -> Client_node_rpcs.Blocks.info cctxt block >>=? fun bi ->
let seed_nonce_hash = Nonce.hash seed_nonce in let seed_nonce_hash = Nonce.hash seed_nonce in
Client_proto_rpcs.Context.next_level cctxt block >>=? fun level -> Client_proto_rpcs.Context.next_level cctxt block >>=? fun level ->
let operations = let operations_hash =
Operation_list_list_hash.compute Operation_list_list_hash.compute
(List.map Operation_list_hash.compute operation_list) in (List.map Operation_list_hash.compute operations) in
let shell = let shell =
{ Store.Block_header.net_id = bi.net ; predecessor = bi.hash ; { Store.Block_header.net_id = bi.net_id ; level = bi.level ;
timestamp ; fitness ; operations } in predecessor = bi.hash ; timestamp ; fitness ; operations_hash } in
let slot =
{ Block.level = level.level ; priority = Int32.of_int priority } in
compute_stamp cctxt block compute_stamp cctxt block
src_sk shell slot seed_nonce_hash >>=? fun proof_of_work_nonce -> src_sk shell priority seed_nonce_hash >>=? fun proof_of_work_nonce ->
Client_proto_rpcs.Helpers.Forge.block cctxt Client_proto_rpcs.Helpers.Forge.block cctxt
block block
~net:bi.net ~net:bi.net_id
~predecessor:bi.hash ~predecessor:bi.hash
~timestamp ~timestamp
~fitness ~fitness
~operations ~operations_hash
~level:level.level ~level:level.level
~priority:priority ~priority:priority
~seed_nonce_hash ~seed_nonce_hash
@ -71,7 +69,7 @@ let inject_block cctxt block
() >>=? fun unsigned_header -> () >>=? fun unsigned_header ->
let signed_header = Ed25519.Signature.append src_sk unsigned_header in let signed_header = Ed25519.Signature.append src_sk unsigned_header in
Client_node_rpcs.inject_block cctxt Client_node_rpcs.inject_block cctxt
?force signed_header operation_list >>=? fun block_hash -> ?force signed_header operations >>=? fun block_hash ->
return block_hash return block_hash
let forge_block cctxt block let forge_block cctxt block

View File

@ -64,11 +64,7 @@ end
module Context = struct module Context = struct
let level cctxt block = let level cctxt block =
match block with call_error_service1 cctxt Services.Context.level block ()
| `Genesis -> return Level.root
| `Hash h when Block_hash.equal Client_blocks.genesis h ->
return Level.root
| _ -> call_error_service1 cctxt Services.Context.level block ()
let next_level cctxt block = let next_level cctxt block =
call_error_service1 cctxt Services.Context.next_level block () call_error_service1 cctxt Services.Context.next_level block ()
@ -249,10 +245,10 @@ module Helpers = struct
operations cctxt block ~net [Faucet { id ; nonce }] operations cctxt block ~net [Faucet { id ; nonce }]
end end
let block cctxt let block cctxt
block ~net ~predecessor ~timestamp ~fitness ~operations block ~net ~predecessor ~timestamp ~fitness ~operations_hash
~level ~priority ~seed_nonce_hash ~proof_of_work_nonce () = ~level ~priority ~seed_nonce_hash ~proof_of_work_nonce () =
call_error_service1 cctxt Services.Helpers.Forge.block block call_error_service1 cctxt Services.Helpers.Forge.block block
(net, predecessor, timestamp, fitness, operations, (net, predecessor, timestamp, fitness, operations_hash,
level, priority, seed_nonce_hash, proof_of_work_nonce) level, priority, seed_nonce_hash, proof_of_work_nonce)
end end

View File

@ -35,7 +35,7 @@ module Constants : sig
block -> (Period.t list) tzresult Lwt.t block -> (Period.t list) tzresult Lwt.t
val first_free_mining_slot: val first_free_mining_slot:
Client_rpcs.config -> Client_rpcs.config ->
block -> int32 tzresult Lwt.t block -> int tzresult Lwt.t
val max_signing_slot: val max_signing_slot:
Client_rpcs.config -> Client_rpcs.config ->
block -> int tzresult Lwt.t block -> int tzresult Lwt.t
@ -298,7 +298,7 @@ module Helpers : sig
predecessor:Block_hash.t -> predecessor:Block_hash.t ->
timestamp:Time.t -> timestamp:Time.t ->
fitness:Fitness.t -> fitness:Fitness.t ->
operations:Operation_list_list_hash.t -> operations_hash:Operation_list_list_hash.t ->
level:Raw_level.t -> level:Raw_level.t ->
priority:int -> priority:int ->
seed_nonce_hash:Nonce_hash.t -> seed_nonce_hash:Nonce_hash.t ->

View File

@ -51,7 +51,7 @@ let mine cctxt =
(cctxt.message "Cannot parse fitness: %a" Fitness.pp bi.fitness); (cctxt.message "Cannot parse fitness: %a" Fitness.pp bi.fitness);
exit 2 in exit 2 in
Client_node_rpcs.forge_block cctxt.rpc_config Client_node_rpcs.forge_block cctxt.rpc_config
~net:bi.net ~predecessor:bi.hash ~net_id:bi.net_id ~predecessor:bi.hash
fitness Operation_list_list_hash.empty (MBytes.create 0) >>=? fun bytes -> fitness Operation_list_list_hash.empty (MBytes.create 0) >>=? fun bytes ->
Client_node_rpcs.inject_block cctxt.rpc_config bytes [] >>=? fun hash -> Client_node_rpcs.inject_block cctxt.rpc_config bytes [] >>=? fun hash ->
cctxt.answer "Injected %a" Block_hash.pp_short hash >>= fun () -> cctxt.answer "Injected %a" Block_hash.pp_short hash >>= fun () ->

View File

@ -26,13 +26,15 @@ let call_error_service1 rpc_config s block a1 =
let forge_block let forge_block
rpc_config block net_id ?(timestamp = Time.now ()) command fitness = rpc_config block net_id ?(timestamp = Time.now ()) command fitness =
Client_blocks.get_block_hash rpc_config block >>=? fun pred -> Client_blocks.get_block_hash rpc_config block >>=? fun pred ->
Client_node_rpcs.Blocks.level rpc_config block >>=? fun level ->
call_service1 rpc_config call_service1 rpc_config
Services.Forge.block block Services.Forge.block block
((net_id, pred, timestamp, fitness), command) ((net_id, Int32.succ level, pred, timestamp, fitness), command)
let mine rpc_config ?timestamp block command fitness seckey = let mine rpc_config ?timestamp block command fitness seckey =
Client_blocks.get_block_info rpc_config block >>=? fun bi -> Client_blocks.get_block_info rpc_config block >>=? fun bi ->
forge_block rpc_config ?timestamp block bi.net command fitness >>=? fun blk -> forge_block
rpc_config ?timestamp block bi.net_id command fitness >>=? fun blk ->
let signed_blk = Environment.Ed25519.Signature.append seckey blk in let signed_blk = Environment.Ed25519.Signature.append seckey blk in
Client_node_rpcs.inject_block rpc_config signed_blk [[]] Client_node_rpcs.inject_block rpc_config signed_blk [[]]
@ -86,7 +88,8 @@ let commands () =
let fitness = let fitness =
Client_embedded_proto_alpha.Fitness_repr.from_int64 fitness in Client_embedded_proto_alpha.Fitness_repr.from_int64 fitness in
mine cctxt.rpc_config ?timestamp cctxt.config.block mine cctxt.rpc_config ?timestamp cctxt.config.block
(Activate_testnet hash) fitness seckey >>=? fun hash -> (Activate_testnet (hash, Int64.mul 24L 3600L))
fitness seckey >>=? fun hash ->
cctxt.answer "Injected %a" Block_hash.pp_short hash >>= fun () -> cctxt.answer "Injected %a" Block_hash.pp_short hash >>= fun () ->
return () return ()
end ; end ;

View File

@ -84,14 +84,7 @@ type t = context
(*-- Version Access and Update -----------------------------------------------*) (*-- Version Access and Update -----------------------------------------------*)
let current_protocol_key = ["protocol"] let current_protocol_key = ["protocol"]
let current_fitness_key = ["fitness"]
let current_timestamp_key = ["timestamp"]
let current_test_protocol_key = ["test_protocol"]
let current_test_network_key = ["test_network"] let current_test_network_key = ["test_network"]
let current_test_network_expiration_key = ["test_network_expiration"]
let current_fork_test_network_key = ["fork_test_network"]
let transient_commit_message_key = ["message"]
let exists { repo } key = let exists { repo } key =
GitStore.of_branch_id GitStore.of_branch_id
@ -134,59 +127,17 @@ let exists index key =
Block_hash.pp_short key exists >>= fun () -> Block_hash.pp_short key exists >>= fun () ->
Lwt.return exists Lwt.return exists
let get_and_erase_commit_message ctxt =
GitStore.FunView.get ctxt.view transient_commit_message_key >>= function
| None -> Lwt.return (None, ctxt)
| Some bytes ->
GitStore.FunView.del ctxt.view transient_commit_message_key >>= fun view ->
Lwt.return (Some (MBytes.to_string bytes), { ctxt with view })
let set_commit_message ctxt msg =
GitStore.FunView.set ctxt.view
transient_commit_message_key
(MBytes.of_string msg) >>= fun view ->
Lwt.return { ctxt with view }
let get_fitness { view } =
GitStore.FunView.get view current_fitness_key >>= function
| None -> assert false
| Some data ->
match Data_encoding.Binary.of_bytes Fitness.encoding data with
| None -> assert false
| Some data -> Lwt.return data
let set_fitness ctxt data =
GitStore.FunView.set ctxt.view current_fitness_key
(Data_encoding.Binary.to_bytes Fitness.encoding data) >>= fun view ->
Lwt.return { ctxt with view }
let get_timestamp { view } =
GitStore.FunView.get view current_timestamp_key >>= function
| None -> assert false
| Some time ->
Lwt.return (Time.of_notation_exn (MBytes.to_string time))
let set_timestamp ctxt time =
GitStore.FunView.set ctxt.view current_timestamp_key
(MBytes.of_string (Time.to_notation time)) >>= fun view ->
Lwt.return { ctxt with view }
exception Preexistent_context of Block_hash.t exception Preexistent_context of Block_hash.t
exception Empty_head of Block_hash.t exception Empty_head of Block_hash.t
let commit key context = let commit key ~time ~message context =
get_timestamp context >>= fun timestamp -> let task = Irmin.Task.create ~date:(Time.to_seconds time) ~owner:"Tezos" in
get_fitness context >>= fun fitness ->
let task =
Irmin.Task.create ~date:(Time.to_seconds timestamp) ~owner:"Tezos" in
GitStore.clone task context.store (Block_hash.to_b58check key) >>= function GitStore.clone task context.store (Block_hash.to_b58check key) >>= function
| `Empty_head -> Lwt.fail (Empty_head key) | `Empty_head -> Lwt.fail (Empty_head key)
| `Duplicated_branch -> Lwt.fail (Preexistent_context key) | `Duplicated_branch -> Lwt.fail (Preexistent_context key)
| `Ok store -> | `Ok store ->
get_and_erase_commit_message context >>= fun (msg, context) -> GitStore.FunView.update_path
let msg = match msg with (store message) [] context.view >>= fun () ->
| None ->
Format.asprintf "%a %a"
Fitness.pp fitness Block_hash.pp_short key
| Some msg -> msg in
GitStore.FunView.update_path (store msg) [] context.view >>= fun () ->
context.index.commits <- context.index.commits + 1 ; context.index.commits <- context.index.commits + 1 ;
if context.index.commits mod 200 = 0 then if context.index.commits mod 200 = 0 then
Lwt_utils.Idle_waiter.force_idle Lwt_utils.Idle_waiter.force_idle
@ -250,6 +201,77 @@ let remove_rec ctxt key =
GitStore.FunView.remove_rec ctxt.view (data_key key) >>= fun view -> GitStore.FunView.remove_rec ctxt.view (data_key key) >>= fun view ->
Lwt.return { ctxt with view } Lwt.return { ctxt with view }
(*-- Predefined Fields -------------------------------------------------------*)
let get_protocol v =
raw_get v current_protocol_key >>= function
| None -> assert false
| Some data -> Lwt.return (Protocol_hash.of_bytes_exn data)
let set_protocol v key =
raw_set v current_protocol_key (Protocol_hash.to_bytes key)
type test_network =
| Not_running
| Forking of {
protocol: Protocol_hash.t ;
expiration: Time.t ;
}
| Running of {
net_id: Net_id.t ;
genesis: Block_hash.t ;
protocol: Protocol_hash.t ;
expiration: Time.t ;
}
let test_network_encoding =
let open Data_encoding in
union [
case ~tag:0
(obj1 (req "status" (constant "not_running")))
(function Not_running -> Some () | _ -> None)
(fun () -> Not_running) ;
case ~tag:1
(obj3
(req "status" (constant "forking"))
(req "protocol" Protocol_hash.encoding)
(req "expiration" Time.encoding))
(function
| Forking { protocol ; expiration } ->
Some ((), protocol, expiration)
| _ -> None)
(fun ((), protocol, expiration) ->
Forking { protocol ; expiration }) ;
case ~tag:2
(obj5
(req "status" (constant "running"))
(req "net_id" Net_id.encoding)
(req "genesis" Block_hash.encoding)
(req "protocol" Protocol_hash.encoding)
(req "expiration" Time.encoding))
(function
| Running { net_id ; genesis ; protocol ; expiration } ->
Some ((), net_id, genesis, protocol, expiration)
| _ -> None)
(fun ((), net_id, genesis, protocol, expiration) ->
Running { net_id ; genesis ;protocol ; expiration }) ;
]
let get_test_network v =
raw_get v current_test_network_key >>= function
| None -> Lwt.fail (Failure "Unexpected error (Context.get_test_network)")
| Some data ->
match Data_encoding.Binary.of_bytes test_network_encoding data with
| None -> Lwt.fail (Failure "Unexpected error (Context.get_test_network)")
| Some r -> Lwt.return r
let set_test_network v id =
raw_set v current_test_network_key
(Data_encoding.Binary.to_bytes test_network_encoding id)
let del_test_network v = raw_del v current_test_network_key
let fork_test_network v ~protocol ~expiration =
set_test_network v (Forking { protocol ; expiration })
(*-- Initialisation ----------------------------------------------------------*) (*-- Initialisation ----------------------------------------------------------*)
let init ?patch_context ~root = let init ?patch_context ~root =
@ -266,86 +288,48 @@ let init ?patch_context ~root =
| Some patch_context -> patch_context | Some patch_context -> patch_context
} }
let commit_genesis index ~id:block ~time ~protocol ~test_protocol = let commit_genesis index ~id:block ~time ~protocol =
let task = Irmin.Task.create ~date:(Time.to_seconds time) ~owner:"Tezos" in
GitStore.of_branch_id GitStore.of_branch_id
Irmin.Task.none (Block_hash.to_b58check block) task (Block_hash.to_b58check block)
index.repo >>= fun t -> index.repo >>= fun t ->
let store = t () in let store = t "Genesis" in
GitStore.FunView.of_path store [] >>= fun view -> GitStore.FunView.of_path store [] >>= fun view ->
let view = (view, index.repack_scheduler) in let view = (view, index.repack_scheduler) in
GitStore.FunView.set view current_timestamp_key
(MBytes.of_string (Time.to_notation time)) >>= fun view ->
GitStore.FunView.set view current_protocol_key
(Protocol_hash.to_bytes protocol) >>= fun view ->
GitStore.FunView.set view current_fitness_key
(Data_encoding.Binary.to_bytes Fitness.encoding []) >>= fun view ->
GitStore.FunView.set view current_test_protocol_key
(Protocol_hash.to_bytes test_protocol) >>= fun view ->
let ctxt = { index ; store ; view } in let ctxt = { index ; store ; view } in
set_protocol ctxt protocol >>= fun ctxt ->
set_test_network ctxt Not_running >>= fun ctxt ->
index.patch_context ctxt >>= fun ctxt -> index.patch_context ctxt >>= fun ctxt ->
GitStore.FunView.update_path ctxt.store [] ctxt.view >>= fun () -> GitStore.FunView.update_path ctxt.store [] ctxt.view >>= fun () ->
Lwt.return ctxt Lwt.return ctxt
(*-- Predefined Fields -------------------------------------------------------*) let compute_testnet_genesis forked_block =
let genesis = Block_hash.hash_bytes [Block_hash.to_bytes forked_block] in
let net_id = Net_id.of_block_hash genesis in
net_id, genesis
let get_protocol v = let commit_test_network_genesis forked_block time ctxt =
raw_get v current_protocol_key >>= function let net_id, genesis = compute_testnet_genesis forked_block in
| None -> assert false let task = Irmin.Task.create ~date:(Time.to_seconds time) ~owner:"Tezos" in
| Some data -> Lwt.return (Protocol_hash.of_bytes_exn data) GitStore.clone task ctxt.store (Block_hash.to_b58check genesis) >>= function
let set_protocol v key = | `Empty_head -> fail (Exn (Empty_head genesis))
raw_set v current_protocol_key (Protocol_hash.to_bytes key) | `Duplicated_branch -> fail (Exn (Preexistent_context genesis))
let get_test_protocol v =
raw_get v current_test_protocol_key >>= function
| None -> assert false
| Some data -> Lwt.return (Protocol_hash.of_bytes_exn data)
let set_test_protocol v data =
raw_set v current_test_protocol_key (Protocol_hash.to_bytes data)
let get_test_network v =
raw_get v current_test_network_key >>= function
| None -> Lwt.return_none
| Some data -> Lwt.return (Some (Net_id.of_bytes_exn data))
let set_test_network v id =
raw_set v current_test_network_key (Net_id.to_bytes id)
let del_test_network v = raw_del v current_test_network_key
let get_test_network_expiration v =
raw_get v current_test_network_expiration_key >>= function
| None -> Lwt.return_none
| Some data -> Lwt.return (Time.of_notation @@ MBytes.to_string data)
let set_test_network_expiration v data =
raw_set v current_test_network_expiration_key
(MBytes.of_string @@ Time.to_notation data)
let del_test_network_expiration v =
raw_del v current_test_network_expiration_key
let read_and_reset_fork_test_network v =
raw_get v current_fork_test_network_key >>= function
| None -> Lwt.return (false, v)
| Some _ ->
raw_del v current_fork_test_network_key >>= fun v ->
Lwt.return (true, v)
let fork_test_network v =
raw_set v current_fork_test_network_key (MBytes.of_string "fork")
let init_test_network v ~time ~genesis =
get_test_protocol v >>= fun test_protocol ->
del_test_network_expiration v >>= fun v ->
set_protocol v test_protocol >>= fun v ->
set_timestamp v time >>= fun v ->
let task =
Irmin.Task.create
~date:(Time.to_seconds time)
~owner:"tezos" in
GitStore.clone task v.store (Block_hash.to_b58check genesis) >>= function
| `Empty_head -> Lwt.return (Error [Exn (Empty_head genesis)])
| `Duplicated_branch -> Lwt.return (Error [Exn (Preexistent_context genesis)])
| `Ok store -> | `Ok store ->
let msg = let msg =
Format.asprintf "Fake block. Forking testnet: %a." Format.asprintf "Forking testnet: %a." Net_id.pp_short net_id in
Block_hash.pp_short genesis in GitStore.FunView.update_path (store msg) [] ctxt.view >>= fun () ->
GitStore.FunView.update_path (store msg) [] v.view >>= fun () -> return (net_id, genesis)
return v
let reset_test_network ctxt forked_block timestamp =
get_test_network ctxt >>= function
| Not_running -> Lwt.return ctxt
| Running { expiration } ->
if Time.(expiration <= timestamp) then
set_test_network ctxt Not_running
else
Lwt.return ctxt
| Forking { protocol ; expiration } ->
let net_id, genesis = compute_testnet_genesis forked_block in
set_test_network ctxt
(Running { net_id ; genesis ;
protocol ; expiration })

View File

@ -27,9 +27,12 @@ val commit_genesis:
id:Block_hash.t -> id:Block_hash.t ->
time:Time.t -> time:Time.t ->
protocol:Protocol_hash.t -> protocol:Protocol_hash.t ->
test_protocol:Protocol_hash.t ->
context Lwt.t context Lwt.t
val commit_test_network_genesis:
Block_hash.t -> Time.t -> context ->
(Net_id.t * Block_hash.t) tzresult Lwt.t
(** {2 Generic interface} ****************************************************) (** {2 Generic interface} ****************************************************)
include Persist.STORE with type t := context include Persist.STORE with type t := context
@ -40,34 +43,37 @@ exception Preexistent_context of Block_hash.t
val exists: index -> Block_hash.t -> bool Lwt.t val exists: index -> Block_hash.t -> bool Lwt.t
val checkout: index -> Block_hash.t -> context option Lwt.t val checkout: index -> Block_hash.t -> context option Lwt.t
val checkout_exn: index -> Block_hash.t -> context Lwt.t val checkout_exn: index -> Block_hash.t -> context Lwt.t
val commit: Block_hash.t -> context -> unit Lwt.t val commit:
Block_hash.t ->
time:Time.t ->
message:string ->
context -> unit Lwt.t
(** {2 Predefined Fields} ****************************************************) (** {2 Predefined Fields} ****************************************************)
val get_protocol: context -> Protocol_hash.t Lwt.t val get_protocol: context -> Protocol_hash.t Lwt.t
val set_protocol: context -> Protocol_hash.t -> context Lwt.t val set_protocol: context -> Protocol_hash.t -> context Lwt.t
val get_test_protocol: context -> Protocol_hash.t Lwt.t type test_network =
val set_test_protocol: context -> Protocol_hash.t -> context Lwt.t | Not_running
| Forking of {
protocol: Protocol_hash.t ;
expiration: Time.t ;
}
| Running of {
net_id: Net_id.t ;
genesis: Block_hash.t ;
protocol: Protocol_hash.t ;
expiration: Time.t ;
}
val get_test_network: context -> Net_id.t option Lwt.t val test_network_encoding: test_network Data_encoding.t
val set_test_network: context -> Net_id.t -> context Lwt.t
val get_test_network: context -> test_network Lwt.t
val set_test_network: context -> test_network -> context Lwt.t
val del_test_network: context -> context Lwt.t val del_test_network: context -> context Lwt.t
val get_test_network_expiration: context -> Time.t option Lwt.t val reset_test_network: context -> Block_hash.t -> Time.t -> context Lwt.t
val set_test_network_expiration: context -> Time.t -> context Lwt.t
val del_test_network_expiration: context -> context Lwt.t
val read_and_reset_fork_test_network: context -> (bool * context) Lwt.t val fork_test_network:
val fork_test_network: context -> context Lwt.t context -> protocol:Protocol_hash.t -> expiration:Time.t -> context Lwt.t
val set_fitness: context -> Fitness.fitness -> context Lwt.t
val get_fitness: context -> Fitness.fitness Lwt.t
val set_timestamp: context -> Time.t -> context Lwt.t
val get_timestamp: context -> Time.t Lwt.t
val set_commit_message: context -> string -> context Lwt.t
val init_test_network:
context -> time:Time.t -> genesis:Block_hash.t -> context tzresult Lwt.t

View File

@ -61,14 +61,8 @@ module Net = struct
(struct let name = ["expiration"] end) (struct let name = ["expiration"] end)
(Store_helpers.Make_value(Time)) (Store_helpers.Make_value(Time))
module Forked_network_ttl = module Allow_forked_network =
Store_helpers.Make_single_store Indexed_store.Make_set (struct let name = ["allow_forked_network"] end)
(Indexed_store.Store)
(struct let name = ["forked_network_ttl"] end)
(Store_helpers.Make_value(struct
type t = Int64.t
let encoding = Data_encoding.int64
end))
end end
@ -258,24 +252,30 @@ module Block_header = struct
type shell_header = { type shell_header = {
net_id: Net_id.t ; net_id: Net_id.t ;
level: Int32.t ;
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
timestamp: Time.t ; timestamp: Time.t ;
operations: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ; fitness: MBytes.t list ;
} }
let shell_header_encoding = let shell_header_encoding =
let open Data_encoding in let open Data_encoding in
conv conv
(fun { net_id ; predecessor ; timestamp ; operations ; fitness } -> (fun { net_id ; level ; predecessor ;
(net_id, predecessor, timestamp, operations, fitness)) timestamp ; operations_hash ; fitness } ->
(fun (net_id, predecessor, timestamp, operations, fitness) -> (net_id, level, predecessor,
{ net_id ; predecessor ; timestamp ; operations ; fitness }) timestamp, operations_hash, fitness))
(obj5 (fun (net_id, level, predecessor,
timestamp, operations_hash, fitness) ->
{ net_id ; level ; predecessor ;
timestamp ; operations_hash ; fitness })
(obj6
(req "net_id" Net_id.encoding) (req "net_id" Net_id.encoding)
(req "level" int32)
(req "predecessor" Block_hash.encoding) (req "predecessor" Block_hash.encoding)
(req "timestamp" Time.encoding) (req "timestamp" Time.encoding)
(req "operations" Operation_list_list_hash.encoding) (req "operations_hash" Operation_list_list_hash.encoding)
(req "fitness" Fitness.encoding)) (req "fitness" Fitness.encoding))
module Encoding = struct module Encoding = struct
@ -307,7 +307,7 @@ module Block_header = struct
Block_hash.compare b1.shell.predecessor b2.shell.predecessor >> fun () -> Block_hash.compare b1.shell.predecessor b2.shell.predecessor >> fun () ->
compare b1.proto b2.proto >> fun () -> compare b1.proto b2.proto >> fun () ->
Operation_list_list_hash.compare Operation_list_list_hash.compare
b1.shell.operations b2.shell.operations >> fun () -> b1.shell.operations_hash b2.shell.operations_hash >> fun () ->
Time.compare b1.shell.timestamp b2.shell.timestamp >> fun () -> Time.compare b1.shell.timestamp b2.shell.timestamp >> fun () ->
list compare b1.shell.fitness b2.shell.fitness list compare b1.shell.fitness b2.shell.fitness

View File

@ -46,9 +46,9 @@ module Net : sig
with type t := store with type t := store
and type value := Time.t and type value := Time.t
module Forked_network_ttl : SINGLE_STORE module Allow_forked_network : SET_STORE
with type t := store with type t := t
and type value := Int64.t and type elt := Net_id.t
end end
@ -171,9 +171,10 @@ module Block_header : sig
type shell_header = { type shell_header = {
net_id: Net_id.t ; net_id: Net_id.t ;
level: Int32.t ;
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
timestamp: Time.t ; timestamp: Time.t ;
operations: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ; fitness: MBytes.t list ;
} }
val shell_header_encoding: shell_header Data_encoding.t val shell_header_encoding: shell_header Data_encoding.t

View File

@ -27,8 +27,6 @@ let context_dir data_dir = data_dir // "context"
let protocol_dir data_dir = data_dir // "protocol" let protocol_dir data_dir = data_dir // "protocol"
let lock_file data_dir = data_dir // "lock" let lock_file data_dir = data_dir // "lock"
let test_protocol = None
let init_logger ?verbosity (log_config : Node_config_file.log) = let init_logger ?verbosity (log_config : Node_config_file.log) =
let open Logging in let open Logging in
begin begin
@ -116,11 +114,11 @@ let init_node ?sandbox (config : Node_config_file.t) =
end >>=? fun p2p_config -> end >>=? fun p2p_config ->
let node_config : Node.config = { let node_config : Node.config = {
genesis ; genesis ;
test_protocol ;
patch_context ; patch_context ;
store_root = store_dir config.data_dir ; store_root = store_dir config.data_dir ;
context_root = context_dir config.data_dir ; context_root = context_dir config.data_dir ;
p2p = p2p_config ; p2p = p2p_config ;
test_network_max_tll = Some (48 * 3600) ; (* 2 days *)
} in } in
Node.create node_config Node.create node_config

View File

@ -348,7 +348,7 @@ module P2p_reader = struct
| None -> Lwt.return_unit | None -> Lwt.return_unit
| Some bh -> | Some bh ->
if Operation_list_list_hash.compare if Operation_list_list_hash.compare
found_hash bh.shell.operations <> 0 then found_hash bh.shell.operations_hash <> 0 then
Lwt.return_unit Lwt.return_unit
else else
Raw_operation_list.Table.notify Raw_operation_list.Table.notify
@ -624,7 +624,7 @@ let inject_block t bytes operations =
(List.map Operation_list_hash.compute operations) in (List.map Operation_list_hash.compute operations) in
fail_unless fail_unless
(Operation_list_list_hash.compare (Operation_list_list_hash.compare
computed_hash block.shell.operations = 0) computed_hash block.shell.operations_hash = 0)
(Exn (Failure "Incoherent operation list")) >>=? fun () -> (Exn (Failure "Incoherent operation list")) >>=? fun () ->
Raw_block_header.Table.inject Raw_block_header.Table.inject
net_db.block_header_db.table hash block >>= function net_db.block_header_db.table hash block >>= function

View File

@ -87,29 +87,28 @@ type config = {
genesis: State.Net.genesis ; genesis: State.Net.genesis ;
store_root: string ; store_root: string ;
context_root: string ; context_root: string ;
test_protocol: Protocol_hash.t option ;
patch_context: (Context.t -> Context.t Lwt.t) option ; patch_context: (Context.t -> Context.t Lwt.t) option ;
p2p: (P2p.config * P2p.limits) option ; p2p: (P2p.config * P2p.limits) option ;
test_network_max_tll: int option ;
} }
let may_create_net state ?test_protocol genesis = let may_create_net state genesis =
State.Net.get state (Net_id.of_block_hash genesis.State.Net.block) >>= function State.Net.get state (Net_id.of_block_hash genesis.State.Net.block) >>= function
| Ok net -> Lwt.return net | Ok net -> Lwt.return net
| Error _ -> | Error _ ->
State.Net.create state State.Net.create state genesis
?test_protocol
~forked_network_ttl:(48 * 3600) (* 2 days *)
genesis
let create { genesis ; store_root ; context_root ; let create { genesis ; store_root ; context_root ;
test_protocol ; patch_context ; p2p = net_params } = patch_context ; p2p = net_params ;
test_network_max_tll = max_ttl } =
init_p2p net_params >>= fun p2p -> init_p2p net_params >>= fun p2p ->
State.read State.read
~store_root ~context_root ?patch_context () >>=? fun state -> ~store_root ~context_root ?patch_context () >>=? fun state ->
let distributed_db = Distributed_db.create state p2p in let distributed_db = Distributed_db.create state p2p in
let validator = Validator.create_worker state distributed_db in let validator =
may_create_net state ?test_protocol genesis >>= fun mainnet_net -> Validator.create_worker ?max_ttl state distributed_db in
may_create_net state genesis >>= fun mainnet_net ->
Validator.activate validator mainnet_net >>= fun mainnet_validator -> Validator.activate validator mainnet_net >>= fun mainnet_validator ->
let mainnet_db = Validator.net_db mainnet_validator in let mainnet_db = Validator.net_db mainnet_validator in
let shutdown () = let shutdown () =
@ -138,46 +137,32 @@ module RPC = struct
type block = Node_rpc_services.Blocks.block type block = Node_rpc_services.Blocks.block
type block_info = Node_rpc_services.Blocks.block_info = { type block_info = Node_rpc_services.Blocks.block_info = {
hash: Block_hash.t ; hash: Block_hash.t ;
net_id: Net_id.t ;
level: Int32.t ;
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
fitness: MBytes.t list ;
timestamp: Time.t ; timestamp: Time.t ;
protocol: Protocol_hash.t option ;
operations_hash: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ;
data: MBytes.t ;
operations: Operation_hash.t list list option ; operations: Operation_hash.t list list option ;
data: MBytes.t option ; protocol: Protocol_hash.t ;
net: Net_id.t ; test_network: Context.test_network;
test_protocol: Protocol_hash.t option ;
test_network: (Net_id.t * Time.t) option ;
} }
let convert (block: State.Valid_block.t) = { let convert (block: State.Valid_block.t) = {
hash = block.hash ; hash = block.hash ;
predecessor = block.pred ; net_id = block.net_id ;
fitness = block.fitness ; level = block.level ;
predecessor = block.predecessor ;
timestamp = block.timestamp ; timestamp = block.timestamp ;
protocol = Some block.protocol_hash ;
operations_hash = block.operations_hash ; operations_hash = block.operations_hash ;
fitness = block.fitness ;
data = block.proto_header ;
operations = Some block.operations ; operations = Some block.operations ;
data = Some block.proto_header ; protocol = block.protocol_hash ;
net = block.net_id ;
test_protocol = Some block.test_protocol_hash ;
test_network = block.test_network ; test_network = block.test_network ;
} }
let convert_block hash ({ shell ; proto }: State.Block_header.t) = {
net = shell.net_id ;
hash = hash ;
predecessor = shell.predecessor ;
fitness = shell.fitness ;
timestamp = shell.timestamp ;
protocol = None ;
operations_hash = shell.operations ;
operations = None ;
data = Some proto ;
test_protocol = None ;
test_network = None ;
}
let inject_block node = node.inject_block let inject_block node = node.inject_block
let inject_operation node = node.inject_operation let inject_operation node = node.inject_operation
let inject_protocol node = node.inject_protocol let inject_protocol node = node.inject_protocol
@ -278,42 +263,62 @@ module RPC = struct
State.Valid_block.Current.head net_state >>= fun head -> State.Valid_block.Current.head net_state >>= fun head ->
Prevalidator.context pv >>= function Prevalidator.context pv >>= function
| Error _ -> Lwt.fail Not_found | Error _ -> Lwt.fail Not_found
| Ok ctxt -> | Ok { context ; fitness } ->
Context.get_fitness ctxt >>= fun fitness -> Context.get_protocol context >>= fun protocol ->
Context.get_protocol ctxt >>= fun protocol -> Context.get_test_network context >>= fun test_network ->
let operations = let operations =
let pv_result, _ = Prevalidator.operations pv in let pv_result, _ = Prevalidator.operations pv in
Some [ pv_result.applied ] in [ pv_result.applied ] in
let timestamp = Prevalidator.timestamp pv in
Lwt.return Lwt.return
{ (convert head) with { hash = prevalidation_hash ;
hash = prevalidation_hash ; level = Int32.succ head.level ;
protocol = Some protocol ; predecessor = head.hash ;
fitness ; operations ; timestamp } fitness ;
timestamp = Prevalidator.timestamp pv ;
protocol ;
operations_hash =
Operation_list_list_hash.compute
(List.map Operation_list_hash.compute operations) ;
operations = Some operations ;
data = MBytes.of_string "" ;
net_id = head.net_id ;
test_network ;
}
let get_context node block = let rpc_context block : Updater.rpc_context =
{ context = block.State.Valid_block.context ;
level = Int32.succ block.level ;
fitness = block.fitness ;
timestamp = block. timestamp }
let get_rpc_context node block =
match block with match block with
| `Genesis -> | `Genesis ->
State.Valid_block.Current.genesis node.mainnet_net >>= fun block -> State.Valid_block.Current.genesis node.mainnet_net >>= fun block ->
Lwt.return (Some block.context) Lwt.return (Some (rpc_context block))
| ( `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 -> State.Valid_block.Current.head net_state >>= fun head ->
get_pred net_db n head >>= fun { context } -> get_pred net_db n head >>= fun block ->
Lwt.return (Some context) Lwt.return (Some (rpc_context block))
| `Hash hash-> begin | `Hash hash-> begin
read_valid_block node hash >|= function read_valid_block node hash >|= function
| None -> None | None -> None
| Some { context } -> Some context | Some block -> Some (rpc_context block)
end end
| ( `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
Prevalidator.context pv >>= function Prevalidator.context pv >>= function
| Error _ -> Lwt.fail Not_found | Error _ -> Lwt.fail Not_found
| Ok ctxt -> Lwt.return (Some ctxt) | Ok { context ; fitness } ->
let timestamp = Prevalidator.timestamp pv in
State.Valid_block.Current.head
(Distributed_db.state net) >>= fun { level } ->
let level = Int32.succ level in
Lwt.return (Some { Updater.context ; fitness ; timestamp ; level })
let operations node block = let operations node block =
match block with match block with
@ -417,8 +422,7 @@ module RPC = struct
~predecessor ~timestamp >>=? fun validation_state -> ~predecessor ~timestamp >>=? fun validation_state ->
Prevalidation.prevalidate Prevalidation.prevalidate
validation_state ~sort rops >>=? fun (validation_state, r) -> validation_state ~sort rops >>=? fun (validation_state, r) ->
Prevalidation.end_prevalidation validation_state >>=? fun ctxt -> Prevalidation.end_prevalidation validation_state >>=? fun { fitness } ->
Context.get_fitness ctxt >>= fun fitness ->
return (fitness, { r with applied = List.rev r.applied }) return (fitness, { r with applied = List.rev r.applied })
let complete node ?block str = let complete node ?block str =
@ -426,9 +430,9 @@ module RPC = struct
| None -> | None ->
Base58.complete str Base58.complete str
| Some block -> | Some block ->
get_context node block >>= function get_rpc_context node block >>= function
| None -> Lwt.fail Not_found | None -> Lwt.fail Not_found
| Some ctxt -> | Some { context = ctxt } ->
Context.get_protocol ctxt >>= fun protocol_hash -> Context.get_protocol ctxt >>= fun protocol_hash ->
let (module Proto) = Updater.get_exn protocol_hash in let (module Proto) = Updater.get_exn protocol_hash in
Base58.complete str >>= fun l1 -> Base58.complete str >>= fun l1 ->
@ -436,12 +440,12 @@ module RPC = struct
Lwt.return (l1 @ l2) Lwt.return (l1 @ l2)
let context_dir node block = let context_dir node block =
get_context node block >>= function get_rpc_context node block >>= function
| None -> Lwt.return None | None -> Lwt.return None
| Some ctxt -> | Some rpc_context ->
Context.get_protocol ctxt >>= fun protocol_hash -> Context.get_protocol rpc_context.context >>= fun protocol_hash ->
let (module Proto) = Updater.get_exn protocol_hash in let (module Proto) = Updater.get_exn protocol_hash in
let dir = RPC.map (fun () -> ctxt) Proto.rpc_services in let dir = RPC.map (fun () -> rpc_context) Proto.rpc_services in
Lwt.return (Some (RPC.map (fun _ -> ()) dir)) Lwt.return (Some (RPC.map (fun _ -> ()) dir))
let heads node = let heads node =
@ -512,12 +516,7 @@ module RPC = struct
heads >>= fun (_, blocks) -> heads >>= fun (_, blocks) ->
Lwt.return (List.rev blocks) Lwt.return (List.rev blocks)
let block_watcher node = let block_watcher node = Distributed_db.watch_block node.distributed_db
let stream, shutdown = Distributed_db.watch_block node.distributed_db in
Lwt_stream.map
(fun (hash, block) -> convert_block hash block)
stream,
shutdown
let valid_block_watcher node = let valid_block_watcher node =
let stream, shutdown = Validator.global_watcher node.validator in let stream, shutdown = Validator.global_watcher node.validator in

View File

@ -13,9 +13,9 @@ type config = {
genesis: State.Net.genesis ; genesis: State.Net.genesis ;
store_root: string ; store_root: string ;
context_root: string ; context_root: string ;
test_protocol: Protocol_hash.t option ;
patch_context: (Context.t -> Context.t Lwt.t) option ; patch_context: (Context.t -> Context.t Lwt.t) option ;
p2p: (P2p.config * P2p.limits) option ; p2p: (P2p.config * P2p.limits) option ;
test_network_max_tll: int option ;
} }
val create: config -> t tzresult Lwt.t val create: config -> t tzresult Lwt.t
@ -44,7 +44,7 @@ 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_watcher:
t -> block_info Lwt_stream.t * Watcher.stopper t -> (Block_hash.t * Store.Block_header.t) Lwt_stream.t * Watcher.stopper
val valid_block_watcher: val valid_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

View File

@ -12,9 +12,8 @@ open Logging.RPC
module Services = Node_rpc_services module Services = Node_rpc_services
let filter_bi (operations, data) (bi: Services.Blocks.block_info) = 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
let bi = if data then bi else { bi with data = None } in
bi bi
let register_bi_dir node dir = let register_bi_dir node dir =
@ -34,9 +33,15 @@ let register_bi_dir node dir =
let dir = let dir =
let implementation b () = let implementation b () =
Node.RPC.block_info node b >>= fun bi -> Node.RPC.block_info node b >>= fun bi ->
RPC.Answer.return bi.net in RPC.Answer.return bi.net_id in
RPC.register1 dir RPC.register1 dir
Services.Blocks.net implementation in Services.Blocks.net implementation in
let dir =
let implementation b () =
Node.RPC.block_info node b >>= fun bi ->
RPC.Answer.return bi.level in
RPC.register1 dir
Services.Blocks.level implementation in
let dir = let dir =
let implementation b () = let implementation b () =
Node.RPC.block_info node b >>= fun bi -> Node.RPC.block_info node b >>= fun bi ->
@ -65,17 +70,9 @@ let register_bi_dir node dir =
let dir = let dir =
let implementation b () = let implementation b () =
Node.RPC.block_info node b >>= fun bi -> Node.RPC.block_info node b >>= fun bi ->
match bi.protocol with RPC.Answer.return bi.protocol in
| None -> raise Not_found
| Some p -> RPC.Answer.return p in
RPC.register1 dir RPC.register1 dir
Services.Blocks.protocol implementation in Services.Blocks.protocol implementation in
let dir =
let implementation b () =
Node.RPC.block_info node b >>= fun bi ->
RPC.Answer.return bi.test_protocol in
RPC.register1 dir
Services.Blocks.test_protocol implementation in
let dir = let dir =
let implementation b () = let implementation b () =
Node.RPC.block_info node b >>= fun bi -> Node.RPC.block_info node b >>= fun bi ->
@ -214,11 +211,10 @@ let create_delayed_stream
let list_blocks let list_blocks
node node
{ Services.Blocks.operations ; data ; length ; heads ; monitor ; delay ; { Services.Blocks.include_ops ; length ; heads ; monitor ; delay ;
min_date; min_heads} = min_date; min_heads} =
let len = match length with None -> 1 | Some x -> x in let len = match length with None -> 1 | Some x -> x in
let monitor = match monitor with None -> false | Some x -> x in let monitor = match monitor with None -> false | Some x -> x in
let include_ops = (operations, data) in
let time = let time =
match delay with match delay with
| None -> None | None -> None
@ -404,14 +400,17 @@ let build_rpc_directory node =
let dir = let dir =
RPC.register1 dir Services.Protocols.contents (get_protocols node) in RPC.register1 dir Services.Protocols.contents (get_protocols node) in
let dir = let dir =
let implementation (net_id, pred, time, fitness, operations, header) = let implementation
(net_id, level, pred, time, fitness, operations_hash, header) =
Node.RPC.block_info node (`Head 0) >>= fun bi -> Node.RPC.block_info node (`Head 0) >>= fun bi ->
let timestamp = Utils.unopt ~default:(Time.now ()) time in let timestamp = Utils.unopt ~default:(Time.now ()) time in
let net_id = Utils.unopt ~default:bi.net net_id in let net_id = Utils.unopt ~default:bi.net_id net_id in
let predecessor = Utils.unopt ~default:bi.hash pred in let predecessor = Utils.unopt ~default:bi.hash pred in
let level = Utils.unopt ~default:(Int32.succ bi.level) level in
let res = let res =
Data_encoding.Binary.to_bytes Store.Block_header.encoding { Data_encoding.Binary.to_bytes Store.Block_header.encoding {
shell = { net_id ; predecessor ; timestamp ; fitness ; operations } ; shell = { net_id ; predecessor ; level ;
timestamp ; fitness ; operations_hash } ;
proto = header ; proto = header ;
} in } in
RPC.Answer.return res in RPC.Answer.return res in

View File

@ -57,46 +57,45 @@ module Blocks = struct
type block_info = { type block_info = {
hash: Block_hash.t ; hash: Block_hash.t ;
net_id: Net_id.t ;
level: Int32.t ;
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
fitness: MBytes.t list ;
timestamp: Time.t ; timestamp: Time.t ;
protocol: Protocol_hash.t option ;
operations_hash: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ;
data: MBytes.t ;
operations: Operation_hash.t list list option ; operations: Operation_hash.t list list option ;
data: MBytes.t option ; protocol: Protocol_hash.t ;
net: Net_id.t ; test_network: Context.test_network;
test_protocol: Protocol_hash.t option ;
test_network: (Net_id.t * Time.t) option ;
} }
let block_info_encoding = let block_info_encoding =
conv conv
(fun { hash ; predecessor ; fitness ; timestamp ; protocol ; (fun { hash ; net_id ; level ; predecessor ;
operations_hash ; operations ; data ; net ; fitness ; timestamp ; protocol ; operations_hash ; data ;
test_protocol ; test_network } -> operations ; test_network } ->
((hash, predecessor, fitness, timestamp, protocol), ({ Store.Block_header.shell =
(operations_hash, operations, data, { net_id ; level ; predecessor ;
net, test_protocol, test_network))) timestamp ; operations_hash ; fitness } ;
(fun ((hash, predecessor, fitness, timestamp, protocol), proto = data },
(operations_hash, operations, data, (hash, operations, protocol, test_network)))
net, test_protocol, test_network)) -> (fun ({ Store.Block_header.shell =
{ hash ; predecessor ; fitness ; timestamp ; protocol ; { net_id ; level ; predecessor ;
operations_hash ; operations ; data ; net ; timestamp ; operations_hash ; fitness } ;
test_protocol ; test_network }) proto = data },
(merge_objs (hash, operations, protocol, test_network)) ->
(obj5 { hash ; net_id ; level ; predecessor ;
(req "hash" Block_hash.encoding) fitness ; timestamp ; protocol ; operations_hash ; data ;
(req "predecessor" Block_hash.encoding) operations ; test_network })
(req "fitness" Fitness.encoding) (dynamic_size
(req "timestamp" Time.encoding) (merge_objs
(opt "protocol" Protocol_hash.encoding)) Store.Block_header.encoding
(obj6 (obj4
(req "operations_hash" Operation_list_list_hash.encoding) (req "hash" Block_hash.encoding)
(opt "operations" (list (list Operation_hash.encoding))) (opt "operations" (list (list Operation_hash.encoding)))
(opt "data" bytes) (req "protocol" Protocol_hash.encoding)
(req "net" Net_id.encoding) (dft "test_network"
(opt "test_protocol" Protocol_hash.encoding) Context.test_network_encoding Context.Not_running))))
(opt "test_network" (tup2 Net_id.encoding Time.encoding))))
let parse_block s = let parse_block s =
try try
@ -179,10 +178,7 @@ module Blocks = struct
let info = let info =
RPC.service RPC.service
~description:"All the information about a block." ~description:"All the information about a block."
~input: ~input: (obj1 (dft "operations" bool true))
(obj2
(dft "operations" bool true)
(dft "data" bool true))
~output: block_info_encoding ~output: block_info_encoding
block_path block_path
@ -193,6 +189,13 @@ module Blocks = struct
~output: (obj1 (req "net" Net_id.encoding)) ~output: (obj1 (req "net" Net_id.encoding))
RPC.Path.(block_path / "net") RPC.Path.(block_path / "net")
let level =
RPC.service
~description:"Returns the block's level."
~input: empty
~output: (obj1 (req "level" int32))
RPC.Path.(block_path / "level")
let predecessor = let predecessor =
RPC.service RPC.service
~description:"Returns the previous block's id." ~description:"Returns the previous block's id."
@ -244,18 +247,11 @@ module Blocks = struct
~output: (obj1 (req "protocol" Protocol_hash.encoding)) ~output: (obj1 (req "protocol" Protocol_hash.encoding))
RPC.Path.(block_path / "protocol") RPC.Path.(block_path / "protocol")
let test_protocol =
RPC.service
~description:"List the block test protocol."
~input: empty
~output: (obj1 (opt "protocol" Protocol_hash.encoding))
RPC.Path.(block_path / "test_protocol")
let test_network = let test_network =
RPC.service RPC.service
~description:"Returns the associated test network." ~description:"Returns the status of the associated test network."
~input: empty ~input: empty
~output: (obj1 (opt "net" (tup2 Net_id.encoding Time.encoding))) ~output: Context.test_network_encoding
RPC.Path.(block_path / "test_network") RPC.Path.(block_path / "test_network")
let pending_operations = let pending_operations =
@ -320,8 +316,7 @@ module Blocks = struct
RPC.Path.(block_path / "complete" /: prefix_arg ) RPC.Path.(block_path / "complete" /: prefix_arg )
type list_param = { type list_param = {
operations: bool ; include_ops: bool ;
data: bool ;
length: int option ; length: int option ;
heads: Block_hash.t list option ; heads: Block_hash.t list option ;
monitor: bool option ; monitor: bool option ;
@ -331,25 +326,20 @@ module Blocks = struct
} }
let list_param_encoding = let list_param_encoding =
conv conv
(fun { operations ; data ; length ; heads ; monitor ; (fun { include_ops ; length ; heads ; monitor ;
delay ; min_date ; min_heads } -> delay ; min_date ; min_heads } ->
(operations, data, length, heads, monitor, delay, min_date, min_heads)) (include_ops, length, heads, monitor, delay, min_date, min_heads))
(fun (operations, data, length, heads, monitor, delay, min_date, min_heads) -> (fun (include_ops, length, heads, monitor,
{ operations ; data ; length ; heads ; monitor ; delay, min_date, min_heads) ->
{ include_ops ; length ; heads ; monitor ;
delay ; min_date ; min_heads }) delay ; min_date ; min_heads })
(obj8 (obj7
(dft "operations" (dft "include_ops"
(Data_encoding.describe (Data_encoding.describe
~description: ~description:
"Whether the resulting block informations should include the \ "Whether the resulting block informations should include the \
list of operations' hashes. Default false." list of operations' hashes. Default false."
bool) false) bool) false)
(dft "data"
(Data_encoding.describe
~description:
"Whether the resulting block informations should include the \
raw protocol dependent data. Default false."
bool) false)
(opt "length" (opt "length"
(Data_encoding.describe (Data_encoding.describe
~description: ~description:
@ -642,8 +632,9 @@ let forge_block =
RPC.service RPC.service
~description: "Forge a block header" ~description: "Forge a block header"
~input: ~input:
(obj6 (obj7
(opt "net_id" Net_id.encoding) (opt "net_id" Net_id.encoding)
(opt "level" int32)
(opt "predecessor" Block_hash.encoding) (opt "predecessor" Block_hash.encoding)
(opt "timestamp" Time.encoding) (opt "timestamp" Time.encoding)
(req "fitness" Fitness.encoding) (req "fitness" Fitness.encoding)

View File

@ -28,22 +28,24 @@ module Blocks : sig
type block_info = { type block_info = {
hash: Block_hash.t ; hash: Block_hash.t ;
net_id: Net_id.t ;
level: Int32.t ;
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
fitness: MBytes.t list ;
timestamp: Time.t ; timestamp: Time.t ;
protocol: Protocol_hash.t option ;
operations_hash: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ;
data: MBytes.t ;
operations: Operation_hash.t list list option ; operations: Operation_hash.t list list option ;
data: MBytes.t option ; protocol: Protocol_hash.t ;
net: Net_id.t ; test_network: Context.test_network;
test_protocol: Protocol_hash.t option ;
test_network: (Net_id.t * Time.t) option ;
} }
val info: val info:
(unit, unit * block, bool * bool, block_info) RPC.service (unit, unit * block, bool, block_info) RPC.service
val net: val net:
(unit, unit * block, unit, Net_id.t) RPC.service (unit, unit * block, unit, Net_id.t) RPC.service
val level:
(unit, unit * block, unit, Int32.t) RPC.service
val predecessor: val predecessor:
(unit, unit * block, unit, Block_hash.t) RPC.service (unit, unit * block, unit, Block_hash.t) RPC.service
val predecessors: val predecessors:
@ -58,17 +60,14 @@ module Blocks : sig
(unit, unit * block, unit, Operation_hash.t list list) RPC.service (unit, unit * block, unit, Operation_hash.t 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_protocol:
(unit, unit * block, unit, Protocol_hash.t option) RPC.service
val test_network: val test_network:
(unit, unit * block, unit, (Net_id.t * Time.t) option) RPC.service (unit, unit * block, unit, Context.test_network) RPC.service
val pending_operations: val pending_operations:
(unit, unit * block, unit, (unit, unit * block, unit,
error Prevalidation.preapply_result * Hash.Operation_hash.Set.t) RPC.service error Prevalidation.preapply_result * Hash.Operation_hash.Set.t) RPC.service
type list_param = { type list_param = {
operations: bool ; include_ops: bool ;
data: bool ;
length: int option ; length: int option ;
heads: Block_hash.t list option ; heads: Block_hash.t list option ;
monitor: bool option ; monitor: bool option ;
@ -179,7 +178,7 @@ end
val forge_block: val forge_block:
(unit, unit, (unit, unit,
Net_id.t option * Block_hash.t option * Time.t option * Net_id.t option * Int32.t option * Block_hash.t option * Time.t option *
Fitness.fitness * Operation_list_list_hash.t * MBytes.t, Fitness.fitness * Operation_list_list_hash.t * MBytes.t,
MBytes.t) RPC.service MBytes.t) RPC.service

View File

@ -135,17 +135,25 @@ let start_prevalidation
{ State.Valid_block.protocol ; { State.Valid_block.protocol ;
hash = predecessor ; hash = predecessor ;
context = predecessor_context ; context = predecessor_context ;
timestamp = predecessor_timestamp } timestamp = predecessor_timestamp ;
fitness = predecessor_fitness ;
level = predecessor_level }
~timestamp = ~timestamp =
let (module Proto) = let (module Proto) =
match protocol with match 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
predecessor_context predecessor
timestamp >>= fun predecessor_context ->
Proto.begin_construction Proto.begin_construction
~predecessor_context ~predecessor_context
~predecessor_timestamp ~predecessor_timestamp
~predecessor_fitness
~predecessor_level
~predecessor ~predecessor
~timestamp >>=? fun state -> ~timestamp
>>=? fun state ->
return (State { proto = (module Proto) ; state }) return (State { proto = (module Proto) ; state })
let prevalidate let prevalidate

View File

@ -39,4 +39,4 @@ val prevalidate :
(prevalidation_state * error preapply_result) tzresult Lwt.t (prevalidation_state * error preapply_result) tzresult Lwt.t
val end_prevalidation : val end_prevalidation :
prevalidation_state -> Context.t tzresult Lwt.t prevalidation_state -> Updater.validation_result tzresult Lwt.t

View File

@ -54,7 +54,7 @@ type 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.Valid_block.t -> unit -> Operation_hash.Set.t Lwt.t ;
timestamp: unit -> Time.t ; timestamp: unit -> Time.t ;
context: unit -> Context.t tzresult Lwt.t ; context: unit -> Updater.validation_result tzresult Lwt.t ;
shutdown: unit -> unit Lwt.t ; shutdown: unit -> unit Lwt.t ;
} }

View File

@ -44,6 +44,6 @@ val inject_operation:
val flush: t -> State.Valid_block.t -> unit val flush: t -> State.Valid_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 -> Context.t 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.Valid_block.t -> t -> Operation_hash.Set.t Lwt.t

View File

@ -89,7 +89,7 @@ and net = {
state: net_state Shared.t ; state: net_state Shared.t ;
genesis: genesis ; genesis: genesis ;
expiration: Time.t option ; expiration: Time.t option ;
forked_network_ttl: Int64.t option ; allow_forked_network: bool ;
operation_store: Store.Operation.store Shared.t ; operation_store: Store.Operation.store Shared.t ;
block_header_store: Store.Block_header.store Shared.t ; block_header_store: Store.Block_header.store Shared.t ;
valid_block_watcher: valid_block Watcher.input ; valid_block_watcher: valid_block Watcher.input ;
@ -110,7 +110,8 @@ and net_state = {
and valid_block = { and valid_block = {
net_id: Net_id.t ; net_id: Net_id.t ;
hash: Block_hash.t ; hash: Block_hash.t ;
pred: Block_hash.t ; level: Int32.t ;
predecessor: Block_hash.t ;
timestamp: Time.t ; timestamp: Time.t ;
fitness: Protocol.fitness ; fitness: Protocol.fitness ;
operations_hash: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
@ -118,9 +119,7 @@ and valid_block = {
discovery_time: Time.t ; discovery_time: Time.t ;
protocol_hash: Protocol_hash.t ; protocol_hash: Protocol_hash.t ;
protocol: (module Updater.REGISTRED_PROTOCOL) option ; protocol: (module Updater.REGISTRED_PROTOCOL) option ;
test_protocol_hash: Protocol_hash.t ; test_network: Context.test_network ;
test_protocol: (module Updater.REGISTRED_PROTOCOL) option ;
test_network: (Net_id.t * Time.t) option ;
context: Context.t ; context: Context.t ;
successors: Block_hash.Set.t ; successors: Block_hash.Set.t ;
invalid_successors: Block_hash.Set.t ; invalid_successors: Block_hash.Set.t ;
@ -131,29 +130,20 @@ let build_valid_block
hash header operations hash header operations
context discovery_time successors invalid_successors = context discovery_time successors invalid_successors =
Context.get_protocol context >>= fun protocol_hash -> Context.get_protocol context >>= fun protocol_hash ->
Context.get_test_protocol context >>= fun test_protocol_hash ->
Context.get_test_network context >>= fun test_network -> Context.get_test_network context >>= fun test_network ->
Context.get_test_network_expiration
context >>= fun test_network_expiration ->
let test_network =
match test_network, test_network_expiration with
| None, _ | _, None -> None
| Some net_id, Some time -> Some (net_id, time) in
let protocol = Updater.get protocol_hash in let protocol = Updater.get protocol_hash in
let test_protocol = Updater.get test_protocol_hash in
let valid_block = { let valid_block = {
net_id = header.Store.Block_header.shell.net_id ; net_id = header.Store.Block_header.shell.net_id ;
hash ; hash ;
pred = header.shell.predecessor ; level = header.shell.level ;
predecessor = header.shell.predecessor ;
timestamp = header.shell.timestamp ; timestamp = header.shell.timestamp ;
discovery_time ; discovery_time ;
operations_hash = header.shell.operations ; operations_hash = header.shell.operations_hash ;
operations ; operations ;
fitness = header.shell.fitness ; fitness = header.shell.fitness ;
protocol_hash ; protocol_hash ;
protocol ; protocol ;
test_protocol_hash ;
test_protocol ;
test_network ; test_network ;
context ; context ;
successors ; successors ;
@ -540,10 +530,11 @@ module Raw_block_header = struct
let store_genesis store genesis = let store_genesis store genesis =
let shell : Store.Block_header.shell_header = { let shell : Store.Block_header.shell_header = {
net_id = Net_id.of_block_hash genesis.block; net_id = Net_id.of_block_hash genesis.block;
level = 0l ;
predecessor = genesis.block ; predecessor = genesis.block ;
timestamp = genesis.time ; timestamp = genesis.time ;
fitness = [] ; fitness = [] ;
operations = Operation_list_list_hash.empty ; operations_hash = Operation_list_list_hash.empty ;
} in } in
let header = let header =
{ Store.Block_header.shell ; proto = MBytes.create 0 } in { Store.Block_header.shell ; proto = MBytes.create 0 } in
@ -553,22 +544,23 @@ module Raw_block_header = struct
Raw_operation_list.Locked.store_all store genesis.block [] [] >>= fun () -> Raw_operation_list.Locked.store_all store genesis.block [] [] >>= fun () ->
Lwt.return header Lwt.return header
let store_testnet_genesis store genesis = (* let store_testnet_genesis store genesis = *)
let shell : Store.Block_header.shell_header = { (* let shell : Store.Block_header.shell_header = { *)
net_id = Net_id.of_block_hash genesis.block; (* net_id = Net_id.of_block_hash genesis.block; *)
predecessor = genesis.block ; (* level = 0l ; *)
timestamp = genesis.time ; (* predecessor = genesis.block ; *)
fitness = [] ; (* timestamp = genesis.time ; *)
operations = Operation_list_list_hash.empty ; (* fitness = [] ; *)
} in (* operations = Operation_list_list_hash.empty ; *)
let bytes = (* } in *)
Data_encoding.Binary.to_bytes Store.Block_header.encoding { (* let bytes = *)
shell ; (* Data_encoding.Binary.to_bytes Store.Block_header.encoding { *)
proto = MBytes.create 0 ; (* shell ; *)
} in (* proto = MBytes.create 0 ; *)
Locked.store_raw store genesis.block bytes >>= fun _created -> (* } in *)
Raw_operation_list.Locked.store_all store genesis.block [] [] >>= fun () -> (* Locked.store_raw store genesis.block bytes >>= fun _created -> *)
Lwt.return shell (* Raw_operation_list.Locked.store_all store genesis.block [] [] >>= fun () -> *)
(* Lwt.return shell *)
end end
@ -693,9 +685,10 @@ module Block_header = struct
type shell_header = Store.Block_header.shell_header = { type shell_header = Store.Block_header.shell_header = {
net_id: Net_id.t ; net_id: Net_id.t ;
level: Int32.t ;
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
timestamp: Time.t ; timestamp: Time.t ;
operations: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ; fitness: MBytes.t list ;
} }
@ -852,7 +845,7 @@ module Raw_net = struct
~genesis ~genesis
~genesis_block ~genesis_block
~expiration ~expiration
~forked_network_ttl ~allow_forked_network
context_index context_index
chain_store chain_store
block_header_store block_header_store
@ -867,18 +860,16 @@ module Raw_net = struct
state = Shared.create net_state ; state = Shared.create net_state ;
genesis ; genesis ;
expiration ; expiration ;
allow_forked_network ;
operation_store = Shared.create operation_store ; operation_store = Shared.create operation_store ;
forked_network_ttl ;
block_header_store = Shared.create block_header_store ; block_header_store = Shared.create block_header_store ;
valid_block_watcher = Watcher.create_input (); valid_block_watcher = Watcher.create_input ();
} in } in
net net
let locked_create let locked_create
data data ?initial_context ?expiration ?(allow_forked_network = false)
?initial_context ?forked_network_ttl net_id genesis =
?test_protocol ?expiration genesis =
let net_id = Net_id.of_block_hash genesis.block in
let net_store = Store.Net.get data.global_store net_id in let net_store = Store.Net.get data.global_store net_id in
let operation_store = Store.Operation.get net_store let operation_store = Store.Operation.get net_store
and block_header_store = Store.Block_header.get net_store and block_header_store = Store.Block_header.get net_store
@ -886,8 +877,6 @@ module Raw_net = struct
Store.Net.Genesis_hash.store net_store genesis.block >>= fun () -> Store.Net.Genesis_hash.store net_store genesis.block >>= fun () ->
Store.Net.Genesis_time.store net_store genesis.time >>= fun () -> Store.Net.Genesis_time.store net_store genesis.time >>= fun () ->
Store.Net.Genesis_protocol.store net_store genesis.protocol >>= fun () -> Store.Net.Genesis_protocol.store net_store genesis.protocol >>= fun () ->
let test_protocol = Utils.unopt ~default:genesis.protocol test_protocol in
Store.Net.Genesis_test_protocol.store net_store test_protocol >>= fun () ->
Store.Chain.Current_head.store chain_store genesis.block >>= fun () -> Store.Chain.Current_head.store chain_store genesis.block >>= fun () ->
Store.Chain.Known_heads.store chain_store genesis.block >>= fun () -> Store.Chain.Known_heads.store chain_store genesis.block >>= fun () ->
data.init_index net_id >>= fun context_index -> data.init_index net_id >>= fun context_index ->
@ -896,6 +885,12 @@ module Raw_net = struct
| None -> Lwt.return_unit | None -> Lwt.return_unit
| Some time -> Store.Net.Expiration.store net_store time | Some time -> Store.Net.Expiration.store net_store time
end >>= fun () -> end >>= fun () ->
begin
if allow_forked_network then
Store.Net.Allow_forked_network.store data.global_store net_id
else
Lwt.return_unit
end >>= fun () ->
Raw_block_header.store_genesis Raw_block_header.store_genesis
block_header_store genesis >>= fun header -> block_header_store genesis >>= fun header ->
begin begin
@ -906,7 +901,6 @@ module Raw_net = struct
~id:genesis.block ~id:genesis.block
~time:genesis.time ~time:genesis.time
~protocol:genesis.protocol ~protocol:genesis.protocol
~test_protocol
| Some context -> | Some context ->
Lwt.return context Lwt.return context
end >>= fun context -> end >>= fun context ->
@ -918,7 +912,7 @@ module Raw_net = struct
~genesis ~genesis
~genesis_block ~genesis_block
~expiration ~expiration
~forked_network_ttl ~allow_forked_network
context_index context_index
chain_store chain_store
block_header_store block_header_store
@ -932,7 +926,8 @@ module Valid_block = struct
type t = valid_block = { type t = valid_block = {
net_id: Net_id.t ; net_id: Net_id.t ;
hash: Block_hash.t ; hash: Block_hash.t ;
pred: Block_hash.t ; level: Int32.t ;
predecessor: Block_hash.t ;
timestamp: Time.t ; timestamp: Time.t ;
fitness: Fitness.fitness ; fitness: Fitness.fitness ;
operations_hash: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
@ -940,9 +935,7 @@ module Valid_block = struct
discovery_time: Time.t ; discovery_time: Time.t ;
protocol_hash: Protocol_hash.t ; protocol_hash: Protocol_hash.t ;
protocol: (module Updater.REGISTRED_PROTOCOL) option ; protocol: (module Updater.REGISTRED_PROTOCOL) option ;
test_protocol_hash: Protocol_hash.t ; test_network: Context.test_network ;
test_protocol: (module Updater.REGISTRED_PROTOCOL) option ;
test_network: (Net_id.t * Time.t) option ;
context: Context.t ; context: Context.t ;
successors: Block_hash.Set.t ; successors: Block_hash.Set.t ;
invalid_successors: Block_hash.Set.t ; invalid_successors: Block_hash.Set.t ;
@ -996,14 +989,13 @@ module Valid_block = struct
block_header_store block_header_store
(net_state: net_state) (net_state: net_state)
valid_block_watcher valid_block_watcher
hash context ttl = hash { Updater.context ; message ; fitness } =
(* Read the block header. *) (* Read the block header. *)
Raw_block_header.Locked.read Raw_block_header.Locked.read
block_header_store hash >>=? fun block -> block_header_store hash >>=? fun block ->
Raw_block_header.Locked.read_discovery_time Raw_block_header.Locked.read_discovery_time
block_header_store hash >>=? fun discovery_time -> block_header_store hash >>=? fun discovery_time ->
(* Check fitness coherency. *) (* Check fitness coherency. *)
Context.get_fitness context >>= fun fitness ->
fail_unless fail_unless
(Fitness.equal fitness block.Store.Block_header.shell.fitness) (Fitness.equal fitness block.Store.Block_header.shell.fitness)
(Invalid_fitness (Invalid_fitness
@ -1011,37 +1003,21 @@ module Valid_block = struct
expected = block.Store.Block_header.shell.fitness ; expected = block.Store.Block_header.shell.fitness ;
found = fitness ; found = fitness ;
}) >>=? fun () -> }) >>=? fun () ->
begin (* Patch context about the associated test network. *)
Context.read_and_reset_fork_test_network
context >>= fun (fork, context) ->
if fork then
match ttl with
| None ->
(* Ignore fork on forked networks. *)
Context.del_test_network context >>= fun context ->
Context.del_test_network_expiration context
| Some ttl ->
let eol = Time.(add block.shell.timestamp ttl) in
Context.set_test_network
context (Net_id.of_block_hash hash) >>= fun context ->
Context.set_test_network_expiration
context eol >>= fun context ->
Lwt.return context
else
Context.get_test_network_expiration context >>= function
| Some eol when Time.(eol <= now ()) ->
Context.del_test_network context >>= fun context ->
Context.del_test_network_expiration context
| None | Some _ ->
Lwt.return context
end >>= fun context ->
Raw_block_header.Locked.mark_valid Raw_block_header.Locked.mark_valid
block_header_store hash >>= fun _marked -> block_header_store hash >>= fun _marked ->
(* TODO fail if the block was previsouly stored ... ??? *) (* TODO fail if the block was previsouly stored ... ??? *)
Operation_list.Locked.read_all Operation_list.Locked.read_all
block_header_store hash >>=? fun operations -> block_header_store hash >>=? fun operations ->
(* Let's commit the context. *) (* Let's commit the context. *)
Context.commit hash context >>= fun () -> let message =
match message with
| Some message -> message
| None ->
Format.asprintf "%a(%ld): %a"
Block_hash.pp_short hash
block.shell.level
Fitness.pp fitness in
Context.commit hash block.shell.timestamp message context >>= fun () ->
(* Update the chain state. *) (* Update the chain state. *)
let store = net_state.chain_store in let store = net_state.chain_store in
let predecessor = block.shell.predecessor in let predecessor = block.shell.predecessor in
@ -1076,7 +1052,7 @@ module Valid_block = struct
| Error _ -> Lwt.fail Not_found | Error _ -> Lwt.fail Not_found
| Ok b -> Lwt.return b | Ok b -> Lwt.return b
let store net hash context = let store net hash vcontext =
Shared.use net.state begin fun net_state -> Shared.use net.state begin fun net_state ->
Shared.use net.block_header_store begin fun block_header_store -> Shared.use net.block_header_store begin fun block_header_store ->
Context.exists net_state.context_index hash >>= function Context.exists net_state.context_index hash >>= function
@ -1088,7 +1064,7 @@ module Valid_block = struct
| None -> | None ->
Locked.store Locked.store
block_header_store net_state net.valid_block_watcher block_header_store net_state net.valid_block_watcher
hash context net.forked_network_ttl >>=? fun valid_block -> hash vcontext >>=? fun valid_block ->
return (Some valid_block) return (Some valid_block)
end end
end end
@ -1096,26 +1072,22 @@ module Valid_block = struct
let watcher net = let watcher net =
Watcher.create_stream net.valid_block_watcher Watcher.create_stream net.valid_block_watcher
let fork_testnet state net block expiration = let fork_testnet state net block protocol expiration =
assert (Net_id.equal block.net_id (Net_id.of_block_hash net.genesis.block)) ; assert (Net_id.equal block.net_id (Net_id.of_block_hash net.genesis.block)) ;
let hash = Block_hash.hash_bytes [Block_hash.to_bytes block.hash] in
let genesis : genesis = {
block = hash ;
time = Time.add block.timestamp 1L ;
protocol = block.test_protocol_hash ;
} in
Shared.use state.global_data begin fun data -> Shared.use state.global_data begin fun data ->
if Net_id.Table.mem data.nets (Net_id.of_block_hash hash) then let context = block.context in
assert false (* This would mean a block is validated twice... *) Context.set_test_network context Not_running >>= fun context ->
else Context.set_protocol context protocol >>= fun context ->
Context.init_test_network block.context Context.commit_test_network_genesis
~time:genesis.time block.hash block.timestamp context >>=? fun (net_id, genesis) ->
~genesis:genesis.block >>=? fun initial_context -> let genesis = {
Raw_net.locked_create data block = genesis ;
~initial_context time = Time.add block.timestamp 1L ;
~expiration protocol ;
genesis >>= fun net -> } in
return net Raw_net.locked_create data
net_id ~initial_context:context ~expiration genesis >>= fun net ->
return net
end end
module Helpers = struct module Helpers = struct
@ -1159,10 +1131,10 @@ module Valid_block = struct
end end
| res -> res in | res -> res in
let predecessor state b = let predecessor state b =
if Block_hash.equal b.hash b.pred then if Block_hash.equal b.hash b.predecessor then
Lwt.return None Lwt.return None
else else
read_opt state b.pred in read_opt state b.predecessor in
Raw_helpers.iter_predecessors compare predecessor Raw_helpers.iter_predecessors compare predecessor
(fun b -> b.timestamp) (fun b -> b.fitness) (fun b -> b.timestamp) (fun b -> b.fitness)
@ -1320,15 +1292,14 @@ module Net = struct
(req "block" Block_hash.encoding) (req "block" Block_hash.encoding)
(req "protocol" Protocol_hash.encoding)) (req "protocol" Protocol_hash.encoding))
let create state ?test_protocol ?forked_network_ttl genesis = let create state ?allow_forked_network genesis =
let net_id = Net_id.of_block_hash genesis.block in let net_id = Net_id.of_block_hash genesis.block in
let forked_network_ttl = map_option Int64.of_int forked_network_ttl in
Shared.use state.global_data begin fun data -> Shared.use state.global_data begin fun data ->
if Net_id.Table.mem data.nets net_id then if Net_id.Table.mem data.nets net_id then
Pervasives.failwith "State.Net.create" Pervasives.failwith "State.Net.create"
else else
Raw_net.locked_create data Raw_net.locked_create
?test_protocol ?forked_network_ttl genesis >>= fun net -> data ?allow_forked_network net_id genesis >>= fun net ->
Net_id.Table.add data.nets net_id net ; Net_id.Table.add data.nets net_id net ;
Lwt.return net Lwt.return net
end end
@ -1342,7 +1313,8 @@ module Net = struct
Store.Net.Genesis_time.read net_store >>=? fun time -> Store.Net.Genesis_time.read net_store >>=? fun time ->
Store.Net.Genesis_protocol.read net_store >>=? fun protocol -> Store.Net.Genesis_protocol.read net_store >>=? fun protocol ->
Store.Net.Expiration.read_opt net_store >>= fun expiration -> Store.Net.Expiration.read_opt net_store >>= fun expiration ->
Store.Net.Forked_network_ttl.read_opt net_store >>= fun forked_network_ttl -> Store.Net.Allow_forked_network.known
data.global_store id >>= fun allow_forked_network ->
let genesis = { time ; protocol ; block = genesis_hash } in let genesis = { time ; protocol ; block = genesis_hash } in
Store.Chain.Current_head.read chain_store >>=? fun genesis_hash -> Store.Chain.Current_head.read chain_store >>=? fun genesis_hash ->
data.init_index id >>= fun context_index -> data.init_index id >>= fun context_index ->
@ -1358,7 +1330,7 @@ module Net = struct
~genesis ~genesis
~genesis_block ~genesis_block
~expiration ~expiration
~forked_network_ttl ~allow_forked_network
context_index context_index
chain_store chain_store
block_header_store block_header_store
@ -1393,7 +1365,7 @@ module Net = struct
let id { id } = id let id { id } = id
let genesis { genesis } = genesis let genesis { genesis } = genesis
let expiration { expiration } = expiration let expiration { expiration } = expiration
let forked_network_ttl { forked_network_ttl } = forked_network_ttl let allow_forked_network { allow_forked_network } = allow_forked_network
let destroy state net = let destroy state net =
lwt_debug "destroy %a" Net_id.pp (id net) >>= fun () -> lwt_debug "destroy %a" Net_id.pp (id net) >>= fun () ->

View File

@ -62,12 +62,12 @@ 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 (** Initialize a network for a given [genesis]. By default,
never expirate and the test_protocol is the genesis protocol. *) 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 ->
?test_protocol: Protocol_hash.t -> ?allow_forked_network:bool ->
?forked_network_ttl: int ->
genesis -> net Lwt.t genesis -> net 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. *)
@ -88,7 +88,7 @@ module Net : sig
val id: net -> Net_id.t val id: net -> Net_id.t
val genesis: net -> genesis val genesis: net -> genesis
val expiration: net -> Time.t option val expiration: net -> Time.t option
val forked_network_ttl: net -> Int64.t option val allow_forked_network: net -> bool
end end
@ -144,9 +144,10 @@ module Block_header : sig
type shell_header = Store.Block_header.shell_header = { type shell_header = Store.Block_header.shell_header = {
net_id: Net_id.t ; net_id: Net_id.t ;
level: Int32.t ;
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
timestamp: Time.t ; timestamp: Time.t ;
operations: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ; fitness: MBytes.t list ;
} }
@ -245,7 +246,9 @@ module Valid_block : sig
(** The genesis of the chain this block belongs to. *) (** The genesis of the chain this block belongs to. *)
hash: Block_hash.t ; hash: Block_hash.t ;
(** The block hash. *) (** The block hash. *)
pred: Block_hash.t ; level: Int32.t ;
(** The number of preceding block in the chain. *)
predecessor: Block_hash.t ;
(** The preceding block in the chain. *) (** The preceding block in the chain. *)
timestamp: Time.t ; timestamp: Time.t ;
(** The date at which this block has been forged. *) (** The date at which this block has been forged. *)
@ -261,14 +264,8 @@ module Valid_block : sig
protocol: (module Updater.REGISTRED_PROTOCOL) option ; protocol: (module Updater.REGISTRED_PROTOCOL) option ;
(** The actual implementation of the protocol to be used for (** The actual implementation of the protocol to be used for
validating the following blocks. *) validating the following blocks. *)
test_protocol_hash: Protocol_hash.t ; test_network: Context.test_network ;
(** The protocol to be used for the next test network. *) (** The current test network associated to the block. *)
test_protocol: (module Updater.REGISTRED_PROTOCOL) option ;
(** The actual implementatino of the protocol to be used for the
next test network. *)
test_network: (Net_id.t * Time.t) option ;
(** The current test network associated to the block, and the date
of its expiration date. *)
context: Context.t ; context: Context.t ;
(** The validation context that was produced by the block validation. *) (** The validation context that was produced by the block validation. *)
successors: Block_hash.Set.t ; successors: Block_hash.Set.t ;
@ -284,7 +281,8 @@ module Valid_block : sig
val read_opt: Net.t -> Block_hash.t -> valid_block option 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 read_exn: Net.t -> Block_hash.t -> valid_block Lwt.t
val store: val store:
Net.t -> Block_hash.t -> Context.t -> valid_block option tzresult Lwt.t Net.t -> Block_hash.t -> Updater.validation_result ->
valid_block option tzresult Lwt.t
val watcher: Net.t -> valid_block Lwt_stream.t * Watcher.stopper val watcher: Net.t -> valid_block Lwt_stream.t * Watcher.stopper
@ -292,7 +290,10 @@ module Valid_block : sig
val known_heads: Net.t -> valid_block list Lwt.t val known_heads: Net.t -> valid_block list Lwt.t
val fork_testnet: val fork_testnet:
global_state -> Net.t -> valid_block -> Time.t -> Net.t tzresult Lwt.t global_state ->
Net.t -> valid_block ->
Protocol_hash.t -> Time.t ->
Net.t tzresult Lwt.t
module Current : sig module Current : sig

View File

@ -33,7 +33,11 @@ and t = {
net_db: Distributed_db.net ; net_db: Distributed_db.net ;
notify_block: Block_hash.t -> Store.Block_header.t -> unit Lwt.t ; notify_block: Block_hash.t -> Store.Block_header.t -> unit Lwt.t ;
fetch_block: Block_hash.t -> State.Valid_block.t tzresult Lwt.t ; fetch_block: Block_hash.t -> State.Valid_block.t tzresult Lwt.t ;
create_child: State.Valid_block.t -> unit tzresult Lwt.t ; create_child:
State.Valid_block.t -> Protocol_hash.t -> Time.t -> unit tzresult Lwt.t ;
check_child:
Block_hash.t -> Protocol_hash.t -> Time.t -> Time.t -> unit tzresult Lwt.t ;
deactivate_child: unit -> unit Lwt.t ;
test_validator: unit -> (t * Distributed_db.net) option ; test_validator: unit -> (t * Distributed_db.net) option ;
shutdown: unit -> unit Lwt.t ; shutdown: unit -> unit Lwt.t ;
valid_block_input: State.Valid_block.t Watcher.input ; valid_block_input: State.Valid_block.t Watcher.input ;
@ -59,29 +63,10 @@ let bootstrapped v = v.bootstrapped
(** Current block computation *) (** Current block computation *)
let may_change_test_network v (block: State.Valid_block.t) =
let change =
match block.test_network, v.child with
| None, None -> false
| Some _, None
| None, Some _ -> true
| Some (net_id, _), Some { net } ->
let net_id' = State.Net.id net in
not (Net_id.equal net_id net_id') in
if change then begin
v.create_child block >>= function
| Ok () -> Lwt.return_unit
| Error err ->
lwt_log_error "@[<v 2>Error while switch test network:@ %a@]"
Error_monad.pp_print_error err
end else
Lwt.return_unit
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 Distributed_db.Protocol.fetch v.worker.db hash >>= fun protocol ->
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"
@ -101,12 +86,16 @@ let fetch_protocols v (block: State.Valid_block.t) =
| Some _ -> return false | Some _ -> return false
| None -> fetch_protocol v block.protocol_hash | None -> fetch_protocol v block.protocol_hash
and test_proto_updated = and test_proto_updated =
match block.test_protocol with match block.test_network with
| Some _ -> return false | Not_running -> return false
| None -> fetch_protocol v block.test_protocol_hash in | Forking { protocol }
| Running { protocol } ->
Distributed_db.Protocol.known v.worker.db protocol >>= fun known ->
if known then return false
else 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 test_proto_updated || proto_updated then if proto_updated then
State.Valid_block.read_exn v.net block.hash >>= return State.Valid_block.read_exn v.net block.hash >>= return
else else
return block return block
@ -122,14 +111,27 @@ let rec may_set_head v (block: State.Valid_block.t) =
| 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 ;
may_change_test_network v block >>= fun () -> begin
begin
match block.test_network with
| Not_running -> v.deactivate_child () >>= return
| Running { genesis ; protocol ; expiration } ->
v.check_child genesis protocol expiration block.timestamp
| Forking { protocol ; expiration } ->
v.create_child block protocol expiration
end >>= function
| Ok () -> Lwt.return_unit
| Error err ->
lwt_log_error "@[<v 2>Error while switch test network:@ %a@]"
Error_monad.pp_print_error err
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.fitness
Time.pp_hum block.timestamp Time.pp_hum block.timestamp
(fun ppf -> (fun ppf ->
if Block_hash.equal head.hash block.pred then if Block_hash.equal head.hash block.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,6 +144,22 @@ type error +=
| Invalid_operation of Operation_hash.t | Invalid_operation of Operation_hash.t
| Non_increasing_timestamp | Non_increasing_timestamp
| Non_increasing_fitness | Non_increasing_fitness
| Wrong_level of Int32.t * Int32.t
let () =
register_error_kind
`Permanent
~id:"validator.wrong_level"
~title:"Wrong level"
~description:"The block level is not the expected one"
~pp:(fun ppf (e, g) ->
Format.fprintf ppf
"The declared level %ld is not %ld" g e)
Data_encoding.(obj2
(req "expected" int32)
(req "provided" int32))
(function Wrong_level (e, g) -> Some (e, g) | _ -> None)
(fun (e, g) -> Wrong_level (e, g))
let apply_block net db let apply_block net db
(pred: State.Valid_block.t) hash (block: State.Block_header.t) = (pred: State.Valid_block.t) hash (block: State.Block_header.t) =
@ -151,10 +169,13 @@ let apply_block net db
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
(Int32.succ pred.level = block.shell.level)
(Wrong_level (Int32.succ pred.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.Operation_list.fetch
db (hash, 0) block.shell.operations >>= fun operation_hashes -> db (hash, 0) block.shell.operations_hash >>= fun operation_hashes ->
Lwt_list.map_p Lwt_list.map_p
(fun op -> Distributed_db.Operation.fetch db op) (fun op -> Distributed_db.Operation.fetch db op)
operation_hashes >>= fun operations -> operation_hashes >>= fun operations ->
@ -181,10 +202,8 @@ let apply_block net db
begin begin
match pred.protocol with match pred.protocol with
| None -> fail (State.Unknown_protocol pred.protocol_hash) | None -> fail (State.Unknown_protocol pred.protocol_hash)
| Some p -> | Some p -> return p
Context.set_timestamp pred.context block.shell.timestamp >>= fun c -> end >>=? fun (module Proto) ->
return (p, c)
end >>=? fun ((module Proto), patched_context) ->
lwt_debug "validation of %a: Proto %a" lwt_debug "validation of %a: Proto %a"
Block_hash.pp_short hash Block_hash.pp_short hash
Protocol_hash.pp_short Proto.hash >>= fun () -> Protocol_hash.pp_short Proto.hash >>= fun () ->
@ -200,9 +219,12 @@ let apply_block net db
operations >>=? fun parsed_operations -> operations >>=? fun parsed_operations ->
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
pred.context pred.hash block.shell.timestamp >>= fun context ->
Proto.begin_application Proto.begin_application
~predecessor_context:patched_context ~predecessor_context:context
~predecessor_timestamp:pred.timestamp ~predecessor_timestamp:pred.timestamp
~predecessor_fitness:pred.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 ->
@ -466,7 +488,7 @@ module Context_db = struct
end end
let rec create_validator ?parent worker state db net = let rec create_validator ?max_ttl ?parent worker state db net =
let queue = Lwt_pipe.create () in let queue = Lwt_pipe.create () in
let current_ops = ref (fun () -> []) in let current_ops = ref (fun () -> []) in
@ -550,6 +572,8 @@ let rec create_validator ?parent worker state db net =
notify_block ; notify_block ;
fetch_block ; fetch_block ;
create_child ; create_child ;
check_child ;
deactivate_child ;
test_validator ; test_validator ;
bootstrapped ; bootstrapped ;
new_head_input ; new_head_input ;
@ -567,36 +591,62 @@ let rec create_validator ?parent worker state db net =
and fetch_block hash = and fetch_block hash =
Context_db.fetch session v hash Context_db.fetch session v hash
and create_child block = and create_child block protocol expiration =
begin if State.Net.allow_forked_network net then begin
deactivate_child () >>= fun () ->
begin
State.Net.get state net_id >>= function
| Ok net_store -> return net_store
| Error _ ->
State.Valid_block.fork_testnet
state net block protocol expiration >>=? fun net_store ->
State.Valid_block.Current.head net_store >>= fun block ->
Watcher.notify v.worker.valid_block_input block ;
return net_store
end >>=? fun net_store ->
worker.activate ~parent:v net_store >>= fun child ->
v.child <- Some child ;
return ()
end else begin
(* Ignoring request... *)
return ()
end
and deactivate_child () =
match v.child with
| None -> Lwt.return_unit
| Some child ->
v.child <- None ;
deactivate child
and check_child genesis protocol expiration current_time =
let activated =
match v.child with match v.child with
| None -> Lwt.return_unit | None -> false
| Some child -> | Some child ->
v.child <- None ; Block_hash.equal (State.Net.genesis child.net).block genesis in
deactivate child begin
end >>= fun () -> match max_ttl with
match block.test_network with | None -> Lwt.return expiration
| None -> return () | Some ttl ->
| Some (net_id, expiration) -> Distributed_db.Block_header.fetch net_db genesis >>= fun genesis ->
begin Lwt.return
State.Net.get state net_id >>= function (Time.min expiration
| Ok net_store -> return net_store (Time.add genesis.shell.timestamp (Int64.of_int ttl)))
| Error _ -> end >>= fun local_expiration ->
State.Valid_block.fork_testnet let expired = Time.(local_expiration <= current_time) in
state net block expiration >>=? fun net_store -> if expired && activated then
State.Valid_block.Current.head net_store >>= fun block -> deactivate_child () >>= return
Watcher.notify v.worker.valid_block_input block ; else if not activated && not expired then
return net_store fetch_block genesis >>=? fun genesis ->
end >>=? fun net_store -> create_child genesis protocol expiration
worker.activate ~parent:v net_store >>= fun child -> else
v.child <- Some child ; return ()
return ()
and test_validator () = and test_validator () =
match v.child with match v.child with
| None -> None | None -> None
| Some child -> Some (child, child.net_db) | Some child -> Some (child, child.net_db)
in in
new_blocks := begin new_blocks := begin
@ -619,7 +669,7 @@ let rec create_validator ?parent worker state db net =
type error += Unknown_network of Net_id.t type error += Unknown_network of Net_id.t
let create_worker state db = let create_worker ?max_ttl state db =
let validators : t Lwt.t Net_id.Table.t = let validators : t Lwt.t Net_id.Table.t =
Net_id.Table.create 7 in Net_id.Table.create 7 in
@ -750,10 +800,9 @@ let create_worker state db =
let net_id = State.Net.id net in let net_id = State.Net.id net in
lwt_log_notice "activate network %a" lwt_log_notice "activate network %a"
Net_id.pp net_id >>= fun () -> Net_id.pp net_id >>= fun () ->
State.Valid_block.Current.genesis net >>= fun genesis ->
get net_id >>= function get net_id >>= function
| Error _ -> | Error _ ->
let v = create_validator ?parent worker state db net in let v = create_validator ?max_ttl ?parent worker state db net in
Net_id.Table.add validators net_id v ; Net_id.Table.add validators net_id v ;
v v
| Ok v -> Lwt.return v | Ok v -> Lwt.return v

View File

@ -9,7 +9,7 @@
type worker type worker
val create_worker: State.t -> Distributed_db.t -> worker val create_worker: ?max_ttl:int -> State.t -> Distributed_db.t -> worker
val shutdown: worker -> unit Lwt.t val shutdown: worker -> unit Lwt.t
val notify_block: worker -> Block_hash.t -> State.Block_header.t -> unit Lwt.t val notify_block: worker -> Block_hash.t -> State.Block_header.t -> unit Lwt.t

View File

@ -82,7 +82,7 @@ module Ed25519 = struct
(conv (conv
Sodium.Sign.Bigbytes.of_public_key Sodium.Sign.Bigbytes.of_public_key
Sodium.Sign.Bigbytes.to_public_key Sodium.Sign.Bigbytes.to_public_key
bytes) (Fixed.bytes Sodium.Sign.public_key_size))
let hash v = let hash v =
Public_key_hash.hash_bytes Public_key_hash.hash_bytes
@ -144,7 +144,7 @@ module Ed25519 = struct
(conv (conv
Sodium.Sign.Bigbytes.of_secret_key Sodium.Sign.Bigbytes.of_secret_key
Sodium.Sign.Bigbytes.to_secret_key Sodium.Sign.Bigbytes.to_secret_key
bytes) (Fixed.bytes Sodium.Sign.secret_key_size))
end end
@ -199,7 +199,7 @@ module Ed25519 = struct
| None -> Data_encoding.Json.cannot_destruct | None -> Data_encoding.Json.cannot_destruct
"Ed25519 signature: unexpected prefix.") "Ed25519 signature: unexpected prefix.")
string) string)
~binary: (Fixed.bytes 64) ~binary: (Fixed.bytes Sodium.Sign.signature_size)
let check public_key signature msg = let check public_key signature msg =
try try

View File

@ -9,11 +9,10 @@
(** Tezos Protocol Environment - Protocol Implementation Signature *) (** Tezos Protocol Environment - Protocol Implementation Signature *)
(** The score of a block as a sequence of as unsigned bytes. Ordered (* See `src/proto/updater.mli` for documentation. *)
by length and then by contents lexicographically. *)
type fitness = Fitness.fitness type fitness = Fitness.fitness
(** The version agnostic toplevel structure of operations. *)
type shell_operation = Store.Operation.shell_header = { type shell_operation = Store.Operation.shell_header = {
net_id: Net_id.t ; net_id: Net_id.t ;
} }
@ -23,20 +22,13 @@ type raw_operation = Store.Operation.t = {
proto: MBytes.t ; proto: MBytes.t ;
} }
(** The version agnostic toplevel structure of blocks. *)
type shell_block = Store.Block_header.shell_header = type shell_block = Store.Block_header.shell_header =
{ net_id: Net_id.t ; { net_id: Net_id.t ;
(** The genesis of the chain this block belongs to. *) level: Int32.t ;
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
(** The preceding block in the chain. *)
timestamp: Time.t ; timestamp: Time.t ;
(** The date at which this block has been forged. *) operations_hash: Operation_list_list_hash.t ;
operations: Operation_list_list_hash.t ;
(** The sequence of operations. *)
fitness: MBytes.t list ; fitness: MBytes.t list ;
(** The announced score of the block. As a sequence of sequences
of unsigned bytes. Ordered by length and then by contents
lexicographically. *)
} }
type raw_block = Store.Block_header.t = { type raw_block = Store.Block_header.t = {
@ -44,96 +36,61 @@ type raw_block = Store.Block_header.t = {
proto: MBytes.t ; proto: MBytes.t ;
} }
(** This is the signature of a Tezos protocol implementation. It has type validation_result = {
access to the standard library and the Environment module. *) context: Context.t ;
fitness: Fitness.fitness ;
message: string option ;
}
type rpc_context = {
context: Context.t ;
level: Int32.t ;
timestamp: Time.t ;
fitness: Fitness.fitness ;
}
module type PROTOCOL = sig module type PROTOCOL = sig
type error = .. type error = ..
type 'a tzresult = ('a, error list) result type 'a tzresult = ('a, error list) result
(** The version specific type of operations. *)
type operation
(** The maximum size of operations in bytes *)
val max_operation_data_length : int val max_operation_data_length : int
(** The maximum size of block headers in bytes *)
val max_block_length : int val max_block_length : int
(** The maximum *)
val max_number_of_operations : int val max_number_of_operations : int
(** The parsing / preliminary validation function for type operation
operations. Similar to {!parse_block}. *)
val parse_operation : val parse_operation :
Operation_hash.t -> raw_operation -> operation tzresult Operation_hash.t -> raw_operation -> operation tzresult
(** Basic ordering of operations. [compare_operations op1 op2] means
that [op1] should appear before [op2] in a block. *)
val compare_operations : operation -> operation -> int val compare_operations : operation -> operation -> int
(** A functional state that is transmitted through the steps of a
block validation sequence. It must retain the current state of
the store (that can be extracted from the outside using
{!current_context}, and whose final value is produced by
{!finalize_block}). It can also contain the information that
must be remembered during the validation, which must be
immutable (as validator or baker implementations are allowed to
pause, replay or backtrack during the validation process). *)
type validation_state type validation_state
(** Access the context at a given validation step. *)
val current_context : validation_state -> Context.t tzresult Lwt.t val current_context : validation_state -> Context.t tzresult Lwt.t
(** Checks that a block is well formed in a given context. This
function should run quickly, as its main use is to reject bad
blocks from the network as early as possible. The input context
is the one resulting of an ancestor block of same protocol
version, not necessarily the one of its predecessor. *)
val precheck_block : val precheck_block :
ancestor_context: Context.t -> ancestor_context: Context.t ->
ancestor_timestamp: Time.t -> ancestor_timestamp: Time.t ->
raw_block -> raw_block ->
unit tzresult Lwt.t unit tzresult Lwt.t
(** The first step in a block validation sequence. Initializes a
validation context for validating a block. Takes as argument the
{!raw_block} to initialize the context for this block, patching
the context resulting of the application of the predecessor
block passed as parameter. The function {!precheck_block} may
not have been called before [begin_application], so all the
check performed by the former must be repeated in the latter. *)
val begin_application : val begin_application :
predecessor_context: Context.t -> predecessor_context: Context.t ->
predecessor_timestamp: Time.t -> predecessor_timestamp: Time.t ->
predecessor_fitness: Fitness.fitness ->
raw_block -> raw_block ->
validation_state tzresult Lwt.t validation_state tzresult Lwt.t
(** Initializes a validation context for constructing a new block
(as opposed to validating an existing block). Since there is no
{!raw_block} header available, the parts that it provides are
passed as arguments (predecessor block hash, context resulting
of the application of the predecessor block, and timestamp). *)
val begin_construction : val begin_construction :
predecessor_context: Context.t -> predecessor_context: Context.t ->
predecessor_timestamp: Time.t -> predecessor_timestamp: Time.t ->
predecessor_level: Int32.t ->
predecessor_fitness: Fitness.fitness ->
predecessor: Block_hash.t -> predecessor: Block_hash.t ->
timestamp: Time.t -> timestamp: Time.t ->
validation_state tzresult Lwt.t validation_state tzresult Lwt.t
(** Called after {!begin_application} (or {!begin_construction}) and
before {!finalize_block}, with each operation in the block. *)
val apply_operation : val apply_operation :
validation_state -> operation -> validation_state tzresult Lwt.t validation_state -> operation -> validation_state tzresult Lwt.t
(** The last step in a block validation sequence. It produces the
context that will be used as input for the validation of its
successor block candidates. *)
val finalize_block : val finalize_block :
validation_state -> Context.t tzresult Lwt.t validation_state -> validation_result tzresult Lwt.t
(** The list of remote procedures exported by this implementation *) val rpc_services : rpc_context RPC.directory
val rpc_services : Context.t RPC.directory
val configure_sandbox : val configure_sandbox :
Context.t -> Data_encoding.json option -> Context.t tzresult Lwt.t Context.t -> Data_encoding.json option -> Context.t tzresult Lwt.t

View File

@ -41,15 +41,19 @@ let register (module Proto : Protocol.PACKED_PROTOCOL) =
raw_block >|= wrap_error raw_block >|= wrap_error
let begin_application let begin_application
~predecessor_context ~predecessor_timestamp ~predecessor_context ~predecessor_timestamp
~predecessor_fitness
raw_block = raw_block =
begin_application begin_application
~predecessor_context ~predecessor_timestamp ~predecessor_context ~predecessor_timestamp
~predecessor_fitness
raw_block >|= wrap_error raw_block >|= wrap_error
let begin_construction let begin_construction
~predecessor_context ~predecessor_timestamp ~predecessor_context ~predecessor_timestamp
~predecessor_level ~predecessor_fitness
~predecessor ~timestamp = ~predecessor ~timestamp =
begin_construction begin_construction
~predecessor_context ~predecessor_timestamp ~predecessor_context ~predecessor_timestamp
~predecessor_level ~predecessor_fitness
~predecessor ~timestamp >|= wrap_error ~predecessor ~timestamp >|= wrap_error
let current_context c = let current_context c =
current_context c >|= wrap_error current_context c >|= wrap_error

View File

@ -11,6 +11,19 @@ open Logging.Updater
let (//) = Filename.concat let (//) = Filename.concat
type validation_result = Protocol.validation_result = {
context: Context.t ;
fitness: Fitness.fitness ;
message: string option ;
}
type rpc_context = Protocol.rpc_context = {
context: Context.t ;
level: Int32.t ;
timestamp: Time.t ;
fitness: Fitness.fitness ;
}
module type PROTOCOL = Protocol.PROTOCOL module type PROTOCOL = Protocol.PROTOCOL
module type REGISTRED_PROTOCOL = sig module type REGISTRED_PROTOCOL = sig
val hash: Protocol_hash.t val hash: Protocol_hash.t
@ -30,20 +43,13 @@ type raw_operation = Store.Operation.t = {
} }
let raw_operation_encoding = Store.Operation.encoding let raw_operation_encoding = Store.Operation.encoding
(** The version agnostic toplevel structure of blocks. *)
type shell_block = Store.Block_header.shell_header = { type shell_block = Store.Block_header.shell_header = {
net_id: Net_id.t ; net_id: Net_id.t ;
(** The genesis of the chain this block belongs to. *) level: Int32.t ;
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
(** The preceding block in the chain. *)
timestamp: Time.t ; timestamp: Time.t ;
(** The date at which this block has been forged. *) operations_hash: Operation_list_list_hash.t ;
operations: Operation_list_list_hash.t ;
(** The sequence of operations. *)
fitness: MBytes.t list ; fitness: MBytes.t list ;
(** The announced score of the block. As a sequence of sequences
of unsigned bytes. Ordered by length and then by contents
lexicographically. *)
} }
let shell_block_encoding = Store.Block_header.shell_header_encoding let shell_block_encoding = Store.Block_header.shell_header_encoding
@ -65,7 +71,6 @@ let register hash proto =
let activate = Context.set_protocol let activate = Context.set_protocol
let fork_test_network = Context.fork_test_network let fork_test_network = Context.fork_test_network
let set_test_protocol = Context.set_test_protocol
let get_exn hash = VersionTable.find versions hash let get_exn hash = VersionTable.find versions hash
let get hash = let get hash =

View File

@ -18,20 +18,13 @@ type raw_operation = Store.Operation.t = {
} }
val raw_operation_encoding: raw_operation Data_encoding.t val raw_operation_encoding: raw_operation Data_encoding.t
(** The version agnostic toplevel structure of blocks. *)
type shell_block = Store.Block_header.shell_header = { type shell_block = Store.Block_header.shell_header = {
net_id: Net_id.t ; net_id: Net_id.t ;
(** The genesis of the chain this block belongs to. *) level: Int32.t ;
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
(** The preceding block in the chain. *)
timestamp: Time.t ; timestamp: Time.t ;
(** The date at which this block has been forged. *) operations_hash: Operation_list_list_hash.t ;
operations: Operation_list_list_hash.t ;
(** The sequence of operations. *)
fitness: MBytes.t list ; fitness: MBytes.t list ;
(** The announced score of the block. As a sequence of sequences
of unsigned bytes. Ordered by length and then by contents
lexicographically. *)
} }
val shell_block_encoding: shell_block Data_encoding.t val shell_block_encoding: shell_block Data_encoding.t
@ -41,6 +34,19 @@ type raw_block = Store.Block_header.t = {
} }
val raw_block_encoding: raw_block Data_encoding.t val raw_block_encoding: raw_block Data_encoding.t
type validation_result = Protocol.validation_result = {
context: Context.t ;
fitness: Fitness.fitness ;
message: string option ;
}
type rpc_context = Protocol.rpc_context = {
context: Context.t ;
level: Int32.t ;
timestamp: Time.t ;
fitness: Fitness.fitness ;
}
module type PROTOCOL = Protocol.PROTOCOL module type PROTOCOL = Protocol.PROTOCOL
module type REGISTRED_PROTOCOL = sig module type REGISTRED_PROTOCOL = sig
val hash: Protocol_hash.t val hash: Protocol_hash.t
@ -60,8 +66,8 @@ val extract: Lwt_io.file_name -> Protocol_hash.t -> component list -> unit Lwt.t
val compile: Protocol_hash.t -> component list -> bool Lwt.t val compile: Protocol_hash.t -> component list -> bool Lwt.t
val activate: Context.t -> Protocol_hash.t -> Context.t Lwt.t val activate: Context.t -> Protocol_hash.t -> Context.t Lwt.t
val set_test_protocol: Context.t -> Protocol_hash.t -> Context.t Lwt.t val fork_test_network:
val fork_test_network: Context.t -> Context.t Lwt.t Context.t -> protocol:Protocol_hash.t -> expiration:Time.t -> Context.t Lwt.t
val register: Protocol_hash.t -> (module REGISTRED_PROTOCOL) -> unit val register: Protocol_hash.t -> (module REGISTRED_PROTOCOL) -> unit

View File

@ -67,9 +67,10 @@ let start_new_voting_cycle ctxt =
Vote.clear_ballots ctxt >>= fun ctxt -> Vote.clear_ballots ctxt >>= fun ctxt ->
Vote.clear_listings ctxt >>=? fun ctxt -> Vote.clear_listings ctxt >>=? fun ctxt ->
if approved then if approved then
let expiration = (* in two days maximum... *)
Time.add (Timestamp.current ctxt) (Int64.mul 48L 3600L) in
Vote.get_current_proposal ctxt >>=? fun proposal -> Vote.get_current_proposal ctxt >>=? fun proposal ->
set_test_protocol ctxt proposal >>= fun ctxt -> fork_test_network ctxt proposal expiration >>= fun ctxt ->
fork_test_network ctxt >>= fun ctxt ->
Vote.set_current_period_kind ctxt Testing >>=? fun ctxt -> Vote.set_current_period_kind ctxt Testing >>=? fun ctxt ->
return ctxt return ctxt
else else
@ -133,12 +134,13 @@ let record_ballot ctxt delegate proposal ballot =
| Testing | Proposal -> | Testing | Proposal ->
fail Unexpected_ballot fail Unexpected_ballot
let first_of_a_voting_period l = let last_of_a_voting_period ctxt l =
Compare.Int32.(l.Level.voting_period_position = 0l) Compare.Int32.(Int32.succ l.Level.voting_period_position =
Constants.voting_period_length ctxt )
let may_start_new_voting_cycle ctxt = let may_start_new_voting_cycle ctxt =
Level.current ctxt >>=? fun level -> let level = Level.current ctxt in
if first_of_a_voting_period level then if last_of_a_voting_period ctxt level then
start_new_voting_cycle ctxt start_new_voting_cycle ctxt
else else
return ctxt return ctxt

View File

@ -51,19 +51,19 @@ let apply_delegate_operation_content
(Block_hash.equal block pred_block) (Block_hash.equal block pred_block)
(Wrong_endorsement_predecessor (pred_block, block)) >>=? fun () -> (Wrong_endorsement_predecessor (pred_block, block)) >>=? fun () ->
Mining.check_signing_rights ctxt slot delegate >>=? fun () -> Mining.check_signing_rights ctxt slot delegate >>=? fun () ->
Fitness.increase ctxt >>=? fun ctxt -> let ctxt = Fitness.increase ctxt in
Mining.pay_endorsement_bond ctxt delegate >>=? fun (ctxt, bond) -> Mining.pay_endorsement_bond ctxt delegate >>=? fun (ctxt, bond) ->
Mining.endorsement_reward ~block_priority >>=? fun reward -> Mining.endorsement_reward ~block_priority >>=? fun reward ->
Level.current ctxt >>=? fun { cycle = current_cycle } -> let { cycle = current_cycle } : Level.t = Level.current ctxt in
Lwt.return Tez.(reward +? bond) >>=? fun full_reward -> Lwt.return Tez.(reward +? bond) >>=? fun full_reward ->
Reward.record ctxt delegate current_cycle full_reward Reward.record ctxt delegate current_cycle full_reward
| Proposals { period ; proposals } -> | Proposals { period ; proposals } ->
Level.current ctxt >>=? fun level -> let level = Level.current ctxt in
fail_unless Voting_period.(level.voting_period = period) fail_unless Voting_period.(level.voting_period = period)
(Wrong_voting_period (level.voting_period, period)) >>=? fun () -> (Wrong_voting_period (level.voting_period, period)) >>=? fun () ->
Amendment.record_proposals ctxt delegate proposals Amendment.record_proposals ctxt delegate proposals
| Ballot { period ; proposal ; ballot } -> | Ballot { period ; proposal ; ballot } ->
Level.current ctxt >>=? fun level -> let level = Level.current ctxt in
fail_unless Voting_period.(level.voting_period = period) fail_unless Voting_period.(level.voting_period = period)
(Wrong_voting_period (level.voting_period, period)) >>=? fun () -> (Wrong_voting_period (level.voting_period, period)) >>=? fun () ->
Amendment.record_ballot ctxt delegate proposal ballot Amendment.record_ballot ctxt delegate proposal ballot
@ -175,8 +175,9 @@ let apply_sourced_operation
| Dictator_operation (Activate_testnet hash) -> | Dictator_operation (Activate_testnet hash) ->
let dictator_pubkey = Constants.dictator_pubkey ctxt in let dictator_pubkey = Constants.dictator_pubkey ctxt in
Operation.check_signature dictator_pubkey operation >>=? fun () -> Operation.check_signature dictator_pubkey operation >>=? fun () ->
set_test_protocol ctxt hash >>= fun ctxt -> let expiration = (* in two days maximum... *)
fork_test_network ctxt >>= fun ctxt -> Time.add (Timestamp.current ctxt) (Int64.mul 48L 3600L) in
fork_test_network ctxt hash expiration >>= fun ctxt ->
return (ctxt, origination_nonce, None) return (ctxt, origination_nonce, None)
let apply_anonymous_operation ctxt miner_contract origination_nonce kind = let apply_anonymous_operation ctxt miner_contract origination_nonce kind =
@ -228,17 +229,14 @@ let apply_operation
let may_start_new_cycle ctxt = let may_start_new_cycle ctxt =
Mining.dawn_of_a_new_cycle ctxt >>=? function Mining.dawn_of_a_new_cycle ctxt >>=? function
| None -> return ctxt | None -> return ctxt
| Some new_cycle -> | Some last_cycle ->
let last_cycle = let new_cycle = Cycle.succ last_cycle in
match Cycle.pred new_cycle with
| None -> assert false
| Some last_cycle -> last_cycle in
Bootstrap.refill ctxt >>=? fun ctxt -> Bootstrap.refill ctxt >>=? fun ctxt ->
Seed.clear_cycle ctxt last_cycle >>=? fun ctxt -> Seed.clear_cycle ctxt last_cycle >>=? fun ctxt ->
Seed.compute_for_cycle ctxt (Cycle.succ new_cycle) >>=? fun ctxt -> Seed.compute_for_cycle ctxt (Cycle.succ new_cycle) >>=? fun ctxt ->
Roll.clear_cycle ctxt last_cycle >>=? fun ctxt -> Roll.clear_cycle ctxt last_cycle >>=? fun ctxt ->
Roll.freeze_rolls_for_cycle ctxt (Cycle.succ new_cycle) >>=? fun ctxt -> Roll.freeze_rolls_for_cycle ctxt (Cycle.succ new_cycle) >>=? fun ctxt ->
Timestamp.get_current ctxt >>= fun timestamp -> let timestamp = Timestamp.current ctxt in
Lwt.return (Timestamp.(timestamp +? (Constants.time_before_reward ctxt))) Lwt.return (Timestamp.(timestamp +? (Constants.time_before_reward ctxt)))
>>=? fun reward_date -> >>=? fun reward_date ->
Reward.set_reward_time_for_cycle Reward.set_reward_time_for_cycle
@ -254,28 +252,20 @@ let begin_application ctxt block pred_timestamp =
Mining.check_mining_rights ctxt block pred_timestamp >>=? fun miner -> Mining.check_mining_rights ctxt block pred_timestamp >>=? fun miner ->
Mining.check_signature ctxt block miner >>=? fun () -> Mining.check_signature ctxt block miner >>=? fun () ->
Mining.pay_mining_bond ctxt block miner >>=? fun ctxt -> Mining.pay_mining_bond ctxt block miner >>=? fun ctxt ->
Fitness.increase ctxt >>=? fun ctxt -> let ctxt = Fitness.increase ctxt in
return (ctxt, miner) return (ctxt, miner)
let finalize_application ctxt block miner op_count = let finalize_application ctxt block miner =
(* end of level (from this point nothing should fail) *) (* end of level (from this point nothing should fail) *)
let priority = block.Block.proto.mining_slot.priority in let priority = block.Block.proto.priority in
let reward = Mining.base_mining_reward ctxt ~priority in let reward = Mining.base_mining_reward ctxt ~priority in
Nonce.record_hash ctxt Nonce.record_hash ctxt
miner reward block.proto.seed_nonce_hash >>=? fun ctxt -> miner reward block.proto.seed_nonce_hash >>=? fun ctxt ->
Reward.pay_due_rewards ctxt >>=? fun ctxt -> Reward.pay_due_rewards ctxt >>=? fun ctxt ->
Level.increment_current ctxt >>=? fun ctxt ->
(* end of cycle *) (* end of cycle *)
may_start_new_cycle ctxt >>=? fun ctxt -> may_start_new_cycle ctxt >>=? fun ctxt ->
Amendment.may_start_new_voting_cycle ctxt >>=? fun ctxt -> Amendment.may_start_new_voting_cycle ctxt >>=? fun ctxt ->
Level.current ctxt >>=? fun { level } -> return ctxt
let level = Raw_level.to_int32 level in
Fitness.get ctxt >>=? fun fitness ->
let commit_message =
Format.asprintf
"lvl %ld, fit %Ld, prio %ld, %d ops"
level fitness priority op_count in
return (commit_message, ctxt)
let compare_operations op1 op2 = let compare_operations op1 op2 =
match op1.contents, op2.contents with match op1.contents, op2.contents with

View File

@ -19,37 +19,23 @@ type header = {
} }
and proto_header = { and proto_header = {
mining_slot: mining_slot ; priority: int ;
seed_nonce_hash: Nonce_hash.t ; seed_nonce_hash: Nonce_hash.t ;
proof_of_work_nonce: MBytes.t ; proof_of_work_nonce: MBytes.t ;
} }
and mining_slot = {
level: Raw_level_repr.t ;
priority: Int32.t ;
}
let mining_slot_encoding =
let open Data_encoding in
conv
(fun { level ; priority } -> level, priority)
(fun (level, priority) -> { level ; priority })
(obj2
(req "level" Raw_level_repr.encoding)
(req "proprity" int32))
let proto_header_encoding = let proto_header_encoding =
let open Data_encoding in let open Data_encoding in
conv conv
(fun { mining_slot ; seed_nonce_hash ; proof_of_work_nonce } -> (fun { priority ; seed_nonce_hash ; proof_of_work_nonce } ->
(mining_slot, (seed_nonce_hash, proof_of_work_nonce))) (priority, seed_nonce_hash, proof_of_work_nonce))
(fun (mining_slot, (seed_nonce_hash, proof_of_work_nonce)) -> (fun (priority, seed_nonce_hash, proof_of_work_nonce) ->
{ mining_slot ; seed_nonce_hash ; proof_of_work_nonce }) { priority ; seed_nonce_hash ; proof_of_work_nonce })
(merge_objs (obj3
mining_slot_encoding (req "priority" uint16)
(obj2 (req "seed_nonce_hash" Nonce_hash.encoding)
(req "seed_nonce_hash" Nonce_hash.encoding) (req "proof_of_work_nonce"
(req "proof_of_work_nonce" (Fixed.bytes Constants_repr.proof_of_work_nonce_size)))) (Fixed.bytes Constants_repr.proof_of_work_nonce_size)))
let signed_proto_header_encoding = let signed_proto_header_encoding =
let open Data_encoding in let open Data_encoding in
@ -76,13 +62,15 @@ type error +=
| Cant_parse_proto_header | Cant_parse_proto_header
let parse_header let parse_header
({ shell = { net_id ; predecessor ; timestamp ; fitness ; operations } ; ({ shell = { net_id ; level ; predecessor ;
timestamp ; fitness ; operations_hash } ;
proto } : Updater.raw_block) : header tzresult = proto } : Updater.raw_block) : header tzresult =
match Data_encoding.Binary.of_bytes signed_proto_header_encoding proto with match Data_encoding.Binary.of_bytes signed_proto_header_encoding proto with
| None -> Error [Cant_parse_proto_header] | None -> Error [Cant_parse_proto_header]
| Some (proto, signature) -> | Some (proto, signature) ->
let shell = let shell =
{ Updater.net_id ; predecessor ; timestamp ; fitness ; operations } in { Updater.net_id ; level ; predecessor ;
timestamp ; fitness ; operations_hash } in
Ok { shell ; proto ; signature } Ok { shell ; proto ; signature }
let forge_header shell proto = let forge_header shell proto =

View File

@ -17,18 +17,11 @@ type header = {
} }
and proto_header = { and proto_header = {
mining_slot: mining_slot ; priority: int ;
seed_nonce_hash: Nonce_hash.t ; seed_nonce_hash: Nonce_hash.t ;
proof_of_work_nonce: MBytes.t ; proof_of_work_nonce: MBytes.t ;
} }
and mining_slot = {
level: Raw_level_repr.t ;
priority: Int32.t ;
}
val mining_slot_encoding: mining_slot Data_encoding.encoding
(** The maximum size of block headers in bytes *) (** The maximum size of block headers in bytes *)
val max_header_length: int val max_header_length: int

View File

@ -38,7 +38,7 @@ type constants = {
voting_period_length: int32 ; voting_period_length: int32 ;
time_before_reward: Period_repr.t ; time_before_reward: Period_repr.t ;
slot_durations: Period_repr.t list ; slot_durations: Period_repr.t list ;
first_free_mining_slot: int32 ; first_free_mining_slot: int ;
max_signing_slot: int ; max_signing_slot: int ;
instructions_per_transaction: int ; instructions_per_transaction: int ;
proof_of_work_threshold: int64 ; proof_of_work_threshold: int64 ;
@ -58,7 +58,7 @@ let default = {
Int64.(mul 365L (mul 24L 3600L)) ; Int64.(mul 365L (mul 24L 3600L)) ;
slot_durations = slot_durations =
List.map Period_repr.of_seconds_exn [ 60L ] ; List.map Period_repr.of_seconds_exn [ 60L ] ;
first_free_mining_slot = 16l ; first_free_mining_slot = 16 ;
max_signing_slot = 15 ; max_signing_slot = 15 ;
instructions_per_transaction = 16 * 1024 ; instructions_per_transaction = 16 * 1024 ;
proof_of_work_threshold = proof_of_work_threshold =
@ -103,7 +103,7 @@ let constants_encoding =
opt Compare_slot_durations.(=) opt Compare_slot_durations.(=)
default.slot_durations c.slot_durations default.slot_durations c.slot_durations
and first_free_mining_slot = and first_free_mining_slot =
opt Compare.Int32.(=) opt Compare.Int.(=)
default.first_free_mining_slot c.first_free_mining_slot default.first_free_mining_slot c.first_free_mining_slot
and max_signing_slot = and max_signing_slot =
opt Compare.Int.(=) opt Compare.Int.(=)
@ -171,8 +171,8 @@ let constants_encoding =
(opt "voting_period_length" int32) (opt "voting_period_length" int32)
(opt "time_before_reward" int64) (opt "time_before_reward" int64)
(opt "slot_durations" (list Period_repr.encoding)) (opt "slot_durations" (list Period_repr.encoding))
(opt "first_free_mining_slot" int32) (opt "first_free_mining_slot" uint16)
(opt "max_signing_slot" int31) (opt "max_signing_slot" uint16)
(opt "instructions_per_transaction" int31) (opt "instructions_per_transaction" int31)
(opt "proof_of_work_threshold" int64) (opt "proof_of_work_threshold" int64)
(opt "bootstrap_keys" (list Ed25519.Public_key.encoding)) (opt "bootstrap_keys" (list Ed25519.Public_key.encoding))

View File

@ -16,9 +16,9 @@ let int64_to_bytes i =
let int64_of_bytes b = let int64_of_bytes b =
if Compare.Int.(MBytes.length b <> 8) then if Compare.Int.(MBytes.length b <> 8) then
fail Invalid_fitness error Invalid_fitness
else else
return (MBytes.get_int64 b 0) ok (MBytes.get_int64 b 0)
let from_int64 fitness = let from_int64 fitness =
[ MBytes.of_string Constants_repr.version_number ; [ MBytes.of_string Constants_repr.version_number ;
@ -30,5 +30,5 @@ let to_int64 = function
when Compare.String. when Compare.String.
(MBytes.to_string version = Constants_repr.version_number) -> (MBytes.to_string version = Constants_repr.version_number) ->
int64_of_bytes fitness int64_of_bytes fitness
| [] -> return 0L | [] -> ok 0L
| _ -> fail Invalid_fitness | _ -> error Invalid_fitness

View File

@ -7,17 +7,7 @@
(* *) (* *)
(**************************************************************************) (**************************************************************************)
let get ctxt = let current = Storage.current_fitness
Storage.get_fitness ctxt >>= fun fitness ->
Fitness_repr.to_int64 fitness
let set ctxt v =
Storage.set_fitness ctxt (Fitness_repr.from_int64 v) >>= fun ctxt ->
Lwt.return ctxt
let increase ctxt = let increase ctxt =
get ctxt >>=? fun v -> let fitness = current ctxt in
set ctxt (Int64.succ v) >>= fun ctxt -> Storage.set_current_fitness ctxt (Int64.succ fitness)
return ctxt
let init ctxt = set ctxt 0L

View File

@ -7,25 +7,9 @@
(* *) (* *)
(**************************************************************************) (**************************************************************************)
let version_key = ["version"]
(* This key should always be populated for every version of the
protocol. It's absence meaning that the context is empty. *)
let version_value = "alpha"
(* This is the genesis protocol: initialise the state *) (* This is the genesis protocol: initialise the state *)
let initialize ~from_genesis (ctxt:Context.t) = let initialize store =
Context.set ctxt version_key (MBytes.of_string version_value) >>= fun ctxt ->
Storage.prepare ctxt >>=? fun store ->
begin
if from_genesis then
Lwt.return store
else
Fitness_storage.init store
end >>= fun store ->
Level_storage.init store >>=? fun store ->
Roll_storage.init store >>=? fun store -> Roll_storage.init store >>=? fun store ->
Nonce_storage.init store >>=? fun store ->
Seed_storage.init store >>=? fun store -> Seed_storage.init store >>=? fun store ->
Contract_storage.init store >>=? fun store -> Contract_storage.init store >>=? fun store ->
Reward_storage.init store >>=? fun store -> Reward_storage.init store >>=? fun store ->
@ -38,34 +22,25 @@ let initialize ~from_genesis (ctxt:Context.t) =
return store return store
type error += type error +=
| Incompatiple_protocol_version
| Unimplemented_sandbox_migration | Unimplemented_sandbox_migration
let may_initialize ctxt = let may_initialize ctxt ~level ~timestamp ~fitness =
Context.get ctxt version_key >>= function Storage.prepare ~level ~timestamp ~fitness ctxt >>=? fun (ctxt, first_block) ->
| None -> if first_block then
(* This is the genesis protocol: The only acceptable preceding initialize ctxt
version is an empty context *) else
initialize ~from_genesis:false ctxt return ctxt
| Some bytes ->
let s = MBytes.to_string bytes in
if Compare.String.(s = version_value)
then Storage.prepare ctxt
else if Compare.String.(s = "genesis") then
initialize ~from_genesis:true ctxt
else fail Incompatiple_protocol_version
let configure_sandbox ctxt json = let configure_sandbox ctxt json =
let json = let json =
match json with match json with
| None -> `O [] | None -> `O []
| Some json -> json in | Some json -> json in
Context.get ctxt version_key >>= function Storage.is_first_block ctxt >>=? function
| None -> | true ->
Storage.set_sandboxed ctxt json >>= fun ctxt -> Storage.set_sandboxed ctxt json >>= fun ctxt ->
initialize ~from_genesis:false ctxt >>=? fun ctxt -> return ctxt
return (Storage.recover ctxt) | false ->
| Some _ ->
Storage.get_sandboxed ctxt >>=? function Storage.get_sandboxed ctxt >>=? function
| None -> | None ->
fail Unimplemented_sandbox_migration fail Unimplemented_sandbox_migration

View File

@ -10,6 +10,7 @@
type t = { type t = {
level: Raw_level_repr.t ; level: Raw_level_repr.t ;
level_position: int32 ;
cycle: Cycle_repr.t ; cycle: Cycle_repr.t ;
cycle_position: int32 ; cycle_position: int32 ;
voting_period: Voting_period_repr.t ; voting_period: Voting_period_repr.t ;
@ -22,47 +23,58 @@ let pp ppf { level } = Raw_level_repr.pp ppf level
let pp_full ppf l = let pp_full ppf l =
Format.fprintf ppf Format.fprintf ppf
"%a (cycle %a.%ld) (vote %a.%ld)" "%a.%ld (cycle %a.%ld) (vote %a.%ld)"
Raw_level_repr.pp l.level Raw_level_repr.pp l.level l.level_position
Cycle_repr.pp l.cycle l.cycle_position Cycle_repr.pp l.cycle l.cycle_position
Voting_period_repr.pp l.voting_period l.voting_period_position Voting_period_repr.pp l.voting_period l.voting_period_position
let encoding = let encoding =
let open Data_encoding in let open Data_encoding in
conv conv
(fun { level ; cycle ; cycle_position ; (fun { level ; level_position ;
cycle ; cycle_position ;
voting_period; voting_period_position } -> voting_period; voting_period_position } ->
(level, cycle, cycle_position, (level, level_position,
cycle, cycle_position,
voting_period, voting_period_position)) voting_period, voting_period_position))
(fun (level, cycle, cycle_position, (fun (level, level_position,
cycle, cycle_position,
voting_period, voting_period_position) -> voting_period, voting_period_position) ->
{ level ; cycle ; cycle_position ; { level ; level_position ;
cycle ; cycle_position ;
voting_period ; voting_period_position }) voting_period ; voting_period_position })
(obj5 (obj6
(req "level" Raw_level_repr.encoding) (req "level" Raw_level_repr.encoding)
(req "level_position" int32)
(req "cycle" Cycle_repr.encoding) (req "cycle" Cycle_repr.encoding)
(req "cycle_position" int32) (req "cycle_position" int32)
(req "voting_period" Voting_period_repr.encoding) (req "voting_period" Voting_period_repr.encoding)
(req "voting_period_position" int32)) (req "voting_period_position" int32))
let root = let root first_level =
{ level = Raw_level_repr.root ; { level = first_level ;
level_position = 0l ;
cycle = Cycle_repr.root ; cycle = Cycle_repr.root ;
cycle_position = 0l ; cycle_position = 0l ;
voting_period = Voting_period_repr.root ; voting_period = Voting_period_repr.root ;
voting_period_position = 0l ; voting_period_position = 0l ;
} }
let from_raw ~cycle_length ~voting_period_length level = let from_raw ~first_level ~cycle_length ~voting_period_length level =
let raw_level = Raw_level_repr.to_int32 level in let raw_level = Raw_level_repr.to_int32 level in
let cycle = Cycle_repr.of_int32_exn (Int32.div raw_level cycle_length) in let first_level = Raw_level_repr.to_int32 first_level in
let cycle_position = Int32.rem raw_level cycle_length in let level_position =
Compare.Int32.max 0l (Int32.sub raw_level first_level) in
let cycle =
Cycle_repr.of_int32_exn (Int32.div level_position cycle_length) in
let cycle_position = Int32.rem level_position cycle_length in
let voting_period = let voting_period =
Voting_period_repr.of_int32_exn Voting_period_repr.of_int32_exn
(Int32.div raw_level voting_period_length) in (Int32.div level_position voting_period_length) in
let voting_period_position = let voting_period_position =
Int32.rem raw_level voting_period_length in Int32.rem level_position voting_period_length in
{ level ; cycle ; cycle_position ; { level ; level_position ;
cycle ; cycle_position ;
voting_period ; voting_period_position } voting_period ; voting_period_position }
let diff { level = l1 } { level = l2 } = let diff { level = l1 } { level = l2 } =

View File

@ -9,6 +9,7 @@
type t = private { type t = private {
level: Raw_level_repr.t ; level: Raw_level_repr.t ;
level_position: int32 ;
cycle: Cycle_repr.t ; cycle: Cycle_repr.t ;
cycle_position: int32 ; cycle_position: int32 ;
voting_period: Voting_period_repr.t ; voting_period: Voting_period_repr.t ;
@ -21,10 +22,12 @@ val pp: Format.formatter -> level -> unit
val pp_full: Format.formatter -> level -> unit val pp_full: Format.formatter -> level -> unit
include Compare.S with type t := level include Compare.S with type t := level
val root: level val root: Raw_level_repr.t -> level
val from_raw: val from_raw:
cycle_length:int32 -> voting_period_length:int32 -> first_level:Raw_level_repr.t ->
cycle_length:int32 ->
voting_period_length:int32 ->
Raw_level_repr.t -> level Raw_level_repr.t -> level
val diff: level -> level -> int32 val diff: level -> level -> int32

View File

@ -15,31 +15,29 @@ let from_raw c ?offset l =
| None -> l | None -> l
| Some o -> Raw_level_repr.(of_int32_exn (Int32.add (to_int32 l) o)) in | Some o -> Raw_level_repr.(of_int32_exn (Int32.add (to_int32 l) o)) in
let constants = Storage.constants c in let constants = Storage.constants c in
let first_level = Storage.first_level c in
Level_repr.from_raw Level_repr.from_raw
~first_level
~cycle_length:constants.Constants_repr.cycle_length ~cycle_length:constants.Constants_repr.cycle_length
~voting_period_length:constants.Constants_repr.voting_period_length ~voting_period_length:constants.Constants_repr.voting_period_length
l l
let root c =
Level_repr.root (Storage.first_level c)
let succ c l = from_raw c (Raw_level_repr.succ l.level) let succ c l = from_raw c (Raw_level_repr.succ l.level)
let pred c l = let pred c l =
match Raw_level_repr.pred l.Level_repr.level with match Raw_level_repr.pred l.Level_repr.level with
| None -> None | None -> None
| Some l -> Some (from_raw c l) | Some l -> Some (from_raw c l)
let current ctxt = let current ctxt = Storage.current_level ctxt
Storage.Current_level.get ctxt >>=? fun l ->
return (from_raw ctxt l)
let previous ctxt = let previous ctxt =
current ctxt >>=? fun l -> let l = current ctxt in
match pred ctxt l with match pred ctxt l with
| None -> assert false (* Context inited with level = 1. *) | None -> assert false (* We never validate the Genesis... *)
| Some p -> return p | Some p -> p
let increment_current ctxt =
Storage.Current_level.get ctxt >>=? fun l ->
Storage.Current_level.set ctxt (Raw_level_repr.succ l)
let first_level_in_cycle ctxt c = let first_level_in_cycle ctxt c =
let constants = Storage.constants ctxt in let constants = Storage.constants ctxt in
@ -60,8 +58,3 @@ let levels_in_cycle ctxt c =
else acc else acc
in in
loop first [] loop first []
let init ctxt =
Storage.Current_level.init ctxt Raw_level_repr.(succ root)

View File

@ -7,11 +7,10 @@
(* *) (* *)
(**************************************************************************) (**************************************************************************)
val init: Storage.t -> Storage.t tzresult Lwt.t val current: Storage.t -> Level_repr.t
val previous: Storage.t -> Level_repr.t
val increment_current: Storage.t -> Storage.t tzresult Lwt.t val root: Storage.t -> Level_repr.t
val current: Storage.t -> Level_repr.t tzresult Lwt.t
val previous: Storage.t -> Level_repr.t tzresult Lwt.t
val from_raw: Storage.t -> ?offset:int32 -> Raw_level_repr.t -> Level_repr.t val from_raw: Storage.t -> ?offset:int32 -> Raw_level_repr.t -> Level_repr.t
val pred: Storage.t -> Level_repr.t -> Level_repr.t option val pred: Storage.t -> Level_repr.t -> Level_repr.t option

View File

@ -34,7 +34,7 @@ type validation_state =
op_count : int } op_count : int }
let current_context { ctxt } = let current_context { ctxt } =
Tezos_context.finalize ctxt return (Tezos_context.finalize ctxt).context
let precheck_block let precheck_block
~ancestor_context:_ ~ancestor_context:_
@ -47,9 +47,13 @@ let precheck_block
let begin_application let begin_application
~predecessor_context:ctxt ~predecessor_context:ctxt
~predecessor_timestamp:pred_timestamp ~predecessor_timestamp:pred_timestamp
~predecessor_fitness:pred_fitness
raw_block = raw_block =
Lwt.return (Tezos_context.Block.parse_header raw_block) >>=? fun header -> Lwt.return (Tezos_context.Block.parse_header raw_block) >>=? fun header ->
Tezos_context.init ctxt >>=? fun ctxt -> let level = header.shell.level in
let fitness = pred_fitness in
let timestamp = header.shell.timestamp in
Tezos_context.init ~level ~timestamp ~fitness ctxt >>=? fun ctxt ->
Apply.begin_application ctxt header pred_timestamp >>=? fun (ctxt, miner) -> Apply.begin_application ctxt header pred_timestamp >>=? fun (ctxt, miner) ->
let mode = Application (header, miner) in let mode = Application (header, miner) in
return { mode ; ctxt ; op_count = 0 } return { mode ; ctxt ; op_count = 0 }
@ -57,21 +61,25 @@ let begin_application
let begin_construction let begin_construction
~predecessor_context:ctxt ~predecessor_context:ctxt
~predecessor_timestamp:_ ~predecessor_timestamp:_
~predecessor_level:pred_level
~predecessor_fitness:pred_fitness
~predecessor:pred_block ~predecessor:pred_block
~timestamp = ~timestamp =
let mode = Construction { pred_block ; timestamp } in let mode = Construction { pred_block ; timestamp } in
Tezos_context.init ctxt >>=? fun ctxt -> let level = Int32.succ pred_level in
Apply.begin_construction ctxt >>=? fun ctxt -> let fitness = pred_fitness in
Tezos_context.init ~timestamp ~level ~fitness ctxt >>=? fun ctxt ->
let ctxt = Apply.begin_construction ctxt in
return { mode ; ctxt ; op_count = 0 } return { mode ; ctxt ; op_count = 0 }
let apply_operation ({ mode ; ctxt ; op_count } as data) operation = let apply_operation ({ mode ; ctxt ; op_count } as data) operation =
let pred_block, block_prio, miner_contract = let pred_block, block_prio, miner_contract =
match mode with match mode with
| Construction { pred_block } -> | Construction { pred_block } ->
pred_block, 0l, None pred_block, 0, None
| Application (block, delegate) -> | Application (block, delegate) ->
block.shell.predecessor, block.shell.predecessor,
block.proto.mining_slot.priority, block.proto.priority,
Some (Tezos_context.Contract.default_contract delegate) in Some (Tezos_context.Contract.default_contract delegate) in
Apply.apply_operation Apply.apply_operation
ctxt miner_contract pred_block block_prio operation ctxt miner_contract pred_block block_prio operation
@ -81,12 +89,20 @@ let apply_operation ({ mode ; ctxt ; op_count } as data) operation =
let finalize_block { mode ; ctxt ; op_count } = match mode with let finalize_block { mode ; ctxt ; op_count } = match mode with
| Construction _ -> | Construction _ ->
Tezos_context.finalize ctxt >>=? fun ctxt -> let ctxt = Tezos_context.finalize ctxt in
return ctxt return ctxt
| Application (block, miner) -> | Application (block, miner) ->
Apply.finalize_application Apply.finalize_application ctxt block miner >>=? fun ctxt ->
ctxt block miner op_count >>=? fun (commit_message, ctxt) -> let { level } : Tezos_context.Level.t =
Tezos_context.finalize ~commit_message ctxt >>=? fun ctxt -> Tezos_context. Level.current ctxt in
let priority = block.proto.priority in
let level = Tezos_context.Raw_level.to_int32 level in
let fitness = Tezos_context.Fitness.current ctxt in
let commit_message =
Format.asprintf
"lvl %ld, fit %Ld, prio %d, %d ops"
level fitness priority op_count in
let ctxt = Tezos_context.finalize ~commit_message ctxt in
return ctxt return ctxt
let compare_operations op1 op2 = let compare_operations op1 op2 =

View File

@ -14,7 +14,6 @@ open Misc
type error += Invalid_fitness_gap of int64 * int64 (* `Permanent *) type error += Invalid_fitness_gap of int64 * int64 (* `Permanent *)
type error += Invalid_endorsement_slot of int * int (* `Permanent *) type error += Invalid_endorsement_slot of int * int (* `Permanent *)
type error += Timestamp_too_early of Timestamp.t * Timestamp.t (* `Permanent *) type error += Timestamp_too_early of Timestamp.t * Timestamp.t (* `Permanent *)
type error += Wrong_level of Raw_level.t * Raw_level.t (* `Permanent *)
type error += Wrong_delegate of public_key_hash * public_key_hash (* `Permanent *) type error += Wrong_delegate of public_key_hash * public_key_hash (* `Permanent *)
type error += Cannot_pay_mining_bond (* `Permanent *) type error += Cannot_pay_mining_bond (* `Permanent *)
type error += Cannot_pay_endorsement_bond (* `Permanent *) type error += Cannot_pay_endorsement_bond (* `Permanent *)
@ -60,20 +59,6 @@ let () =
(req "provided" int16)) (req "provided" int16))
(function Invalid_endorsement_slot (m, g) -> Some (m, g) | _ -> None) (function Invalid_endorsement_slot (m, g) -> Some (m, g) | _ -> None)
(fun (m, g) -> Invalid_endorsement_slot (m, g)) ; (fun (m, g) -> Invalid_endorsement_slot (m, g)) ;
register_error_kind
`Permanent
~id:"mining.wrong_level"
~title:"Wrong level"
~description:"The block level is not the expected one"
~pp:(fun ppf (e, g) ->
Format.fprintf ppf
"The declared level %a is not %a"
Raw_level.pp g Raw_level.pp e)
Data_encoding.(obj2
(req "expected" Raw_level.encoding)
(req "provided" Raw_level.encoding))
(function Wrong_level (e, g) -> Some (e, g) | _ -> None)
(fun (e, g) -> Wrong_level (e, g)) ;
register_error_kind register_error_kind
`Permanent `Permanent
~id:"mining.wrong_delegate" ~id:"mining.wrong_delegate"
@ -110,6 +95,7 @@ let () =
(fun () -> Cannot_pay_endorsement_bond) (fun () -> Cannot_pay_endorsement_bond)
let minimal_time c priority pred_timestamp = let minimal_time c priority pred_timestamp =
let priority = Int32.of_int priority in
let rec cumsum_slot_durations acc durations p = let rec cumsum_slot_durations acc durations p =
if Compare.Int32.(<=) p 0l then if Compare.Int32.(<=) p 0l then
ok acc ok acc
@ -128,26 +114,19 @@ let minimal_time c priority pred_timestamp =
let check_timestamp c priority pred_timestamp = let check_timestamp c priority pred_timestamp =
minimal_time c priority pred_timestamp >>=? fun minimal_time -> minimal_time c priority pred_timestamp >>=? fun minimal_time ->
Tezos_context.Timestamp.get_current c >>= fun timestamp -> let timestamp = Tezos_context.Timestamp.current c in
fail_unless Timestamp.(minimal_time <= timestamp) fail_unless Timestamp.(minimal_time <= timestamp)
(Timestamp_too_early (minimal_time, timestamp)) (Timestamp_too_early (minimal_time, timestamp))
let check_mining_rights c let check_mining_rights c { Block.proto = { priority } }
{ Block.proto = { mining_slot = { level = raw_level ; priority } } }
pred_timestamp = pred_timestamp =
Level.current c >>=? fun current_level -> let level = Level.current c in
fail_unless
Raw_level.(raw_level = current_level.level)
(Wrong_level (current_level.Level.level, raw_level)) >>=? fun () ->
let level = Level.from_raw c raw_level in
Roll.mining_rights_owner c level ~priority >>=? fun delegate -> Roll.mining_rights_owner c level ~priority >>=? fun delegate ->
check_timestamp c priority pred_timestamp >>=? fun () -> check_timestamp c priority pred_timestamp >>=? fun () ->
return delegate return delegate
let pay_mining_bond c let pay_mining_bond c { Block.proto = { priority } } id =
{ Block.proto = { mining_slot = { priority} } } if Compare.Int.(priority >= Constants.first_free_mining_slot c)
id =
if Compare.Int32.(priority >= Constants.first_free_mining_slot c)
then return c then return c
else else
Contract.spend c (Contract.default_contract id) Constants.mining_bond_cost Contract.spend c (Contract.default_contract id) Constants.mining_bond_cost
@ -162,13 +141,13 @@ let pay_endorsement_bond c id =
let check_signing_rights c slot delegate = let check_signing_rights c slot delegate =
fail_unless Compare.Int.(0 <= slot && slot <= Constants.max_signing_slot c) fail_unless Compare.Int.(0 <= slot && slot <= Constants.max_signing_slot c)
(Invalid_endorsement_slot (Constants.max_signing_slot c, slot)) >>=? fun () -> (Invalid_endorsement_slot (Constants.max_signing_slot c, slot)) >>=? fun () ->
Level.current c >>=? fun level -> let level = Level.current c in
Roll.endorsement_rights_owner c level ~slot >>=? fun owning_delegate -> Roll.endorsement_rights_owner c level ~slot >>=? fun owning_delegate ->
fail_unless (Ed25519.Public_key_hash.equal owning_delegate delegate) fail_unless (Ed25519.Public_key_hash.equal owning_delegate delegate)
(Wrong_delegate (owning_delegate, delegate)) (Wrong_delegate (owning_delegate, delegate))
let paying_priorities c = let paying_priorities c =
0l ---> Constants.first_free_mining_slot c 0 --> Constants.first_free_mining_slot c
let bond_and_reward = let bond_and_reward =
match Tez.(Constants.mining_bond_cost +? Constants.mining_reward) with match Tez.(Constants.mining_bond_cost +? Constants.mining_reward) with
@ -176,25 +155,25 @@ let bond_and_reward =
| Error _ -> assert false | Error _ -> assert false
let base_mining_reward c ~priority = let base_mining_reward c ~priority =
if Compare.Int32.(priority < Constants.first_free_mining_slot c) if Compare.Int.(priority < Constants.first_free_mining_slot c)
then bond_and_reward then bond_and_reward
else Constants.mining_reward else Constants.mining_reward
type error += Incorect_priority type error += Incorect_priority
let endorsement_reward ~block_priority:prio = let endorsement_reward ~block_priority:prio =
if Compare.Int32.(prio >= 0l) if Compare.Int.(prio >= 0)
then then
Lwt.return Lwt.return
Tez.(Constants.endorsement_reward /? (Int64.(succ (of_int32 prio)))) Tez.(Constants.endorsement_reward /? (Int64.(succ (of_int prio))))
else fail Incorect_priority else fail Incorect_priority
let mining_priorities c level = let mining_priorities c level =
let rec f priority = let rec f priority =
Roll.mining_rights_owner c level ~priority >>=? fun delegate -> Roll.mining_rights_owner c level ~priority >>=? fun delegate ->
return (LCons (delegate, (fun () -> f (Int32.succ priority)))) return (LCons (delegate, (fun () -> f (succ priority))))
in in
f 0l f 0
let endorsement_priorities c level = let endorsement_priorities c level =
let rec f slot = let rec f slot =
@ -205,7 +184,7 @@ let endorsement_priorities c level =
let select_delegate delegate delegate_list max_priority = let select_delegate delegate delegate_list max_priority =
let rec loop acc l n = let rec loop acc l n =
if Compare.Int32.(n >= max_priority) if Compare.Int.(n >= max_priority)
then return (List.rev acc) then return (List.rev acc)
else else
let LCons (pkh, t) = l in let LCons (pkh, t) = l in
@ -214,9 +193,9 @@ let select_delegate delegate delegate_list max_priority =
then n :: acc then n :: acc
else acc in else acc in
t () >>=? fun t -> t () >>=? fun t ->
loop acc t (Int32.succ n) loop acc t (succ n)
in in
loop [] delegate_list 0l loop [] delegate_list 0
let first_mining_priorities let first_mining_priorities
ctxt ctxt
@ -227,8 +206,7 @@ let first_mining_priorities
let first_endorsement_slots let first_endorsement_slots
ctxt ctxt
?(max_priority = ?(max_priority = Constants.max_signing_slot ctxt)
Int32.of_int (Constants.max_signing_slot ctxt))
delegate level = delegate level =
endorsement_priorities ctxt level >>=? fun delegate_list -> endorsement_priorities ctxt level >>=? fun delegate_list ->
select_delegate delegate delegate_list max_priority select_delegate delegate delegate_list max_priority
@ -273,20 +251,21 @@ let max_fitness_gap ctxt =
Int64.add slots 1L Int64.add slots 1L
let check_fitness_gap ctxt (block : Block.header) = let check_fitness_gap ctxt (block : Block.header) =
Fitness.get ctxt >>=? fun current_fitness -> let current_fitness = Fitness.current ctxt in
Fitness.to_int64 block.shell.fitness >>=? fun announced_fitness -> Lwt.return (Fitness.to_int64 block.shell.fitness) >>=? fun announced_fitness ->
let gap = Int64.sub announced_fitness current_fitness in let gap = Int64.sub announced_fitness current_fitness in
if Compare.Int64.(gap <= 0L || max_fitness_gap ctxt < gap) then if Compare.Int64.(gap <= 0L || max_fitness_gap ctxt < gap) then
fail (Invalid_fitness_gap (max_fitness_gap ctxt, gap)) fail (Invalid_fitness_gap (max_fitness_gap ctxt, gap))
else else
return () return ()
let first_of_a_cycle l = let last_of_a_cycle ctxt l =
Compare.Int32.(l.Level.cycle_position = 0l) Compare.Int32.(Int32.succ l.Level.cycle_position =
Constants.cycle_length ctxt)
let dawn_of_a_new_cycle ctxt = let dawn_of_a_new_cycle ctxt =
Level.current ctxt >>=? fun level -> let level = Level.current ctxt in
if first_of_a_cycle level then if last_of_a_cycle ctxt level then
return (Some level.cycle) return (Some level.cycle)
else else
return None return None

View File

@ -14,15 +14,13 @@ open Misc
type error += Invalid_fitness_gap of int64 * int64 (* `Permanent *) type error += Invalid_fitness_gap of int64 * int64 (* `Permanent *)
type error += Invalid_endorsement_slot of int * int (* `Permanent *) type error += Invalid_endorsement_slot of int * int (* `Permanent *)
type error += Timestamp_too_early of Timestamp.t * Timestamp.t (* `Permanent *) type error += Timestamp_too_early of Timestamp.t * Timestamp.t (* `Permanent *)
type error += Wrong_level of Raw_level.t * Raw_level.t (* `Permanent *)
type error += Wrong_delegate of public_key_hash * public_key_hash (* `Permanent *) type error += Wrong_delegate of public_key_hash * public_key_hash (* `Permanent *)
type error += Cannot_pay_mining_bond (* `Permanent *) type error += Cannot_pay_mining_bond (* `Permanent *)
type error += Cannot_pay_endorsement_bond (* `Permanent *) type error += Cannot_pay_endorsement_bond (* `Permanent *)
val paying_priorities: context -> int32 list val paying_priorities: context -> int list
val minimal_time: val minimal_time: context -> int -> Time.t -> Time.t tzresult Lwt.t
context -> int32 -> Time.t -> Time.t tzresult Lwt.t
(** [minimal_time ctxt priority pred_block_time] returns the minimal (** [minimal_time ctxt priority pred_block_time] returns the minimal
time, given the predecessor block timestamp [pred_block_time], time, given the predecessor block timestamp [pred_block_time],
after which a miner with priority [priority] is allowed to after which a miner with priority [priority] is allowed to
@ -56,9 +54,9 @@ val check_signing_rights:
(** If this priority should have payed the bond it is the base mining (** If this priority should have payed the bond it is the base mining
reward and the bond, or just the base reward otherwise *) reward and the bond, or just the base reward otherwise *)
val base_mining_reward: context -> priority:int32 -> Tez.t val base_mining_reward: context -> priority:int -> Tez.t
val endorsement_reward: block_priority:int32 -> Tez.t tzresult Lwt.t val endorsement_reward: block_priority:int -> Tez.t tzresult Lwt.t
val mining_priorities: val mining_priorities:
context -> Level.t -> public_key_hash lazy_list context -> Level.t -> public_key_hash lazy_list
@ -70,10 +68,10 @@ val endorsement_priorities:
val first_mining_priorities: val first_mining_priorities:
context -> context ->
?max_priority:int32 -> ?max_priority:int ->
public_key_hash -> public_key_hash ->
Level.t -> Level.t ->
int32 list tzresult Lwt.t int list tzresult Lwt.t
(** [first_mining_priorities ctxt ?max_priority contract_hash level] (** [first_mining_priorities ctxt ?max_priority contract_hash level]
is a list of priorities of max [?max_priority] elements, where the is a list of priorities of max [?max_priority] elements, where the
delegate of [contract_hash] is allowed to mine for [level]. If delegate of [contract_hash] is allowed to mine for [level]. If
@ -82,9 +80,9 @@ val first_mining_priorities:
val first_endorsement_slots: val first_endorsement_slots:
context -> context ->
?max_priority:int32 -> ?max_priority:int ->
public_key_hash -> public_key_hash ->
Level.t -> int32 list tzresult Lwt.t Level.t -> int list tzresult Lwt.t
val check_signature: val check_signature:
context -> Block.header -> public_key_hash -> unit tzresult Lwt.t context -> Block.header -> public_key_hash -> unit tzresult Lwt.t

View File

@ -18,7 +18,7 @@ type error +=
| Unexpected_nonce | Unexpected_nonce
let get_unrevealed c level = let get_unrevealed c level =
Level_storage.current c >>=? fun cur_level -> let cur_level = Level_storage.current c in
let min_cycle = let min_cycle =
match Cycle_repr.pred cur_level.cycle with match Cycle_repr.pred cur_level.cycle with
| None -> Cycle_repr.root | None -> Cycle_repr.root
@ -40,7 +40,7 @@ let get_unrevealed c level =
(* return nonce_hash *) (* return nonce_hash *)
let record_hash c delegate_to_reward reward_amount nonce_hash = let record_hash c delegate_to_reward reward_amount nonce_hash =
Level_storage.current c >>=? fun level -> let level = Level_storage.current c in
Storage.Seed.Nonce.init c level Storage.Seed.Nonce.init c level
(Unrevealed { nonce_hash; delegate_to_reward ; reward_amount }) (Unrevealed { nonce_hash; delegate_to_reward ; reward_amount })
@ -65,6 +65,3 @@ let get c level = Storage.Seed.Nonce.get c level
let of_bytes = Seed_repr.make_nonce let of_bytes = Seed_repr.make_nonce
let hash = Seed_repr.hash let hash = Seed_repr.hash
let check_hash = Seed_repr.check_hash let check_hash = Seed_repr.check_hash
let init c =
Storage.Seed.Nonce.init c Level_repr.root (Revealed Seed_repr.initial_nonce_0)

View File

@ -41,6 +41,3 @@ val get: Storage.t -> Level_repr.t -> status tzresult Lwt.t
val of_bytes: MBytes.t -> nonce tzresult val of_bytes: MBytes.t -> nonce tzresult
val hash: nonce -> Nonce_hash.t val hash: nonce -> Nonce_hash.t
val check_hash: nonce -> Nonce_hash.t -> bool val check_hash: nonce -> Nonce_hash.t -> bool
val init:
Storage.t -> Storage.t tzresult Lwt.t

View File

@ -39,3 +39,9 @@ let of_int32_exn l =
if Compare.Int32.(l >= 0l) if Compare.Int32.(l >= 0l)
then l then l
else invalid_arg "Level_repr.of_int32" else invalid_arg "Level_repr.of_int32"
type error += Unexpected_level of Int32.t
let of_int32 l =
try Ok (of_int32_exn l)
with _ -> Error [Unexpected_level l]

View File

@ -16,6 +16,7 @@ include Compare.S with type t := raw_level
val to_int32: raw_level -> int32 val to_int32: raw_level -> int32
val of_int32_exn: int32 -> raw_level val of_int32_exn: int32 -> raw_level
val of_int32: int32 -> raw_level tzresult
val diff: raw_level -> raw_level -> int32 val diff: raw_level -> raw_level -> int32

View File

@ -56,7 +56,7 @@ let pay_rewards_for_cycle c cycle =
amount) amount)
let pay_due_rewards c = let pay_due_rewards c =
Storage.get_timestamp c >>= fun timestamp -> let timestamp = Storage.current_timestamp c in
let rec loop c cycle = let rec loop c cycle =
Storage.Rewards.Date.get_option c cycle >>=? function Storage.Rewards.Date.get_option c cycle >>=? function
| None -> | None ->

View File

@ -73,7 +73,7 @@ module Random = struct
let cycle = level.Level_repr.cycle in let cycle = level.Level_repr.cycle in
Seed_storage.for_cycle c cycle >>=? fun random_seed -> Seed_storage.for_cycle c cycle >>=? fun random_seed ->
let rd = level_random random_seed kind level in let rd = level_random random_seed kind level in
let sequence = Seed_repr.sequence rd offset in let sequence = Seed_repr.sequence rd (Int32.of_int offset) in
Storage.Roll.Last_for_cycle.get c cycle >>=? fun bound -> Storage.Roll.Last_for_cycle.get c cycle >>=? fun bound ->
let roll, _ = Roll_repr.random sequence bound in let roll, _ = Roll_repr.random sequence bound in
Storage.Roll.Owner_for_cycle.get c (cycle, roll) Storage.Roll.Owner_for_cycle.get c (cycle, roll)
@ -84,7 +84,7 @@ let mining_rights_owner c level ~priority =
Random.owner c "mining" level priority Random.owner c "mining" level priority
let endorsement_rights_owner c level ~slot = let endorsement_rights_owner c level ~slot =
Random.owner c "endorsement" level (Int32.of_int slot) Random.owner c "endorsement" level slot
module Contract = struct module Contract = struct

View File

@ -35,7 +35,7 @@ val clear_cycle :
Storage.t -> Cycle_repr.t -> Storage.t tzresult Lwt.t Storage.t -> Cycle_repr.t -> Storage.t tzresult Lwt.t
val mining_rights_owner : val mining_rights_owner :
Storage.t -> Level_repr.t -> priority:int32 -> Storage.t -> Level_repr.t -> priority:int ->
Ed25519.Public_key_hash.t tzresult Lwt.t Ed25519.Public_key_hash.t tzresult Lwt.t
val endorsement_rights_owner : val endorsement_rights_owner :

View File

@ -475,7 +475,7 @@ let rec interp
Contract.get_balance ctxt source >>=? fun balance -> Contract.get_balance ctxt source >>=? fun balance ->
logged_return (Item (balance, rest), qta - 1, ctxt) logged_return (Item (balance, rest), qta - 1, ctxt)
| Now, rest -> | Now, rest ->
Timestamp.get_current ctxt >>= fun now -> let now = Timestamp.current ctxt in
logged_return (Item (now, rest), qta - 1, ctxt) logged_return (Item (now, rest), qta - 1, ctxt)
| Check_signature, Item (key, Item ((signature, message), rest)) -> | Check_signature, Item (key, Item ((signature, message), rest)) ->
Public_key.get ctxt key >>=? fun key -> Public_key.get ctxt key >>=? fun key ->

View File

@ -45,7 +45,7 @@ let compute_for_cycle c cycle =
| c -> Lwt.return c | c -> Lwt.return c
let for_cycle c cycle = let for_cycle c cycle =
Level_storage.current c >>=? fun current_level -> let current_level = Level_storage.current c in
let current_cycle = current_level.cycle in let current_cycle = current_level.cycle in
let next_cycle = (Level_storage.succ c current_level).cycle in let next_cycle = (Level_storage.succ c current_level).cycle in
fail_unless fail_unless

View File

@ -73,7 +73,7 @@ module Constants = struct
~description: "First free mining slot" ~description: "First free mining slot"
~input: empty ~input: empty
~output: (wrap_tzerror @@ ~output: (wrap_tzerror @@
describe ~title: "first free mining slot" int32) describe ~title: "first free mining slot" uint16)
RPC.Path.(custom_root / "constants" / "first_free_mining_slot") RPC.Path.(custom_root / "constants" / "first_free_mining_slot")
let max_signing_slot custom_root = let max_signing_slot custom_root =
@ -81,7 +81,7 @@ module Constants = struct
~description: "Max signing slot" ~description: "Max signing slot"
~input: empty ~input: empty
~output: (wrap_tzerror @@ ~output: (wrap_tzerror @@
describe ~title: "max signing slot" int31) describe ~title: "max signing slot" uint16)
RPC.Path.(custom_root / "constants" / "max_signing_slot") RPC.Path.(custom_root / "constants" / "max_signing_slot")
let instructions_per_transaction custom_root = let instructions_per_transaction custom_root =
@ -563,7 +563,7 @@ module Helpers = struct
(req "fitness" Fitness.encoding) (req "fitness" Fitness.encoding)
(req "operations" Operation_list_list_hash.encoding) (req "operations" Operation_list_list_hash.encoding)
(req "level" Raw_level.encoding) (req "level" Raw_level.encoding)
(req "priority" int31) (req "priority" uint16)
(req "nonce_hash" Nonce_hash.encoding) (req "nonce_hash" Nonce_hash.encoding)
(req "proof_of_work_nonce" (req "proof_of_work_nonce"
(Fixed.bytes Tezos_context.Constants.proof_of_work_nonce_size))) (Fixed.bytes Tezos_context.Constants.proof_of_work_nonce_size)))

View File

@ -9,24 +9,27 @@
open Tezos_context open Tezos_context
let rpc_services = ref (RPC.empty : Context.t RPC.directory) let rpc_init { Updater.context ; level ; timestamp ; fitness } =
Tezos_context.init ~level ~timestamp ~fitness context
let rpc_services = ref (RPC.empty : Updater.rpc_context RPC.directory)
let register0 s f = let register0 s f =
rpc_services := rpc_services :=
RPC.register !rpc_services (s RPC.Path.root) RPC.register !rpc_services (s RPC.Path.root)
(fun ctxt () -> (fun ctxt () ->
( Tezos_context.init ctxt >>=? fun ctxt -> ( rpc_init ctxt >>=? fun ctxt ->
f ctxt ) >>= RPC.Answer.return) f ctxt ) >>= RPC.Answer.return)
let register1 s f = let register1 s f =
rpc_services := rpc_services :=
RPC.register !rpc_services (s RPC.Path.root) RPC.register !rpc_services (s RPC.Path.root)
(fun ctxt arg -> (fun ctxt arg ->
( Tezos_context.init ctxt >>=? fun ctxt -> ( rpc_init ctxt >>=? fun ctxt ->
f ctxt arg ) >>= RPC.Answer.return) f ctxt arg ) >>= RPC.Answer.return)
let register2 s f = let register2 s f =
rpc_services := rpc_services :=
RPC.register !rpc_services (s RPC.Path.root) RPC.register !rpc_services (s RPC.Path.root)
(fun (ctxt, arg1) arg2 -> (fun (ctxt, arg1) arg2 ->
( Tezos_context.init ctxt >>=? fun ctxt -> ( rpc_init ctxt >>=? fun ctxt ->
f ctxt arg1 arg2 ) >>= RPC.Answer.return) f ctxt arg1 arg2 ) >>= RPC.Answer.return)
let register1_noctxt s f = let register1_noctxt s f =
rpc_services := rpc_services :=
@ -92,7 +95,7 @@ let () =
type error += Unexpected_level_in_context type error += Unexpected_level_in_context
let level ctxt = let level ctxt =
Level.current ctxt >>=? fun level -> let level = Level.current ctxt in
match Level.pred ctxt level with match Level.pred ctxt level with
| None -> fail Unexpected_level_in_context | None -> fail Unexpected_level_in_context
| Some level -> return level | Some level -> return level
@ -100,7 +103,7 @@ let level ctxt =
let () = register0 Services.Context.level level let () = register0 Services.Context.level level
let next_level ctxt = let next_level ctxt =
Level.current ctxt return (Level.current ctxt)
let () = register0 Services.Context.next_level next_level let () = register0 Services.Context.next_level next_level
@ -143,7 +146,7 @@ let () =
rpc_services := rpc_services :=
RPC.register !rpc_services (s RPC.Path.root) RPC.register !rpc_services (s RPC.Path.root)
(fun (ctxt, contract) arg -> (fun (ctxt, contract) arg ->
( Tezos_context.init ctxt >>=? fun ctxt -> ( rpc_init ctxt >>=? fun ctxt ->
Contract.exists ctxt contract >>=? function Contract.exists ctxt contract >>=? function
| true -> f ctxt contract arg | true -> f ctxt contract arg
| false -> raise Not_found ) >>= RPC.Answer.return) in | false -> raise Not_found ) >>= RPC.Answer.return) in
@ -171,13 +174,13 @@ let () =
(*-- Helpers -----------------------------------------------------------------*) (*-- Helpers -----------------------------------------------------------------*)
let minimal_timestamp ctxt prio = let minimal_timestamp ctxt prio =
let prio = match prio with None -> 0l | Some p -> Int32.of_int p in let prio = match prio with None -> 0 | Some p -> p in
Mining.minimal_time ctxt prio Mining.minimal_time ctxt prio
let () = register1 let () = register1
Services.Helpers.minimal_timestamp Services.Helpers.minimal_timestamp
(fun ctxt slot -> (fun ctxt slot ->
Tezos_context.Timestamp.get_current ctxt >>= fun timestamp -> let timestamp = Tezos_context.Timestamp.current ctxt in
minimal_timestamp ctxt slot timestamp) minimal_timestamp ctxt slot timestamp)
let () = let () =
@ -190,10 +193,10 @@ let () =
| None -> Error_monad.fail Operation.Cannot_parse_operation | None -> Error_monad.fail Operation.Cannot_parse_operation
| Some (shell, contents) -> | Some (shell, contents) ->
let operation = { hash ; shell ; contents ; signature } in let operation = { hash ; shell ; contents ; signature } in
Tezos_context.Level.current ctxt >>=? fun level -> let level = Tezos_context.Level.current ctxt in
Mining.mining_priorities ctxt level >>=? fun (Misc.LCons (miner_pkh, _)) -> Mining.mining_priorities ctxt level >>=? fun (Misc.LCons (miner_pkh, _)) ->
let miner_contract = Contract.default_contract miner_pkh in let miner_contract = Contract.default_contract miner_pkh in
let block_prio = 0l in let block_prio = 0 in
Apply.apply_operation Apply.apply_operation
ctxt (Some miner_contract) pred_block block_prio operation ctxt (Some miner_contract) pred_block block_prio operation
>>=? function >>=? function
@ -278,11 +281,11 @@ let () = register2 Services.Helpers.levels levels
let default_max_mining_priority ctxt arg = let default_max_mining_priority ctxt arg =
let default = Constants.first_free_mining_slot ctxt in let default = Constants.first_free_mining_slot ctxt in
match arg with match arg with
| None -> Int32.mul 2l default | None -> 2 * default
| Some m -> Int32.of_int m | Some m -> m
let mining_rights ctxt level max = let mining_rights ctxt level max =
let max = Int32.to_int (default_max_mining_priority ctxt max) in let max = default_max_mining_priority ctxt max in
Mining.mining_priorities ctxt level >>=? fun contract_list -> Mining.mining_priorities ctxt level >>=? fun contract_list ->
let rec loop l n = let rec loop l n =
match n with match n with
@ -299,15 +302,14 @@ let mining_rights ctxt level max =
let () = let () =
register1 Services.Helpers.Rights.mining_rights register1 Services.Helpers.Rights.mining_rights
(fun ctxt max -> (fun ctxt max ->
Level.current ctxt >>=? fun level -> let level = Level.current ctxt in
mining_rights ctxt level max >>=? fun (raw_level, slots) -> mining_rights ctxt level max >>=? fun (raw_level, slots) ->
begin begin
Lwt_list.filter_map_p (fun x -> x) @@ Lwt_list.filter_map_p (fun x -> x) @@
List.mapi List.mapi
(fun prio c -> (fun prio c ->
Tezos_context.Timestamp.get_current ctxt >>= fun timestamp -> let timestamp = Timestamp.current ctxt in
Mining.minimal_time Mining.minimal_time ctxt prio timestamp >>= function
ctxt (Int32.of_int prio) timestamp >>= function
| Error _ -> Lwt.return None | Error _ -> Lwt.return None
| Ok minimal_timestamp -> Lwt.return (Some (c, minimal_timestamp))) | Ok minimal_timestamp -> Lwt.return (Some (c, minimal_timestamp)))
slots slots
@ -323,7 +325,7 @@ let () =
let mining_rights_for_delegate let mining_rights_for_delegate
ctxt contract (max_priority, min_level, max_level) = ctxt contract (max_priority, min_level, max_level) =
let max_priority = default_max_mining_priority ctxt max_priority in let max_priority = default_max_mining_priority ctxt max_priority in
Level.current ctxt >>=? fun current_level -> let current_level = Level.current ctxt in
let max_level = let max_level =
match max_level with match max_level with
| None -> | None ->
@ -343,9 +345,9 @@ let mining_rights_for_delegate
let raw_level = level.level in let raw_level = level.level in
Error_monad.map_s Error_monad.map_s
(fun priority -> (fun priority ->
Tezos_context.Timestamp.get_current ctxt >>= fun timestamp -> let timestamp = Timestamp.current ctxt in
Mining.minimal_time ctxt priority timestamp >>=? fun time -> Mining.minimal_time ctxt priority timestamp >>=? fun time ->
return (raw_level, Int32.to_int priority, time)) return (raw_level, priority, time))
priorities >>=? fun priorities -> priorities >>=? fun priorities ->
return (priorities @ t) return (priorities @ t)
in in
@ -379,7 +381,7 @@ let endorsement_rights ctxt level max =
let () = let () =
register1 Services.Helpers.Rights.endorsement_rights register1 Services.Helpers.Rights.endorsement_rights
(fun ctxt max -> (fun ctxt max ->
Level.current ctxt >>=? fun level -> let level = Level.current ctxt in
endorsement_rights ctxt (Level.succ ctxt level) max) ; endorsement_rights ctxt (Level.succ ctxt level) max) ;
register2 Services.Helpers.Rights.endorsement_rights_for_level register2 Services.Helpers.Rights.endorsement_rights_for_level
(fun ctxt raw_level max -> (fun ctxt raw_level max ->
@ -388,10 +390,8 @@ let () =
let endorsement_rights_for_delegate let endorsement_rights_for_delegate
ctxt contract (max_priority, min_level, max_level) = ctxt contract (max_priority, min_level, max_level) =
let max_priority = let current_level = Level.current ctxt in
Int32.of_int @@ let max_priority = default_max_endorsement_priority ctxt max_priority in
default_max_endorsement_priority ctxt max_priority in
Level.current ctxt >>=? fun current_level ->
let max_level = let max_level =
match max_level with match max_level with
| None -> | None ->
@ -409,10 +409,7 @@ let endorsement_rights_for_delegate
Mining.first_endorsement_slots Mining.first_endorsement_slots
ctxt ~max_priority contract level >>=? fun slots -> ctxt ~max_priority contract level >>=? fun slots ->
let raw_level = level.level in let raw_level = level.level in
let slots = let slots = List.rev_map (fun slot -> (raw_level, slot)) slots in
List.rev_map
(fun slot -> (raw_level, Int32.to_int slot))
slots in
return (List.rev_append slots t) return (List.rev_append slots t)
in in
loop min_level loop min_level
@ -437,13 +434,13 @@ let forge_operations _ctxt (shell, proto) =
let () = register1 Services.Helpers.Forge.operations forge_operations let () = register1 Services.Helpers.Forge.operations forge_operations
let forge_block _ctxt let forge_block _ctxt
(net_id, predecessor, timestamp, fitness, operations, (net_id, predecessor, timestamp, fitness, operations_hash,
raw_level, priority, seed_nonce_hash, proof_of_work_nonce) : MBytes.t tzresult Lwt.t = level, priority, seed_nonce_hash, proof_of_work_nonce) : MBytes.t tzresult Lwt.t =
let priority = Int32.of_int priority in let level = Raw_level.to_int32 level in
let mining_slot = { Block.level = raw_level ; priority } in
return (Block.forge_header return (Block.forge_header
{ net_id ; predecessor ; timestamp ; fitness ; operations } { net_id ; level ; predecessor ;
{ mining_slot ; seed_nonce_hash ; proof_of_work_nonce }) timestamp ; fitness ; operations_hash }
{ priority ; seed_nonce_hash ; proof_of_work_nonce })
let () = register1 Services.Helpers.Forge.block forge_block let () = register1 Services.Helpers.Forge.block forge_block

View File

@ -10,21 +10,54 @@
open Tezos_hash open Tezos_hash
open Storage_functors open Storage_functors
(* This key should always be populated for every version of the
protocol. It's absence meaning that the context is empty. *)
let version_key = ["version"]
let version_value = "alpha"
type error += Incompatiple_protocol_version
let is_first_block ctxt =
Context.get ctxt version_key >>= function
| None ->
return true
| Some bytes ->
let s = MBytes.to_string bytes in
if Compare.String.(s = version_value) then
return false
else if Compare.String.(s = "genesis") then
return true
else
fail Incompatiple_protocol_version
let version = "v1" let version = "v1"
let first_level_key = [ version ; "first_level" ]
let sandboxed_key = [ version ; "sandboxed" ] let sandboxed_key = [ version ; "sandboxed" ]
let prevalidation_key = [ version ; "prevalidation" ]
type t = Storage_functors.context type t = Storage_functors.context
type error += Invalid_sandbox_parameter type error += Invalid_sandbox_parameter
let get_fitness (c, _) = Context.get_fitness c let current_level { level } = level
let set_fitness (c, csts) v = let current_timestamp { timestamp } = timestamp
Context.set_fitness c v >>= fun c -> Lwt.return (c, csts) let current_fitness { fitness } = fitness
let set_current_fitness c fitness = { c with fitness }
let get_timestamp (c, _) = Context.get_timestamp c let get_first_level ctxt =
let set_commit_message (c, csts) msg = Context.get ctxt first_level_key >>= function
Context.set_commit_message c msg >>= fun c -> Lwt.return (c, csts) | None -> failwith "Invalid context"
| Some bytes ->
match
Data_encoding.Binary.of_bytes Raw_level_repr.encoding bytes
with
| None -> failwith "Invalid context"
| Some level -> return level
let set_first_level ctxt level =
let bytes =
Data_encoding.Binary.to_bytes Raw_level_repr.encoding level in
Context.set ctxt first_level_key bytes >>= fun ctxt ->
return ctxt
let get_sandboxed c = let get_sandboxed c =
Context.get c sandboxed_key >>= function Context.get c sandboxed_key >>= function
@ -38,29 +71,41 @@ let set_sandboxed c json =
Context.set c sandboxed_key Context.set c sandboxed_key
(Data_encoding.Binary.to_bytes Data_encoding.json json) (Data_encoding.Binary.to_bytes Data_encoding.json json)
let prepare (c : Context.t) : t tzresult Lwt.t = let may_tag_first_block ctxt level =
get_sandboxed c >>=? fun sandbox -> is_first_block ctxt >>=? function
| false ->
get_first_level ctxt >>=? fun level ->
return (ctxt, false, level)
| true ->
Context.set ctxt version_key
(MBytes.of_string version_value) >>= fun ctxt ->
set_first_level ctxt level >>=? fun ctxt ->
return (ctxt, true, level)
let prepare ~level ~timestamp ~fitness ctxt =
Lwt.return (Raw_level_repr.of_int32 level ) >>=? fun level ->
Lwt.return (Fitness_repr.to_int64 fitness) >>=? fun fitness ->
may_tag_first_block ctxt level >>=? fun (ctxt, first_block, first_level) ->
get_sandboxed ctxt >>=? fun sandbox ->
Constants_repr.read sandbox >>=? function constants -> Constants_repr.read sandbox >>=? function constants ->
return (c, constants) let level =
let recover (c, _ : t) : Context.t = c Level_repr.from_raw
~first_level
~cycle_length:constants.Constants_repr.cycle_length
~voting_period_length:constants.Constants_repr.voting_period_length
level in
return ({ context = ctxt ; constants ; level ;
timestamp ; fitness ; first_level},
first_block)
let recover { context } : Context.t = context
let get_prevalidation (c, _ : t) = let first_level { first_level } = first_level
Context.get c prevalidation_key >>= function let constants { constants } = constants
| None -> Lwt.return false
| Some _ -> Lwt.return true
let set_prevalidation (c, constants : t) =
Context.set c prevalidation_key (MBytes.of_string "prevalidation") >>= fun c ->
Lwt.return (c, constants)
let constants : t -> _ = snd
module Key = struct module Key = struct
let store_root tail = version :: "store" :: tail let store_root tail = version :: "store" :: tail
let current_level = store_root ["level"]
let global_counter = store_root ["global_counter"] let global_counter = store_root ["global_counter"]
let next_cycle_to_be_rewarded = store_root ["next_cycle_to_be_rewarded"] let next_cycle_to_be_rewarded = store_root ["next_cycle_to_be_rewarded"]
@ -132,16 +177,6 @@ module Key = struct
end end
(** Global *)
module Current_level =
Make_single_data_storage(struct
type value = Raw_level_repr.t
let name = "level"
let key = Key.current_level
let encoding = Raw_level_repr.encoding
end)
(** Rolls *) (** Rolls *)
module Roll = struct module Roll = struct
@ -510,13 +545,11 @@ module Rewards = struct
end end
let activate (c, constants) h = let activate ({ context = c } as s) h =
Updater.activate c h >>= fun c -> Lwt.return (c, constants) Updater.activate c h >>= fun c -> Lwt.return { s with context = c }
let fork_test_network (c, constants) = let fork_test_network ({ context = c } as s) protocol expiration =
Updater.fork_test_network c >>= fun c -> Lwt.return (c, constants) Updater.fork_test_network c ~protocol ~expiration >>= fun c ->
let set_test_protocol (c, constants) h = Lwt.return { s with context = c }
Updater.set_test_protocol c h >>= fun c -> Lwt.return (c, constants)
(** Resolver *) (** Resolver *)

View File

@ -24,8 +24,17 @@
(** Abstract view of the database *) (** Abstract view of the database *)
type t type t
(** Rerieves the state of the database and gives its abstract view *) (** Is first block validated with this version of the protocol ? *)
val prepare : Context.t -> t tzresult Lwt.t val is_first_block: Context.t -> bool tzresult Lwt.t
(** Retrieves the state of the database and gives its abstract view.
It also returns wether this is the first block validated
with this version of the protocol. *)
val prepare :
level: Int32.t ->
timestamp: Time.t ->
fitness: Fitness.fitness ->
Context.t -> (t * bool) tzresult Lwt.t
(** Returns the state of the database resulting of operations on its (** Returns the state of the database resulting of operations on its
abstract view *) abstract view *)
@ -34,27 +43,19 @@ val recover : t -> Context.t
val get_sandboxed : Context.t -> Data_encoding.json option tzresult Lwt.t val get_sandboxed : Context.t -> Data_encoding.json option tzresult Lwt.t
val set_sandboxed : Context.t -> Data_encoding.json -> Context.t Lwt.t val set_sandboxed : Context.t -> Data_encoding.json -> Context.t Lwt.t
val get_fitness : t -> Fitness.fitness Lwt.t val current_level : t -> Level_repr.t
val set_fitness : t -> Fitness.fitness -> t Lwt.t val current_timestamp : t -> Time.t
val get_timestamp: t -> Time.t Lwt.t val current_fitness : t -> Int64.t
val set_current_fitness : t -> Int64.t -> t
val set_commit_message: t -> string -> t Lwt.t
val get_prevalidation : t -> bool Lwt.t
val set_prevalidation : t -> t Lwt.t
val constants : t -> Constants_repr.constants val constants : t -> Constants_repr.constants
val first_level : t -> Raw_level_repr.t
(** {1 Entity Accessors} *****************************************************) (** {1 Entity Accessors} *****************************************************)
open Storage_sigs open Storage_sigs
(** The level of the current block *)
module Current_level : Single_data_storage
with type value = Raw_level_repr.t
and type context := t
module Roll : sig module Roll : sig
(** Storage from this submodule must only be accessed through the (** Storage from this submodule must only be accessed through the
@ -274,5 +275,4 @@ module Rewards : sig
end end
val activate: t -> Protocol_hash.t -> t Lwt.t val activate: t -> Protocol_hash.t -> t Lwt.t
val set_test_protocol: t -> Protocol_hash.t -> t Lwt.t val fork_test_network: t -> Protocol_hash.t -> Time.t -> t Lwt.t
val fork_test_network: t -> t Lwt.t

View File

@ -11,7 +11,14 @@
open Misc open Misc
type context = Context.t * Constants_repr.constants type context = {
context: Context.t ;
constants: Constants_repr.constants ;
first_level: Raw_level_repr.t ;
level: Level_repr.t ;
timestamp: Time.t ;
fitness: Int64.t ;
}
(*-- Errors ------------------------------------------------------------------*) (*-- Errors ------------------------------------------------------------------*)
@ -52,7 +59,7 @@ module Make_raw_data_storage (P : Raw_data_description) = struct
let key_to_string l = String.concat "/" (key l) let key_to_string l = String.concat "/" (key l)
let get (c, _) k = let get { context = c } k =
Context.get c (key k) >>= function Context.get c (key k) >>= function
| None -> | None ->
let msg = let msg =
@ -61,16 +68,16 @@ module Make_raw_data_storage (P : Raw_data_description) = struct
| Some bytes -> | Some bytes ->
Lwt.return (P.of_bytes bytes) Lwt.return (P.of_bytes bytes)
let mem (c, _) k = Context.mem c (key k) let mem { context = c } k = Context.mem c (key k)
let get_option (c, _) k = let get_option { context = c } k =
Context.get c (key k) >>= function Context.get c (key k) >>= function
| None -> return None | None -> return None
| Some bytes -> | Some bytes ->
Lwt.return (P.of_bytes bytes >|? fun v -> Some v) Lwt.return (P.of_bytes bytes >|? fun v -> Some v)
(* Verify that the key is present before modifying *) (* Verify that the key is present before modifying *)
let set (c, x) k v = let set ({ context = c } as s) k v =
let key = key k in let key = key k in
Context.get c key >>= function Context.get c key >>= function
| None -> | None ->
@ -80,13 +87,13 @@ module Make_raw_data_storage (P : Raw_data_description) = struct
| Some old -> | Some old ->
let bytes = P.to_bytes v in let bytes = P.to_bytes v in
if MBytes.(old = bytes) then if MBytes.(old = bytes) then
return (c, x) return { s with context = c }
else else
Context.set c key (P.to_bytes v) >>= fun c -> Context.set c key (P.to_bytes v) >>= fun c ->
return (c, x) return { s with context = c }
(* Verify that the key is not present before inserting *) (* Verify that the key is not present before inserting *)
let init (c, x) k v = let init ({ context = c } as s) k v =
let key = key k in let key = key k in
Context.get c key >>= Context.get c key >>=
function function
@ -96,27 +103,29 @@ module Make_raw_data_storage (P : Raw_data_description) = struct
fail (Storage_error msg) fail (Storage_error msg)
| None -> | None ->
Context.set c key (P.to_bytes v) >>= fun c -> Context.set c key (P.to_bytes v) >>= fun c ->
return (c, x) return { s with context = c }
(* Does not verify that the key is present or not *) (* Does not verify that the key is present or not *)
let init_set (c, x) k v = let init_set ({ context = c } as s) k v =
Context.set c (key k) (P.to_bytes v) >>= fun c -> return (c, x) Context.set c (key k) (P.to_bytes v) >>= fun c ->
return { s with context = c }
(* Verify that the key is present before deleting *) (* Verify that the key is present before deleting *)
let delete (c, x) k = let delete ({ context = c } as s) k =
let key = key k in let key = key k in
Context.get c key >>= function Context.get c key >>= function
| Some _ -> | Some _ ->
Context.del c key >>= fun c -> Context.del c key >>= fun c ->
return (c, x) return { s with context = c }
| None -> | None ->
let msg = let msg =
"cannot delete undefined " ^ P.name ^ " key " ^ key_to_string k in "cannot delete undefined " ^ P.name ^ " key " ^ key_to_string k in
fail (Storage_error msg) fail (Storage_error msg)
(* Do not verify before deleting *) (* Do not verify before deleting *)
let remove (c, x) k = let remove ({ context = c } as s) k =
Context.del c (key k) >>= fun c -> Lwt.return (c, x) Context.del c (key k) >>= fun c ->
Lwt.return { s with context = c }
end end
@ -229,28 +238,34 @@ module Make_data_set_storage (P : Single_data_description) = struct
error (Storage_error msg) error (Storage_error msg)
| Some v -> Ok v | Some v -> Ok v
let add (c, x) v = let add ({ context = c } as s) v =
let hash, data = serial v in let hash, data = serial v in
HashTbl.mem c hash >>= function HashTbl.mem c hash >>= function
| true -> return (c, x) | true ->
| false -> HashTbl.set c hash data >>= fun c -> return (c, x) return { s with context = c }
| false ->
HashTbl.set c hash data >>= fun c ->
return { s with context = c }
let del (c, x) v = let del ({ context = c } as s) v =
let hash, _ = serial v in let hash, _ = serial v in
HashTbl.mem c hash >>= function HashTbl.mem c hash >>= function
| false -> return (c, x) | false ->
| true -> HashTbl.del c hash >>= fun c -> return (c, x) return { s with context = c }
| true ->
HashTbl.del c hash >>= fun c ->
return { s with context = c }
let mem (c, _) v = let mem { context = c } v =
let hash, _ = serial v in let hash, _ = serial v in
HashTbl.mem c hash >>= fun v -> HashTbl.mem c hash >>= fun v ->
return v return v
let elements (c, _) = let elements { context = c } =
HashTbl.bindings c >>= fun elts -> HashTbl.bindings c >>= fun elts ->
map_s (fun (_, data) -> Lwt.return (unserial data)) elts map_s (fun (_, data) -> Lwt.return (unserial data)) elts
let fold (c, _) init ~f = let fold { context = c } init ~f =
HashTbl.fold c (ok init) HashTbl.fold c (ok init)
~f:(fun _ data acc -> ~f:(fun _ data acc ->
match acc with match acc with
@ -262,9 +277,9 @@ module Make_data_set_storage (P : Single_data_description) = struct
f data acc >>= fun acc -> f data acc >>= fun acc ->
return acc) return acc)
let clear (c, x) = let clear ({ context = c } as s) =
HashTbl.fold c c ~f:(fun hash _ c -> HashTbl.del c hash) >>= fun c -> HashTbl.fold c c ~f:(fun hash _ c -> HashTbl.del c hash) >>= fun c ->
return (c, x) return { s with context = c }
end end
@ -284,7 +299,7 @@ module Raw_make_iterable_data_storage
let key_to_string k = String.concat "/" (K.to_path k) let key_to_string k = String.concat "/" (K.to_path k)
let get (c, _) k = let get { context = c } k =
HashTbl.get c k >>= function HashTbl.get c k >>= function
| None -> | None ->
let msg = let msg =
@ -293,15 +308,15 @@ module Raw_make_iterable_data_storage
| Some v -> | Some v ->
return v return v
let mem (c, _) k = HashTbl.mem c k let mem { context = c } k = HashTbl.mem c k
let get_option (c, _) k = let get_option { context = c } k =
HashTbl.get c k >>= function HashTbl.get c k >>= function
| None -> return None | None -> return None
| Some v -> return (Some v) | Some v -> return (Some v)
(* Verify that the key is present before modifying *) (* Verify that the key is present before modifying *)
let set (c, x) k v = let set ({ context = c } as s) k v =
HashTbl.get c k >>= function HashTbl.get c k >>= function
| None -> | None ->
let msg = let msg =
@ -309,10 +324,10 @@ module Raw_make_iterable_data_storage
fail (Storage_error msg) fail (Storage_error msg)
| Some _ -> | Some _ ->
HashTbl.set c k v >>= fun c -> HashTbl.set c k v >>= fun c ->
return (c, x) return { s with context = c }
(* Verify that the key is not present before inserting *) (* Verify that the key is not present before inserting *)
let init (c, x) k v = let init ({ context = c } as s) k v =
HashTbl.get c k >>= HashTbl.get c k >>=
function function
| Some _ -> | Some _ ->
@ -321,29 +336,35 @@ module Raw_make_iterable_data_storage
fail (Storage_error msg) fail (Storage_error msg)
| None -> | None ->
HashTbl.set c k v >>= fun c -> HashTbl.set c k v >>= fun c ->
return (c, x) return { s with context = c }
(* Does not verify that the key is present or not *) (* Does not verify that the key is present or not *)
let init_set (c, x) k v = HashTbl.set c k v >>= fun c -> return (c, x) let init_set ({ context = c } as s) k v =
HashTbl.set c k v >>= fun c ->
return { s with context = c }
(* Verify that the key is present before deleting *) (* Verify that the key is present before deleting *)
let delete (c, x) k = let delete ({ context = c } as s) k =
HashTbl.get c k >>= function HashTbl.get c k >>= function
| Some _ -> | Some _ ->
HashTbl.del c k >>= fun c -> HashTbl.del c k >>= fun c ->
return (c, x) return { s with context = c }
| None -> | None ->
let msg = let msg =
"cannot delete undefined " ^ P.name ^ " key " ^ key_to_string k in "cannot delete undefined " ^ P.name ^ " key " ^ key_to_string k in
fail (Storage_error msg) fail (Storage_error msg)
(* Do not verify before deleting *) (* Do not verify before deleting *)
let remove (c, x) k = let remove ({ context = c } as s) k =
HashTbl.del c k >>= fun c -> Lwt.return (c, x) HashTbl.del c k >>= fun c ->
Lwt.return { s with context = c }
let clear (c, x) = HashTbl.clear c >>= fun c -> Lwt.return (c, x) let clear ({ context = c } as s) =
let fold (c, _) x ~f = HashTbl.fold c x ~f:(fun k v acc -> f k v acc) HashTbl.clear c >>= fun c ->
let iter (c, _) ~f = HashTbl.fold c () ~f:(fun k v () -> f k v) Lwt.return { s with context = c }
let fold { context = c } x ~f = HashTbl.fold c x ~f:(fun k v acc -> f k v acc)
let iter { context = c } ~f = HashTbl.fold c () ~f:(fun k v () -> f k v)
end end

View File

@ -14,7 +14,14 @@
indexed data and homgeneous data set). *) indexed data and homgeneous data set). *)
type context = Context.t * Constants_repr.constants type context = {
context: Context.t ;
constants: Constants_repr.constants ;
first_level: Raw_level_repr.t ;
level: Level_repr.t ;
timestamp: Time.t ;
fitness: Int64.t ;
}
open Storage_sigs open Storage_sigs

View File

@ -22,7 +22,7 @@ module Period = Period_repr
module Timestamp = struct module Timestamp = struct
include Time_repr include Time_repr
let get_current = Storage.get_timestamp let current = Storage.current_timestamp
end end
include Operation_repr include Operation_repr
@ -110,18 +110,12 @@ end
let init = Init_storage.may_initialize let init = Init_storage.may_initialize
let finalize ?commit_message c = let finalize ?commit_message:message c =
match commit_message with let fitness = Fitness.from_int64 (Fitness.current c) in
| None -> let context = Storage.recover c in
return (Storage.recover c) { Updater.context ; fitness ; message }
| Some msg ->
Storage.set_commit_message c msg >>= fun c ->
return (Storage.recover c)
let configure_sandbox = Init_storage.configure_sandbox let configure_sandbox = Init_storage.configure_sandbox
let get_prevalidation = Storage.get_prevalidation
let set_prevalidation = Storage.set_prevalidation
let activate = Storage.activate let activate = Storage.activate
let fork_test_network = Storage.fork_test_network let fork_test_network = Storage.fork_test_network
let set_test_protocol = Storage.set_test_protocol

View File

@ -75,10 +75,7 @@ module Timestamp : sig
val of_seconds: string -> time option val of_seconds: string -> time option
val to_seconds: time -> string val to_seconds: time -> string
val get_current: context -> Time.t Lwt.t val current: context -> Time.t
(** [get_current ctxt] returns the current timestamp of [ctxt]. When
[ctxt] is the context of a block, the block timestamp is used,
otherwise a timestamp is inferred otherwise. *)
end end
@ -175,7 +172,7 @@ module Constants : sig
val voting_period_length: context -> int32 val voting_period_length: context -> int32
val time_before_reward: context -> Period.t val time_before_reward: context -> Period.t
val slot_durations: context -> Period.t list val slot_durations: context -> Period.t list
val first_free_mining_slot: context -> int32 val first_free_mining_slot: context -> int
val max_signing_slot: context -> int val max_signing_slot: context -> int
val instructions_per_transaction: context -> int val instructions_per_transaction: context -> int
val proof_of_work_threshold: context -> int64 val proof_of_work_threshold: context -> int64
@ -222,6 +219,7 @@ module Level : sig
type t = private { type t = private {
level: Raw_level.t ; level: Raw_level.t ;
level_position: int32 ;
cycle: Cycle.t ; cycle: Cycle.t ;
cycle_position: int32 ; cycle_position: int32 ;
voting_period: Voting_period.t ; voting_period: Voting_period.t ;
@ -231,7 +229,7 @@ module Level : sig
val pp_full: Format.formatter -> t -> unit val pp_full: Format.formatter -> t -> unit
type level = t type level = t
val root: level val root: context -> level
val succ: context -> level -> level val succ: context -> level -> level
val pred: context -> level -> level option val pred: context -> level -> level option
@ -240,8 +238,7 @@ module Level : sig
val diff: level -> level -> int32 val diff: level -> level -> int32
val current: context -> level tzresult Lwt.t val current: context -> level
val increment_current: context -> context tzresult Lwt.t
val last_level_in_cycle: context -> Cycle.t -> level val last_level_in_cycle: context -> Cycle.t -> level
val levels_in_cycle: context -> Cycle.t -> level list val levels_in_cycle: context -> Cycle.t -> level list
@ -253,10 +250,11 @@ module Fitness : sig
include (module type of Fitness) include (module type of Fitness)
type t = fitness type t = fitness
val increase: context -> context tzresult Lwt.t val increase: context -> context
val get: context -> int64 tzresult Lwt.t val current: context -> int64
val to_int64: fitness -> int64 tzresult Lwt.t
val to_int64: fitness -> int64 tzresult
end end
@ -525,18 +523,11 @@ module Block : sig
} }
and proto_header = { and proto_header = {
mining_slot: mining_slot ; priority: int ;
seed_nonce_hash: Nonce_hash.t ; seed_nonce_hash: Nonce_hash.t ;
proof_of_work_nonce: MBytes.t ; proof_of_work_nonce: MBytes.t ;
} }
and mining_slot = {
level: Raw_level.t ;
priority: Int32.t ;
}
val mining_slot_encoding: mining_slot Data_encoding.encoding
val max_header_length: int val max_header_length: int
val parse_header: Updater.raw_block -> header tzresult val parse_header: Updater.raw_block -> header tzresult
@ -558,7 +549,7 @@ module Roll : sig
val clear_cycle: context -> Cycle.t -> context tzresult Lwt.t val clear_cycle: context -> Cycle.t -> context tzresult Lwt.t
val mining_rights_owner: val mining_rights_owner:
context -> Level.t -> priority:int32 -> public_key_hash tzresult Lwt.t context -> Level.t -> priority:int -> public_key_hash tzresult Lwt.t
val endorsement_rights_owner: val endorsement_rights_owner:
context -> Level.t -> slot:int -> public_key_hash tzresult Lwt.t context -> Level.t -> slot:int -> public_key_hash tzresult Lwt.t
@ -580,15 +571,16 @@ module Reward : sig
end end
val init: Context.t -> context tzresult Lwt.t val init:
val finalize: ?commit_message:string -> context -> Context.t tzresult Lwt.t Context.t ->
level:Int32.t ->
timestamp:Time.t ->
fitness:Fitness.t ->
context tzresult Lwt.t
val finalize: ?commit_message:string -> context -> Updater.validation_result
val configure_sandbox: val configure_sandbox:
Context.t -> Data_encoding.json option -> Context.t tzresult Lwt.t Context.t -> Data_encoding.json option -> Context.t tzresult Lwt.t
val get_prevalidation: context -> bool Lwt.t
val set_prevalidation: context -> context Lwt.t
val activate: context -> Protocol_hash.t -> context Lwt.t val activate: context -> Protocol_hash.t -> context Lwt.t
val set_test_protocol: context -> Protocol_hash.t -> context Lwt.t val fork_test_network: context -> Protocol_hash.t -> Time.t -> context Lwt.t
val fork_test_network: context -> context Lwt.t

View File

@ -17,9 +17,15 @@ let parse_operation h _ = Ok h
let compare_operations _ _ = 0 let compare_operations _ _ = 0
module Fitness = struct type validation_state = {
context : Context.t ;
fitness : Int64.t ;
}
let version_number = "\000" let current_context { context } =
return context
module Fitness = struct
type error += Invalid_fitness type error += Invalid_fitness
type error += Invalid_fitness2 type error += Invalid_fitness2
@ -36,67 +42,51 @@ module Fitness = struct
return (MBytes.get_int64 b 0) return (MBytes.get_int64 b 0)
let from_int64 fitness = let from_int64 fitness =
[ MBytes.of_string version_number ; [ int64_to_bytes fitness ]
int64_to_bytes fitness ]
let to_int64 = function let to_int64 = function
| [ version ; | [ fitness ] -> int64_of_bytes fitness
fitness ]
when Compare.String.
(MBytes.to_string version = version_number) ->
int64_of_bytes fitness
| [] -> return 0L | [] -> return 0L
| _ -> fail Invalid_fitness | _ -> fail Invalid_fitness
let get ctxt = let get { fitness } = fitness
Context.get_fitness ctxt >>= fun fitness ->
to_int64 fitness
let set ctxt v =
Context.set_fitness ctxt (from_int64 v) >>= fun ctxt ->
Lwt.return ctxt
let increase ctxt =
get ctxt >>=? fun v ->
set ctxt (Int64.succ v) >>= fun ctxt ->
return ctxt
end end
type validation_state = Context.t
let current_context ctxt =
return ctxt
let precheck_block let precheck_block
~ancestor_context:_ ~ancestor_context:_
~ancestor_timestamp:_ ~ancestor_timestamp:_
_raw_block = raw_block =
Fitness.to_int64 raw_block.Updater.shell.fitness >>=? fun _ ->
return () return ()
let begin_application let begin_application
~predecessor_context:ctxt ~predecessor_context:context
~predecessor_timestamp:_ ~predecessor_timestamp:_
_raw_block = ~predecessor_fitness:_
return ctxt raw_block =
Fitness.to_int64 raw_block.Updater.shell.fitness >>=? fun fitness ->
return { context ; fitness }
let begin_construction let begin_construction
~predecessor_context:ctxt ~predecessor_context:context
~predecessor_timestamp:_ ~predecessor_timestamp:_
~predecessor_level:_
~predecessor_fitness:pred_fitness
~predecessor:_ ~predecessor:_
~timestamp:_ = ~timestamp:_ =
return ctxt Fitness.to_int64 pred_fitness >>=? function pred_fitness ->
let fitness = Int64.succ pred_fitness in
return { context ; fitness }
let apply_operation ctxt _ = let apply_operation ctxt _ =
return ctxt return ctxt
let finalize_block ctxt = let finalize_block ctxt =
Fitness.increase ctxt >>=? fun ctxt -> let fitness = Fitness.get ctxt in
Fitness.get ctxt >>=? fun fitness -> let message = Some (Format.asprintf "fitness <- %Ld" fitness) in
let commit_message = let fitness = Fitness.from_int64 fitness in
Format.asprintf "fitness <- %Ld" fitness in return { Updater.message ; context = ctxt.context ; fitness }
Context.set_commit_message ctxt commit_message >>= fun ctxt ->
return ctxt
let rpc_services = Services.rpc_services let rpc_services = Services.rpc_services

View File

@ -45,7 +45,7 @@ let failing_service custom_root =
~output: (wrap_tzerror Data_encoding.empty) ~output: (wrap_tzerror Data_encoding.empty)
RPC.Path.(custom_root / "failing") RPC.Path.(custom_root / "failing")
let rpc_services : Context.t RPC.directory = let rpc_services : Updater.rpc_context RPC.directory =
let dir = RPC.empty in let dir = RPC.empty in
let dir = let dir =
RPC.register RPC.register

View File

@ -5,12 +5,6 @@ open Hash
include Persist.STORE include Persist.STORE
val get_fitness: t -> Fitness.fitness Lwt.t
val set_fitness: t -> Fitness.fitness -> t Lwt.t
val get_timestamp: t -> Time.t Lwt.t
val set_commit_message: t -> string -> t Lwt.t
val register_resolver: val register_resolver:
'a Base58.encoding -> (t -> string -> 'a list Lwt.t) -> unit 'a Base58.encoding -> (t -> string -> 'a list Lwt.t) -> unit

View File

@ -28,7 +28,9 @@ val empty : unit encoding
val unit : unit encoding val unit : unit encoding
val constant : string -> unit encoding val constant : string -> unit encoding
val int8 : int encoding val int8 : int encoding
val uint8 : int encoding
val int16 : int encoding val int16 : int encoding
val uint16 : int encoding
val int31 : int encoding val int31 : int encoding
val int32 : int32 encoding val int32 : int32 encoding
val int64 : int64 encoding val int64 : int64 encoding

View File

@ -2,6 +2,7 @@
open Hash open Hash
(** The version agnostic toplevel structure of operations. *)
type shell_operation = { type shell_operation = {
net_id: Net_id.t ; net_id: Net_id.t ;
} }
@ -18,12 +19,14 @@ val raw_operation_encoding: raw_operation Data_encoding.t
type shell_block = { type shell_block = {
net_id: Net_id.t ; net_id: Net_id.t ;
(** The genesis of the chain this block belongs to. *) (** The genesis of the chain this block belongs to. *)
level: Int32.t ;
(** The number of predecessing block in the chain. *)
predecessor: Block_hash.t ; predecessor: Block_hash.t ;
(** The preceding block in the chain. *) (** The preceding block in the chain. *)
timestamp: Time.t ; timestamp: Time.t ;
(** The date at which this block has been forged. *) (** The date at which this block has been forged. *)
operations: Operation_list_list_hash.t ; operations_hash: Operation_list_list_hash.t ;
(** The sequence of operations. *) (** The hash lf the merkle tree of operations. *)
fitness: MBytes.t list ; fitness: MBytes.t list ;
(** The announced score of the block. As a sequence of sequences (** The announced score of the block. As a sequence of sequences
of unsigned bytes. Ordered by length and then by contents of unsigned bytes. Ordered by length and then by contents
@ -37,6 +40,19 @@ type raw_block = {
} }
val raw_block_encoding: raw_block Data_encoding.t val raw_block_encoding: raw_block Data_encoding.t
type validation_result = {
context: Context.t ;
fitness: Fitness.fitness ;
message: string option ;
}
type rpc_context = {
context: Context.t ;
level: Int32.t ;
timestamp: Time.t ;
fitness: Fitness.fitness ;
}
(** This is the signature of a Tezos protocol implementation. It has (** This is the signature of a Tezos protocol implementation. It has
access to the standard library and the Environment module. *) access to the standard library and the Environment module. *)
module type PROTOCOL = sig module type PROTOCOL = sig
@ -99,6 +115,7 @@ module type PROTOCOL = sig
val begin_application : val begin_application :
predecessor_context: Context.t -> predecessor_context: Context.t ->
predecessor_timestamp: Time.t -> predecessor_timestamp: Time.t ->
predecessor_fitness: Fitness.fitness ->
raw_block -> raw_block ->
validation_state tzresult Lwt.t validation_state tzresult Lwt.t
@ -110,6 +127,8 @@ module type PROTOCOL = sig
val begin_construction : val begin_construction :
predecessor_context: Context.t -> predecessor_context: Context.t ->
predecessor_timestamp: Time.t -> predecessor_timestamp: Time.t ->
predecessor_level: Int32.t ->
predecessor_fitness: Fitness.fitness ->
predecessor: Block_hash.t -> predecessor: Block_hash.t ->
timestamp: Time.t -> timestamp: Time.t ->
validation_state tzresult Lwt.t validation_state tzresult Lwt.t
@ -123,10 +142,10 @@ module type PROTOCOL = sig
context that will be used as input for the validation of its context that will be used as input for the validation of its
successor block candidates. *) successor block candidates. *)
val finalize_block : val finalize_block :
validation_state -> Context.t tzresult Lwt.t validation_state -> validation_result tzresult Lwt.t
(** The list of remote procedures exported by this implementation *) (** The list of remote procedures exported by this implementation *)
val rpc_services : Context.t RPC.directory val rpc_services : rpc_context RPC.directory
val configure_sandbox : val configure_sandbox :
Context.t -> Data_encoding.json option -> Context.t tzresult Lwt.t Context.t -> Data_encoding.json option -> Context.t tzresult Lwt.t
@ -155,5 +174,10 @@ val compile : Protocol_hash.t -> component list -> bool Lwt.t
been previously compiled successfully. *) been previously compiled successfully. *)
val activate : Context.t -> Protocol_hash.t -> Context.t Lwt.t val activate : Context.t -> Protocol_hash.t -> Context.t Lwt.t
val set_test_protocol: Context.t -> Protocol_hash.t -> Context.t Lwt.t (** Fork a test network. The forkerd network will use the current block
val fork_test_network: Context.t -> Context.t Lwt.t as genesis, and [protocol] as economic protocol. The network will
be destroyed when a (successor) block will have a timestamp greater
than [expiration]. The protocol must have been previously compiled
successfully. *)
val fork_test_network:
Context.t -> protocol:Protocol_hash.t -> expiration:Time.t -> Context.t Lwt.t

View File

@ -14,7 +14,7 @@ module Command = struct
| Activate of Protocol_hash.t | Activate of Protocol_hash.t
(* Activate a protocol as a testnet *) (* Activate a protocol as a testnet *)
| Activate_testnet of Protocol_hash.t | Activate_testnet of Protocol_hash.t * Int64.t
let mk_case name args = let mk_case name args =
let open Data_encoding in let open Data_encoding in
@ -22,7 +22,7 @@ module Command = struct
(fun o -> ((), o)) (fun o -> ((), o))
(fun ((), o) -> o) (fun ((), o) -> o)
(merge_objs (merge_objs
(obj1 (req "network" (constant name))) (obj1 (req "command" (constant name)))
args) args)
let encoding = let encoding =
@ -30,14 +30,18 @@ module Command = struct
union ~tag_size:`Uint8 [ union ~tag_size:`Uint8 [
case ~tag:0 case ~tag:0
(mk_case "activate" (mk_case "activate"
(obj1 (req "hash" Protocol_hash.encoding))) (obj1
(req "hash" Protocol_hash.encoding)))
(function (Activate hash) -> Some hash | _ -> None) (function (Activate hash) -> Some hash | _ -> None)
(fun hash -> Activate hash) ; (fun hash -> Activate hash) ;
case ~tag:1 case ~tag:1
(mk_case "activate_testnet" (mk_case "activate_testnet"
(obj1 (req "hash" Protocol_hash.encoding))) (obj2
(function (Activate_testnet hash) -> Some hash | _ -> None) (req "hash" Protocol_hash.encoding)
(fun hash -> Activate_testnet hash) ; (req "validity_time" int64)))
(function (Activate_testnet (hash, delay)) -> Some (hash, delay)
| _ -> None)
(fun (hash, delay) -> Activate_testnet (hash, delay)) ;
] ]
let signed_encoding = let signed_encoding =

View File

@ -45,9 +45,15 @@ type block = {
} }
let max_block_length = let max_block_length =
match Data_encoding.Binary.fixed_length Data.Command.signed_encoding with Data_encoding.Binary.length
| None -> assert false Data.Command.encoding
| Some len -> len (Activate_testnet (Protocol_hash.hash_bytes [], 0L))
+
begin
match Data_encoding.Binary.fixed_length Ed25519.Signature.encoding with
| None -> assert false
| Some len -> len
end
let parse_block { Updater.shell ; proto } : block tzresult = let parse_block { Updater.shell ; proto } : block tzresult =
match Data_encoding.Binary.of_bytes Data.Command.signed_encoding proto with match Data_encoding.Binary.of_bytes Data.Command.signed_encoding proto with
@ -61,10 +67,10 @@ let check_signature ctxt { shell ; command ; signature } =
(Ed25519.Signature.check public_key signature bytes) (Ed25519.Signature.check public_key signature bytes)
Invalid_signature Invalid_signature
type validation_state = block * Context.t type validation_state = Updater.validation_result
let current_context (_, ctxt) = let current_context ({ context } : validation_state) =
return ctxt return context
let precheck_block let precheck_block
~ancestor_context:_ ~ancestor_context:_
@ -76,38 +82,39 @@ let precheck_block
let begin_application let begin_application
~predecessor_context:ctxt ~predecessor_context:ctxt
~predecessor_timestamp:_ ~predecessor_timestamp:_
~predecessor_fitness:_
raw_block = raw_block =
Data.Init.may_initialize ctxt >>=? fun ctxt ->
Lwt.return (parse_block raw_block) >>=? fun block -> Lwt.return (parse_block raw_block) >>=? fun block ->
return (block, ctxt) check_signature ctxt block >>=? fun () ->
let fitness = raw_block.shell.fitness in
match block.command with
| Data.Command.Activate hash ->
let message =
Some (Format.asprintf "activate %a" Protocol_hash.pp_short hash) in
Updater.activate ctxt hash >>= fun ctxt ->
return { Updater.message ; context = ctxt ; fitness }
| Activate_testnet (hash, delay) ->
let message =
Some (Format.asprintf "activate testnet %a" Protocol_hash.pp_short hash) in
let expiration = Time.add raw_block.shell.timestamp delay in
Updater.fork_test_network ctxt hash expiration >>= fun ctxt ->
return { Updater.message ; context = ctxt ; fitness }
let begin_construction let begin_construction
~predecessor_context:_ ~predecessor_context:context
~predecessor_timestamp:_ ~predecessor_timestamp:_
~predecessor_level:_
~predecessor_fitness:fitness
~predecessor:_ ~predecessor:_
~timestamp:_ = ~timestamp:_ =
Lwt.return (Error []) (* absurd *) (* Dummy result. *)
return { Updater.message = None ; context ; fitness }
let apply_operation _vctxt _ = let apply_operation _vctxt _ =
Lwt.return (Error []) (* absurd *) Lwt.return (Error []) (* absurd *)
let finalize_block (header, ctxt) = let finalize_block state = return state
check_signature ctxt header >>=? fun () ->
Data.Init.may_initialize ctxt >>=? fun ctxt ->
Context.set_fitness ctxt header.shell.fitness >>= fun ctxt ->
match header.command with
| Activate hash ->
let commit_message =
Format.asprintf "activate %a" Protocol_hash.pp_short hash in
Context.set_commit_message ctxt commit_message >>= fun ctxt ->
Updater.activate ctxt hash >>= fun ctxt ->
return ctxt
| Activate_testnet hash ->
let commit_message =
Format.asprintf "activate testnet %a" Protocol_hash.pp_short hash in
Context.set_commit_message ctxt commit_message >>= fun ctxt ->
Updater.set_test_protocol ctxt hash >>= fun ctxt ->
Updater.fork_test_network ctxt >>= fun ctxt ->
return ctxt
let rpc_services = Services.rpc_services let rpc_services = Services.rpc_services

View File

@ -38,8 +38,9 @@ module Forge = struct
~description: "Forge a block" ~description: "Forge a block"
~input: ~input:
(merge_objs (merge_objs
(obj4 (obj5
(req "net_id" Net_id.encoding) (req "net_id" Net_id.encoding)
(req "level" int32)
(req "predecessor" Block_hash.encoding) (req "predecessor" Block_hash.encoding)
(req "timestamp" Time.encoding) (req "timestamp" Time.encoding)
(req "fitness" Fitness.encoding)) (req "fitness" Fitness.encoding))
@ -53,18 +54,18 @@ let int64_to_bytes i =
MBytes.set_int64 b 0 i; MBytes.set_int64 b 0 i;
b b
let operations = let operations_hash =
Operation_list_list_hash.compute [Operation_list_hash.empty] Operation_list_list_hash.compute [Operation_list_hash.empty]
let rpc_services : Context.t RPC.directory = let rpc_services : Updater.rpc_context RPC.directory =
let dir = RPC.empty in let dir = RPC.empty in
let dir = let dir =
RPC.register RPC.register
dir dir
(Forge.block RPC.Path.root) (Forge.block RPC.Path.root)
(fun _ctxt ((net_id, predecessor, timestamp, fitness), command) -> (fun _ctxt ((net_id, level, predecessor, timestamp, fitness), command) ->
let shell = { Updater.net_id ; predecessor ; timestamp ; fitness ; let shell = { Updater.net_id ; level ; predecessor ;
operations } in timestamp ; fitness ; operations_hash } in
let bytes = Data.Command.forge shell command in let bytes = Data.Command.forge shell command in
RPC.Answer.return bytes) in RPC.Answer.return bytes) in
dir dir

View File

@ -64,7 +64,7 @@ let sync_nodes nodes =
sync_nodes nodes >>= function sync_nodes nodes >>= function
| Ok () | Error (Exn End_of_file :: _) -> | Ok () | Error (Exn End_of_file :: _) ->
return () return ()
| Error e as err -> | Error _ as err ->
Lwt.return err Lwt.return err
let run_nodes client server = let run_nodes client server =
@ -147,7 +147,7 @@ module Low_level = struct
return () return ()
let server _ch sched socket = let server _ch sched socket =
raw_accept sched socket >>= fun (fd, point) -> raw_accept sched socket >>= fun (fd, _point) ->
P2p_io_scheduler.write fd simple_msg >>=? fun () -> P2p_io_scheduler.write fd simple_msg >>=? fun () ->
P2p_io_scheduler.close fd >>=? fun _ -> P2p_io_scheduler.close fd >>=? fun _ ->
return () return ()
@ -190,7 +190,7 @@ module Kicked = struct
let encoding = Data_encoding.bytes let encoding = Data_encoding.bytes
let server _ch sched socket = let server _ch sched socket =
accept sched socket >>=? fun (info, auth_fd) -> accept sched socket >>=? fun (_info, auth_fd) ->
P2p_connection.accept auth_fd encoding >>= fun conn -> P2p_connection.accept auth_fd encoding >>= fun conn ->
_assert (Kick.is_rejected conn) __LOC__ "" >>=? fun () -> _assert (Kick.is_rejected conn) __LOC__ "" >>=? fun () ->
return () return ()
@ -212,7 +212,7 @@ module Simple_message = struct
let simple_msg2 = MBytes.create (1 lsl 4) let simple_msg2 = MBytes.create (1 lsl 4)
let server ch sched socket = let server ch sched socket =
accept sched socket >>=? fun (info, auth_fd) -> accept sched socket >>=? fun (_info, auth_fd) ->
P2p_connection.accept auth_fd encoding >>=? fun conn -> P2p_connection.accept auth_fd encoding >>=? fun conn ->
P2p_connection.write_sync conn simple_msg >>=? fun () -> P2p_connection.write_sync conn simple_msg >>=? fun () ->
P2p_connection.read conn >>=? fun (_msg_size, msg) -> P2p_connection.read conn >>=? fun (_msg_size, msg) ->
@ -242,7 +242,7 @@ module Close_on_read = struct
let simple_msg = MBytes.create (1 lsl 4) let simple_msg = MBytes.create (1 lsl 4)
let server _ch sched socket = let server _ch sched socket =
accept sched socket >>=? fun (info, auth_fd) -> accept sched socket >>=? fun (_info, auth_fd) ->
P2p_connection.accept auth_fd encoding >>=? fun conn -> P2p_connection.accept auth_fd encoding >>=? fun conn ->
P2p_connection.close conn >>= fun _stat -> P2p_connection.close conn >>= fun _stat ->
return () return ()
@ -266,7 +266,7 @@ module Close_on_write = struct
let simple_msg = MBytes.create (1 lsl 4) let simple_msg = MBytes.create (1 lsl 4)
let server ch sched socket = let server ch sched socket =
accept sched socket >>=? fun (info, auth_fd) -> accept sched socket >>=? fun (_info, auth_fd) ->
P2p_connection.accept auth_fd encoding >>=? fun conn -> P2p_connection.accept auth_fd encoding >>=? fun conn ->
P2p_connection.close conn >>= fun _stat -> P2p_connection.close conn >>= fun _stat ->
sync ch >>=? fun ()-> sync ch >>=? fun ()->
@ -291,8 +291,8 @@ module Garbled_data = struct
let garbled_msg = MBytes.create (1 lsl 4) let garbled_msg = MBytes.create (1 lsl 4)
let server ch sched socket = let server _ch sched socket =
accept sched socket >>=? fun (info, auth_fd) -> accept sched socket >>=? fun (_info, auth_fd) ->
P2p_connection.accept auth_fd encoding >>=? fun conn -> P2p_connection.accept auth_fd encoding >>=? fun conn ->
P2p_connection.raw_write_sync conn garbled_msg >>=? fun () -> P2p_connection.raw_write_sync conn garbled_msg >>=? fun () ->
P2p_connection.read conn >>= fun err -> P2p_connection.read conn >>= fun err ->
@ -300,7 +300,7 @@ module Garbled_data = struct
P2p_connection.close conn >>= fun _stat -> P2p_connection.close conn >>= fun _stat ->
return () return ()
let client ch sched addr port = let client _ch sched addr port =
connect sched addr port id2 >>=? fun auth_fd -> connect sched addr port id2 >>=? fun auth_fd ->
P2p_connection.accept auth_fd encoding >>=? fun conn -> P2p_connection.accept auth_fd encoding >>=? fun conn ->
P2p_connection.read conn >>= fun err -> P2p_connection.read conn >>= fun err ->
@ -328,7 +328,7 @@ let spec = Arg.[
let main () = let main () =
let open Utils in let open Utils in
let anon_fun num_peers = raise (Arg.Bad "No anonymous argument.") in let anon_fun _num_peers = raise (Arg.Bad "No anonymous argument.") in
let usage_msg = "Usage: %s.\nArguments are:" in let usage_msg = "Usage: %s.\nArguments are:" in
Arg.parse spec anon_fun usage_msg ; Arg.parse spec anon_fun usage_msg ;
Test.run "p2p-connection." [ Test.run "p2p-connection." [

View File

@ -54,7 +54,7 @@ let sync_nodes nodes =
sync_nodes nodes >>= function sync_nodes nodes >>= function
| Ok () | Error (Exn End_of_file :: _) -> | Ok () | Error (Exn End_of_file :: _) ->
return () return ()
| Error e as err -> | Error _ as err ->
Lwt.return err Lwt.return err
let detach_node f points n = let detach_node f points n =
@ -100,7 +100,7 @@ let detach_node f points n =
return () return ()
end end
let detach_nodes ?(sync = 0) run_node points = let detach_nodes run_node points =
let open Utils in let open Utils in
let clients = List.length points in let clients = List.length points in
Lwt_list.map_p Lwt_list.map_p
@ -196,7 +196,7 @@ module Random_connections = struct
let rem = ref (n * total) in let rem = ref (n * total) in
iter_p (fun point -> connect_random pool total rem point n) points iter_p (fun point -> connect_random pool total rem point n) points
let node repeat channel pool points = let node repeat _channel pool points =
lwt_log_info "Begin random connections." >>= fun () -> lwt_log_info "Begin random connections." >>= fun () ->
connect_random_all pool points repeat >>=? fun () -> connect_random_all pool points repeat >>=? fun () ->
lwt_log_info "Random connections OK." >>= fun () -> lwt_log_info "Random connections OK." >>= fun () ->
@ -267,7 +267,7 @@ let spec = Arg.[
let main () = let main () =
let open Utils in let open Utils in
let anon_fun num_peers = raise (Arg.Bad "No anonymous argument.") in let anon_fun _num_peers = raise (Arg.Bad "No anonymous argument.") in
let usage_msg = "Usage: %s <num_peers>.\nArguments are:" in let usage_msg = "Usage: %s <num_peers>.\nArguments are:" in
Arg.parse spec anon_fun usage_msg ; Arg.parse spec anon_fun usage_msg ;
let ports = !port -- (!port + !clients - 1) in let ports = !port -- (!port + !clients - 1) in

View File

@ -361,7 +361,7 @@ module Mining = struct
block block
delegate_sk delegate_sk
shell shell
mining_slot priority
seed_nonce_hash = seed_nonce_hash =
Client_proto_rpcs.Constants.stamp_threshold Client_proto_rpcs.Constants.stamp_threshold
rpc_config block >>=? fun stamp_threshold -> rpc_config block >>=? fun stamp_threshold ->
@ -370,7 +370,7 @@ module Mining = struct
Sodium.Random.Bigbytes.generate Constants.proof_of_work_nonce_size in Sodium.Random.Bigbytes.generate Constants.proof_of_work_nonce_size in
let unsigned_header = let unsigned_header =
Block.forge_header Block.forge_header
shell { mining_slot ; seed_nonce_hash ; proof_of_work_nonce } in shell { priority ; seed_nonce_hash ; proof_of_work_nonce } in
let signed_header = let signed_header =
Environment.Ed25519.Signature.append delegate_sk unsigned_header in Environment.Ed25519.Signature.append delegate_sk unsigned_header in
let block_hash = Block_hash.hash_bytes [signed_header] in let block_hash = Block_hash.hash_bytes [signed_header] in
@ -393,24 +393,24 @@ module Mining = struct
Client_node_rpcs.Blocks.info rpc_config block >>=? fun bi -> Client_node_rpcs.Blocks.info rpc_config block >>=? fun bi ->
let seed_nonce_hash = Nonce.hash seed_nonce in let seed_nonce_hash = Nonce.hash seed_nonce in
Client_proto_rpcs.Context.next_level rpc_config block >>=? fun level -> Client_proto_rpcs.Context.next_level rpc_config block >>=? fun level ->
let operations = let operations_hash =
Operation_list_list_hash.compute Operation_list_list_hash.compute
[Operation_list_hash.compute operation_list] in [Operation_list_hash.compute operation_list] in
let shell = let shell =
{ Store.Block_header.net_id = bi.net ; predecessor = bi.hash ; { Store.Block_header.net_id = bi.net_id ; predecessor = bi.hash ;
timestamp ; fitness ; operations } in timestamp ; fitness ; operations_hash ;
let slot = { Block.level = level.level ; priority = Int32.of_int priority } in level = Raw_level.to_int32 level.level } in
mine_stamp mine_stamp
block src_sk shell slot seed_nonce_hash >>=? fun proof_of_work_nonce -> block src_sk shell priority seed_nonce_hash >>=? fun proof_of_work_nonce ->
Client_proto_rpcs.Helpers.Forge.block rpc_config Client_proto_rpcs.Helpers.Forge.block rpc_config
block block
~net:bi.net ~net:bi.net_id
~predecessor:bi.hash ~predecessor:bi.hash
~timestamp ~timestamp
~fitness ~fitness
~operations ~operations_hash
~level:level.level ~level:level.level
~priority:priority ~priority
~seed_nonce_hash ~seed_nonce_hash
~proof_of_work_nonce ~proof_of_work_nonce
() >>=? fun unsigned_header -> () >>=? fun unsigned_header ->
@ -422,6 +422,7 @@ module Mining = struct
let mine let mine
?(force = false) ?(force = false)
?(operations = []) ?(operations = [])
~fitness_gap
contract contract
block = block =
Client_mining_blocks.info rpc_config block >>=? fun bi -> Client_mining_blocks.info rpc_config block >>=? fun bi ->
@ -434,12 +435,11 @@ module Mining = struct
Client_proto_rpcs.Context.level rpc_config block >>=? fun level -> Client_proto_rpcs.Context.level rpc_config block >>=? fun level ->
let level = Raw_level.succ level.level in let level = Raw_level.succ level.level in
get_first_priority level contract block >>=? fun priority -> get_first_priority level contract block >>=? fun priority ->
(Fitness_repr.to_int64 bi.fitness >|= (Lwt.return (Fitness_repr.to_int64 bi.fitness) >|=
Register_client_embedded_proto_alpha.wrap_error) >>=? fun fitness -> Register_client_embedded_proto_alpha.wrap_error) >>=? fun fitness ->
let fitness = let fitness =
Fitness_repr.from_int64 @@ Fitness_repr.from_int64 @@
Int64.add fitness (Int64.of_int @@ List.length operations + 1) in Int64.add fitness (Int64.of_int fitness_gap) in
Level.pp_full Format.str_formatter bi.level ;
inject_block inject_block
~force ~force
~priority ~priority
@ -453,7 +453,7 @@ module Mining = struct
let endorsement_reward contract block = let endorsement_reward contract block =
Client_mining_blocks.info rpc_config block >>=? fun bi -> Client_mining_blocks.info rpc_config block >>=? fun bi ->
get_first_priority bi.level.level contract block >>=? fun prio -> get_first_priority bi.level.level contract block >>=? fun prio ->
Mining.endorsement_reward ~block_priority:(Int32.of_int prio) >|= Mining.endorsement_reward ~block_priority:prio >|=
Register_client_embedded_proto_alpha.wrap_error >>|? Register_client_embedded_proto_alpha.wrap_error >>|?
Tez.to_cents Tez.to_cents
@ -553,3 +553,8 @@ module Endorse = struct
block delegate () block delegate ()
end end
let display_level block =
Client_proto_rpcs.Context.level rpc_config block >>=? fun lvl ->
Format.eprintf "Level: %a@." Level.pp_full lvl ;
return ()

View File

@ -105,7 +105,7 @@ module Mining : sig
Client_proto_rpcs.block -> Client_proto_rpcs.block ->
secret_key -> secret_key ->
Updater.shell_block -> Updater.shell_block ->
Block.mining_slot -> int ->
Nonce_hash.t -> Nonce_hash.t ->
MBytes.t tzresult Lwt.t MBytes.t tzresult Lwt.t
@ -122,6 +122,7 @@ module Mining : sig
val mine : val mine :
?force:bool -> ?force:bool ->
?operations:Operation_hash.t list -> ?operations:Operation_hash.t list ->
fitness_gap:int ->
Account.t -> Account.t ->
Client_node_rpcs.Blocks.block -> Client_node_rpcs.Blocks.block ->
Block_hash.t tzresult Lwt.t Block_hash.t tzresult Lwt.t
@ -191,3 +192,7 @@ module Assert : sig
val invalid_endorsement_slot : msg:string -> 'a tzresult -> unit val invalid_endorsement_slot : msg:string -> 'a tzresult -> unit
end end
val rpc_config: Client_rpcs.config
val display_level: Client_proto_rpcs.block -> unit tzresult Lwt.t

View File

@ -9,6 +9,7 @@
open Client_embedded_proto_alpha open Client_embedded_proto_alpha
open Tezos_context open Tezos_context
open Client_alpha
module Helpers = Proto_alpha_helpers module Helpers = Proto_alpha_helpers
module Assert = Helpers.Assert module Assert = Helpers.Assert
@ -16,25 +17,25 @@ module Assert = Helpers.Assert
let test_double_endorsement contract block = let test_double_endorsement contract block =
(* Double endorsement for the same level *) (* Double endorsement for the same level *)
Helpers.Mining.mine contract block >>=? fun b1 -> Helpers.Mining.mine ~fitness_gap:1 contract block >>=? fun b1 ->
(* branch root *) (* branch root *)
Helpers.Mining.mine contract (`Hash b1) >>=? fun b2 -> Helpers.Mining.mine ~fitness_gap:1 contract (`Hash b1) >>=? fun b2 ->
(* changing branch *) (* changing branch *)
Helpers.Mining.mine contract (`Hash b1) >>=? fun b2' -> Helpers.Mining.mine ~fitness_gap:1 contract (`Hash b1) >>=? fun b2' ->
(* branch root *) (* branch root *)
Helpers.Endorse.endorse ~force:true contract (`Hash b2) >>=? fun ops -> Helpers.Endorse.endorse ~force:true contract (`Hash b2) >>=? fun ops ->
Helpers.Mining.mine ~operations:[ ops ] contract (`Hash b2) >>=? fun _b3 -> Helpers.Mining.mine ~fitness_gap:2 ~operations:[ ops ] contract (`Hash b2) >>=? fun _b3 ->
Helpers.Endorse.endorse ~force:true contract (`Hash b2') >>=? fun ops -> Helpers.Endorse.endorse ~force:true contract (`Hash b2') >>=? fun ops ->
Helpers.Mining.mine ~operations:[ ops ] contract (`Hash b2') >>=? fun b3' -> Helpers.Mining.mine ~fitness_gap:2 ~operations:[ ops ] contract (`Hash b2') >>=? fun b3' ->
Helpers.Endorse.endorse ~force:true contract (`Hash b3') >>=? fun ops -> Helpers.Endorse.endorse ~force:true contract (`Hash b3') >>=? fun ops ->
Helpers.Mining.mine ~operations:[ ops ] contract (`Hash b3') >>=? fun b4' -> Helpers.Mining.mine ~fitness_gap:2 ~operations:[ ops ] contract (`Hash b3') >>=? fun b4' ->
(* TODO: Inject double endorsement op ! *) (* TODO: Inject double endorsement op ! *)
Helpers.Mining.mine contract (`Hash b4') Helpers.Mining.mine ~fitness_gap:1 contract (`Hash b4')
(* FIXME: Mining.Invalid_signature is unclassified *) (* FIXME: Mining.Invalid_signature is unclassified *)
let test_invalid_signature block = let test_invalid_signature block =
@ -47,7 +48,7 @@ let test_invalid_signature block =
DYfTKhq7rDQujdn5WWzwUMeV3agaZ6J2vPQT58jJAJPi" in DYfTKhq7rDQujdn5WWzwUMeV3agaZ6J2vPQT58jJAJPi" in
let account = let account =
Helpers.Account.create ~keys:(secret_key, public_key) "WRONG SIGNATURE" in Helpers.Account.create ~keys:(secret_key, public_key) "WRONG SIGNATURE" in
Helpers.Mining.mine account block >>= fun res -> Helpers.Mining.mine ~fitness_gap:1 account block >>= fun res ->
Assert.generic_economic_error ~msg:__LOC__ res ; Assert.generic_economic_error ~msg:__LOC__ res ;
return () return ()
@ -77,7 +78,7 @@ let test_invalid_endorsement_slot contract block =
return () return ()
let test_endorsement_rewards let test_endorsement_rewards
block ({ Helpers.Account.b1 ; _ } as baccounts) = block ({ Helpers.Account.b5 = b1 ; _ } as baccounts) =
let get_endorser_except_b1 accounts = let get_endorser_except_b1 accounts =
let account, cpt = ref accounts.(0), ref 0 in let account, cpt = ref accounts.(0), ref 0 in
while !account = b1 do while !account = b1 do
@ -94,20 +95,24 @@ let test_endorsement_rewards
get_endorser_except_b1 accounts >>=? fun (account0, slot0) -> get_endorser_except_b1 accounts >>=? fun (account0, slot0) ->
Helpers.Account.balance account0 >>=? fun balance0 -> Helpers.Account.balance account0 >>=? fun balance0 ->
Helpers.Endorse.endorse ~slot:slot0 ~force:true account0 block >>=? fun ops -> Helpers.Endorse.endorse ~slot:slot0 ~force:true account0 block >>=? fun ops ->
Helpers.Mining.mine ~operations:[ ops ] b1 block >>=? fun head0 -> Helpers.Mining.mine ~fitness_gap:2 ~operations:[ ops ] b1 block >>=? fun head0 ->
Helpers.display_level (`Hash head0) >>=? fun () ->
Assert.balance_equal ~msg:__LOC__ account0 Assert.balance_equal ~msg:__LOC__ account0
(Int64.sub (Tez.to_cents balance0) bond) >>=? fun () -> (Int64.sub (Tez.to_cents balance0) bond) >>=? fun () ->
(* #2 endorse & inject in a block *) (* #2 endorse & inject in a block *)
let block0 = `Hash head0 in let block0 = `Hash head0 in
Helpers.Endorse.endorsers_list block0 baccounts >>=? fun accounts -> Helpers.Endorse.endorsers_list block0 baccounts >>=? fun accounts ->
get_endorser_except_b1 accounts >>=? fun (account1, slot1) -> get_endorser_except_b1 accounts >>=? fun (account1, slot1) ->
Helpers.Account.balance account1 >>=? fun balance1 -> Helpers.Account.balance account1 >>=? fun balance1 ->
Helpers.Endorse.endorse ~slot:slot1 ~force:true account1 block0 >>=? fun ops -> Helpers.Endorse.endorse ~slot:slot1 ~force:true account1 block0 >>=? fun ops ->
Helpers.Mining.mine ~operations:[ ops ] b1 block0 >>=? fun head1 -> Helpers.Mining.mine ~fitness_gap:2 ~operations:[ ops ] b1 block0 >>=? fun head1 ->
Helpers.display_level (`Hash head1) >>=? fun () ->
Assert.balance_equal ~msg:__LOC__ account1 Assert.balance_equal ~msg:__LOC__ account1
(Int64.sub (Tez.to_cents balance1) bond) >>=? fun () -> (Int64.sub (Tez.to_cents balance1) bond) >>=? fun () ->
(* #3 endorse but the operation is not included in a block, so no reward *) (* #3 endorse but the operation is not included in a block, so no reward *)
let block1 = `Hash head1 in let block1 = `Hash head1 in
Helpers.Endorse.endorsers_list block1 baccounts >>=? fun accounts -> Helpers.Endorse.endorsers_list block1 baccounts >>=? fun accounts ->
@ -117,8 +122,12 @@ let test_endorsement_rewards
Assert.balance_equal ~msg:__LOC__ account2 Assert.balance_equal ~msg:__LOC__ account2
(Int64.sub (Tez.to_cents balance2) bond) >>=? fun () -> (Int64.sub (Tez.to_cents balance2) bond) >>=? fun () ->
Helpers.Mining.mine b1 (`Hash head1) >>=? fun head2 -> Helpers.Mining.mine ~fitness_gap:1 b1 (`Hash head1) >>=? fun head2 ->
Helpers.Mining.mine b1 (`Hash head2) >>=? fun head3 -> Helpers.display_level (`Hash head2) >>=? fun () ->
Helpers.Mining.mine ~fitness_gap:1 b1 (`Hash head2) >>=? fun head3 ->
Helpers.display_level (`Hash head3) >>=? fun () ->
Helpers.Mining.mine ~fitness_gap:1 b1 (`Hash head3) >>=? fun head4 ->
Helpers.display_level (`Hash head4) >>=? fun () ->
(* Check rewards after one cycle for account0 *) (* Check rewards after one cycle for account0 *)
Helpers.Mining.endorsement_reward b1 block0 >>=? fun rw0 -> Helpers.Mining.endorsement_reward b1 block0 >>=? fun rw0 ->
@ -135,8 +144,10 @@ let test_endorsement_rewards
~msg:__LOC__ account2 (Tez.to_cents balance2) >>=? fun () -> ~msg:__LOC__ account2 (Tez.to_cents balance2) >>=? fun () ->
(* #2 endorse and check reward only on the good chain *) (* #2 endorse and check reward only on the good chain *)
Helpers.Mining.mine b1 (`Hash head3) >>=? fun head -> Helpers.Mining.mine ~fitness_gap:1 b1 (`Hash head4) >>=? fun head ->
Helpers.Mining.mine b1 (`Hash head3) >>=? fun fork -> Helpers.display_level (`Hash head) >>=? fun () ->
Helpers.Mining.mine ~fitness_gap:1 b1 (`Hash head4) >>=? fun fork ->
Helpers.display_level (`Hash fork) >>=? fun () ->
(* working on head *) (* working on head *)
Helpers.Endorse.endorsers_list (`Hash head) baccounts >>=? fun accounts -> Helpers.Endorse.endorsers_list (`Hash head) baccounts >>=? fun accounts ->
@ -144,18 +155,22 @@ let test_endorsement_rewards
Helpers.Account.balance account3 >>=? fun balance3 -> Helpers.Account.balance account3 >>=? fun balance3 ->
Helpers.Endorse.endorse Helpers.Endorse.endorse
~slot:slot3 ~force:true account3 (`Hash head) >>=? fun ops -> ~slot:slot3 ~force:true account3 (`Hash head) >>=? fun ops ->
Helpers.Mining.mine ~operations:[ ops ] b1 (`Hash head) >>=? fun new_head -> Helpers.Mining.mine ~fitness_gap:2 ~operations:[ ops ] b1 (`Hash head) >>=? fun new_head ->
Helpers.display_level (`Hash new_head) >>=? fun () ->
(* working on fork *) (* working on fork *)
Helpers.Endorse.endorsers_list (`Hash fork) baccounts >>=? fun accounts -> Helpers.Endorse.endorsers_list (`Hash fork) baccounts >>=? fun accounts ->
get_endorser_except_b1 accounts >>=? fun (account4, slot4) -> get_endorser_except_b1 accounts >>=? fun (account4, slot4) ->
Helpers.Account.balance account4 >>=? fun _balance4 -> Helpers.Account.balance account4 >>=? fun _balance4 ->
Helpers.Endorse.endorse ~slot:slot4 ~force:true account4 (`Hash fork) >>=? fun ops -> Helpers.Endorse.endorse ~slot:slot4 ~force:true account4 (`Hash fork) >>=? fun ops ->
Helpers.Mining.mine ~operations:[ ops ] b1 (`Hash fork) >>=? fun _new_fork -> Helpers.Mining.mine ~fitness_gap:2 ~operations:[ ops ] b1 (`Hash fork) >>=? fun _new_fork ->
Helpers.display_level (`Hash _new_fork) >>=? fun () ->
Helpers.Account.balance account4 >>=? fun balance4 -> Helpers.Account.balance account4 >>=? fun balance4 ->
Helpers.Mining.mine b1 (`Hash new_head) >>=? fun head -> Helpers.Mining.mine ~fitness_gap:1 b1 (`Hash new_head) >>=? fun head ->
Helpers.Mining.mine b1 (`Hash head) >>=? fun head -> Helpers.display_level (`Hash head) >>=? fun () ->
Helpers.Mining.mine ~fitness_gap:1 b1 (`Hash head) >>=? fun head ->
Helpers.display_level (`Hash head) >>=? fun () ->
(* Check rewards after one cycle *) (* Check rewards after one cycle *)
Helpers.Mining.endorsement_reward b1 (`Hash new_head) >>=? fun reward -> Helpers.Mining.endorsement_reward b1 (`Hash new_head) >>=? fun reward ->
@ -209,7 +224,7 @@ let run head (({ b1 ; b2 ; b3 ; b4 ; b5 } : Helpers.Account.bootstrap_accounts)
(* FIXME: cannot inject double endorsement operation yet, but the (* FIXME: cannot inject double endorsement operation yet, but the
code is still here code is still here
Double endorsement *) Double endorsement *)
test_double_endorsement b5 (`Hash head) >>=? fun new_head -> test_double_endorsement b4 (`Hash head) >>=? fun new_head ->
return new_head return new_head

View File

@ -15,7 +15,7 @@ module Assert = Helpers.Assert
let run blkid ({ b1 ; b2 ; _ } : Helpers.Account.bootstrap_accounts) = let run blkid ({ b1 ; b2 ; _ } : Helpers.Account.bootstrap_accounts) =
Helpers.Mining.mine b1 blkid >>=? fun blkh -> Helpers.Mining.mine ~fitness_gap:1 b1 blkid >>=? fun blkh ->
let foo = Helpers.Account.create "foo" in let foo = Helpers.Account.create "foo" in
(* Origination with amount = 0 tez *) (* Origination with amount = 0 tez *)

View File

@ -15,7 +15,7 @@ module Assert = Helpers.Assert
let run blkid ({ b1 ; b2 ; b3 ; _ } : Helpers.Account.bootstrap_accounts) = let run blkid ({ b1 ; b2 ; b3 ; _ } : Helpers.Account.bootstrap_accounts) =
Helpers.Mining.mine b1 blkid >>=? fun blkh -> Helpers.Mining.mine ~fitness_gap:1 b1 blkid >>=? fun blkh ->
let foo = Helpers.Account.create "foo" in let foo = Helpers.Account.create "foo" in
let bar = Helpers.Account.create "bar" in let bar = Helpers.Account.create "bar" in

View File

@ -37,6 +37,8 @@ let net_id = Net_id.of_block_hash genesis_block
(** Context creation *) (** Context creation *)
let commit = commit ~time:Time.epoch ~message:""
let block2 = let block2 =
Block_hash.of_hex_exn Block_hash.of_hex_exn
"2222222222222222222222222222222222222222222222222222222222222222" "2222222222222222222222222222222222222222222222222222222222222222"
@ -87,8 +89,7 @@ let wrap_context_init f base_dir =
Context.commit_genesis idx Context.commit_genesis idx
~id:genesis.block ~id:genesis.block
~time:genesis.time ~time:genesis.time
~protocol:genesis.protocol ~protocol:genesis.protocol >>= fun _ ->
~test_protocol:genesis.protocol >>= fun _ ->
create_block2 idx >>= fun () -> create_block2 idx >>= fun () ->
create_block3a idx >>= fun () -> create_block3a idx >>= fun () ->
create_block3b idx >>= fun () -> create_block3b idx >>= fun () ->

View File

@ -38,7 +38,7 @@ let net_id = Net_id.of_block_hash genesis_block
let incr_fitness fitness = let incr_fitness fitness =
let new_fitness = let new_fitness =
match fitness with match fitness with
| [ _ ; fitness ] -> | [ fitness ] ->
Pervasives.( Pervasives.(
Data_encoding.Binary.of_bytes Data_encoding.int64 fitness Data_encoding.Binary.of_bytes Data_encoding.int64 fitness
|> Utils.unopt ~default:0L |> Utils.unopt ~default:0L
@ -47,7 +47,7 @@ let incr_fitness fitness =
) )
| _ -> Data_encoding.Binary.to_bytes Data_encoding.int64 1L | _ -> Data_encoding.Binary.to_bytes Data_encoding.int64 1L
in in
[ MBytes.of_string "\000" ; new_fitness ] [ new_fitness ]
let incr_timestamp timestamp = let incr_timestamp timestamp =
Time.add timestamp (Int64.add 1L (Random.int64 10L)) Time.add timestamp (Int64.add 1L (Random.int64 10L))
@ -62,15 +62,16 @@ let operation op =
Data_encoding.Binary.to_bytes Store.Operation.encoding op Data_encoding.Binary.to_bytes Store.Operation.encoding op
let block _state ?(operations = []) pred_hash pred name : Store.Block_header.t = let block _state ?(operations = []) pred_hash pred name : Store.Block_header.t =
let operations = 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.Store.Block_header.shell.fitness in let fitness = incr_fitness pred.Store.Block_header.shell.fitness in
let timestamp = incr_timestamp pred.shell.timestamp in let timestamp = incr_timestamp pred.shell.timestamp in
{ shell = { { shell = {
net_id = pred.shell.net_id ; net_id = pred.shell.net_id ;
level = Int32.succ pred.shell.level ;
predecessor = pred_hash ; predecessor = pred_hash ;
timestamp ; operations; fitness } ; timestamp ; operations_hash ; fitness } ;
proto = MBytes.of_string name ; proto = MBytes.of_string name ;
} }
@ -133,14 +134,15 @@ let build_chain state tbl otbl pred names =
let block _state ?(operations = []) (pred: State.Valid_block.t) name let block _state ?(operations = []) (pred: State.Valid_block.t) name
: State.Block_header.t = : State.Block_header.t =
let operations = 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 fitness = incr_fitness pred.fitness in
let timestamp = incr_timestamp pred.timestamp in let timestamp = incr_timestamp pred.timestamp in
{ shell = { net_id = pred.net_id ; { shell = { net_id = pred.net_id ;
level = Int32.succ pred.level ;
predecessor = pred.hash ; predecessor = pred.hash ;
timestamp ; operations; fitness } ; timestamp ; operations_hash ; fitness } ;
proto = MBytes.of_string name ; proto = MBytes.of_string name ;
} }
@ -166,6 +168,7 @@ let build_valid_chain state tbl vtbl otbl pred names =
Proto.begin_application Proto.begin_application
~predecessor_context: pred.context ~predecessor_context: pred.context
~predecessor_timestamp: pred.timestamp ~predecessor_timestamp: pred.timestamp
~predecessor_fitness: pred.fitness
block >>=? fun vstate -> block >>=? fun vstate ->
(* no operations *) (* no operations *)
Proto.finalize_block vstate Proto.finalize_block vstate

View File

@ -89,13 +89,14 @@ let test_operation s =
(** Block store *) (** Block store *)
let lolblock ?(operations = []) header = let lolblock ?(operations = []) header =
let operations = 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
{ Store.Block_header.shell = { Store.Block_header.shell =
{ timestamp = Time.of_seconds (Random.int64 1500L) ; { timestamp = Time.of_seconds (Random.int64 1500L) ;
level = 0l ; (* dummy *)
net_id ; net_id ;
predecessor = genesis_block ; operations ; predecessor = genesis_block ; operations_hash ;
fitness = [MBytes.of_string @@ string_of_int @@ String.length header; fitness = [MBytes.of_string @@ string_of_int @@ String.length header;
MBytes.of_string @@ string_of_int @@ 12] } ; MBytes.of_string @@ string_of_int @@ 12] } ;
proto = MBytes.of_string header ; proto = MBytes.of_string header ;