Shell: add option --checkpoint
to tezos-node run
This commit is contained in:
parent
c16129a02d
commit
fc0af4a55f
@ -28,6 +28,7 @@ let with_node f =
|
|||||||
context_root = dir / "context" ;
|
context_root = dir / "context" ;
|
||||||
p2p = None ;
|
p2p = None ;
|
||||||
test_chain_max_tll = None ;
|
test_chain_max_tll = None ;
|
||||||
|
checkpoint = None ;
|
||||||
} in
|
} in
|
||||||
Node.create
|
Node.create
|
||||||
node_config
|
node_config
|
||||||
|
@ -90,7 +90,7 @@ let init_logger ?verbosity (log_config : Node_config_file.log) =
|
|||||||
end ;
|
end ;
|
||||||
Logging_unix.init ~template:log_config.template log_config.output
|
Logging_unix.init ~template:log_config.template log_config.output
|
||||||
|
|
||||||
let init_node ?sandbox (config : Node_config_file.t) =
|
let init_node ?sandbox ?checkpoint (config : Node_config_file.t) =
|
||||||
let patch_context json ctxt =
|
let patch_context json ctxt =
|
||||||
begin
|
begin
|
||||||
match json with
|
match json with
|
||||||
@ -181,6 +181,7 @@ let init_node ?sandbox (config : Node_config_file.t) =
|
|||||||
context_root = context_dir config.data_dir ;
|
context_root = context_dir config.data_dir ;
|
||||||
p2p = p2p_config ;
|
p2p = p2p_config ;
|
||||||
test_chain_max_tll = Some (48 * 3600) ; (* 2 days *)
|
test_chain_max_tll = Some (48 * 3600) ; (* 2 days *)
|
||||||
|
checkpoint ;
|
||||||
} in
|
} in
|
||||||
Node.create
|
Node.create
|
||||||
node_config
|
node_config
|
||||||
@ -242,7 +243,7 @@ let init_signal () =
|
|||||||
ignore (Lwt_unix.on_signal Sys.sigint (handler "INT") : Lwt_unix.signal_handler_id) ;
|
ignore (Lwt_unix.on_signal Sys.sigint (handler "INT") : Lwt_unix.signal_handler_id) ;
|
||||||
ignore (Lwt_unix.on_signal Sys.sigterm (handler "TERM") : Lwt_unix.signal_handler_id)
|
ignore (Lwt_unix.on_signal Sys.sigterm (handler "TERM") : Lwt_unix.signal_handler_id)
|
||||||
|
|
||||||
let run ?verbosity ?sandbox (config : Node_config_file.t) =
|
let run ?verbosity ?sandbox ?checkpoint (config : Node_config_file.t) =
|
||||||
Node_data_version.ensure_data_dir config.data_dir >>=? fun () ->
|
Node_data_version.ensure_data_dir config.data_dir >>=? fun () ->
|
||||||
Lwt_lock_file.create
|
Lwt_lock_file.create
|
||||||
~unlink_on_exit:true (lock_file config.data_dir) >>=? fun () ->
|
~unlink_on_exit:true (lock_file config.data_dir) >>=? fun () ->
|
||||||
@ -250,7 +251,7 @@ let run ?verbosity ?sandbox (config : Node_config_file.t) =
|
|||||||
init_logger ?verbosity config.log >>= fun () ->
|
init_logger ?verbosity config.log >>= fun () ->
|
||||||
Updater.init (protocol_dir config.data_dir) ;
|
Updater.init (protocol_dir config.data_dir) ;
|
||||||
lwt_log_notice "Starting the Tezos node..." >>= fun () ->
|
lwt_log_notice "Starting the Tezos node..." >>= fun () ->
|
||||||
init_node ?sandbox config >>=? fun node ->
|
init_node ?sandbox ?checkpoint config >>=? fun node ->
|
||||||
init_rpc config.rpc node >>=? fun rpc ->
|
init_rpc config.rpc node >>=? fun rpc ->
|
||||||
lwt_log_notice "The Tezos node is now running!" >>= fun () ->
|
lwt_log_notice "The Tezos node is now running!" >>= fun () ->
|
||||||
Lwt_exit.termination_thread >>= fun x ->
|
Lwt_exit.termination_thread >>= fun x ->
|
||||||
@ -262,7 +263,7 @@ let run ?verbosity ?sandbox (config : Node_config_file.t) =
|
|||||||
Logging_unix.close () >>= fun () ->
|
Logging_unix.close () >>= fun () ->
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
let process sandbox verbosity args =
|
let process sandbox verbosity checkpoint args =
|
||||||
let verbosity =
|
let verbosity =
|
||||||
match verbosity with
|
match verbosity with
|
||||||
| [] -> None
|
| [] -> None
|
||||||
@ -281,11 +282,29 @@ let process sandbox verbosity args =
|
|||||||
else return ()
|
else return ()
|
||||||
| None -> return ()
|
| None -> return ()
|
||||||
end >>=? fun () ->
|
end >>=? fun () ->
|
||||||
|
begin
|
||||||
|
match checkpoint with
|
||||||
|
| None -> return None
|
||||||
|
| Some s ->
|
||||||
|
match String.split ',' s with
|
||||||
|
| [ lvl ; block ] ->
|
||||||
|
Lwt.return (Block_hash.of_b58check block) >>=? fun block ->
|
||||||
|
begin
|
||||||
|
match Int32.of_string_opt lvl with
|
||||||
|
| None ->
|
||||||
|
failwith "... FIXME ..."
|
||||||
|
| Some lvl ->
|
||||||
|
return lvl
|
||||||
|
end >>=? fun lvl ->
|
||||||
|
return (Some (lvl, block))
|
||||||
|
| _ ->
|
||||||
|
failwith "... FIXME ..."
|
||||||
|
end >>=? fun checkpoint ->
|
||||||
Lwt_lock_file.is_locked
|
Lwt_lock_file.is_locked
|
||||||
(lock_file config.data_dir) >>=? function
|
(lock_file config.data_dir) >>=? function
|
||||||
| false ->
|
| false ->
|
||||||
Lwt.catch
|
Lwt.catch
|
||||||
(fun () -> run ?sandbox ?verbosity config)
|
(fun () -> run ?sandbox ?verbosity ?checkpoint config)
|
||||||
(function
|
(function
|
||||||
|Unix.Unix_error(Unix.EADDRINUSE, "bind","") ->
|
|Unix.Unix_error(Unix.EADDRINUSE, "bind","") ->
|
||||||
begin match config.rpc.listen_addr with
|
begin match config.rpc.listen_addr with
|
||||||
@ -327,8 +346,17 @@ module Term = struct
|
|||||||
info ~docs:Node_shared_arg.Manpage.misc_section
|
info ~docs:Node_shared_arg.Manpage.misc_section
|
||||||
~doc ~docv:"FILE.json" ["sandbox"])
|
~doc ~docv:"FILE.json" ["sandbox"])
|
||||||
|
|
||||||
|
let checkpoint =
|
||||||
|
let open Cmdliner in
|
||||||
|
let doc =
|
||||||
|
"..."
|
||||||
|
in
|
||||||
|
Arg.(value & opt (some string) None &
|
||||||
|
info ~docs:Node_shared_arg.Manpage.misc_section
|
||||||
|
~doc ~docv:"<level>,<block_hash>" ["checkpoint"])
|
||||||
|
|
||||||
let term =
|
let term =
|
||||||
Cmdliner.Term.(ret (const process $ sandbox $ verbosity $
|
Cmdliner.Term.(ret (const process $ sandbox $ verbosity $ checkpoint $
|
||||||
Node_shared_arg.Term.args))
|
Node_shared_arg.Term.args))
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -67,6 +67,7 @@ type config = {
|
|||||||
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_chain_max_tll: int option ;
|
test_chain_max_tll: int option ;
|
||||||
|
checkpoint: (Int32.t * Block_hash.t) option ;
|
||||||
}
|
}
|
||||||
|
|
||||||
and peer_validator_limits = Peer_validator.limits = {
|
and peer_validator_limits = Peer_validator.limits = {
|
||||||
@ -134,9 +135,19 @@ let default_chain_validator_limits = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let may_update_checkpoint chain_state checkpoint =
|
||||||
|
match checkpoint with
|
||||||
|
| None ->
|
||||||
|
Lwt.return_unit
|
||||||
|
| Some checkpoint ->
|
||||||
|
State.best_known_head_for_checkpoint
|
||||||
|
chain_state checkpoint >>= fun new_head ->
|
||||||
|
Chain.set_head chain_state new_head >>= fun _old_head ->
|
||||||
|
State.Chain.set_checkpoint chain_state checkpoint
|
||||||
|
|
||||||
let create { genesis ; store_root ; context_root ;
|
let create { genesis ; store_root ; context_root ;
|
||||||
patch_context ; p2p = p2p_params ;
|
patch_context ; p2p = p2p_params ;
|
||||||
test_chain_max_tll = max_child_ttl }
|
test_chain_max_tll = max_child_ttl ; checkpoint }
|
||||||
peer_validator_limits
|
peer_validator_limits
|
||||||
block_validator_limits
|
block_validator_limits
|
||||||
prevalidator_limits
|
prevalidator_limits
|
||||||
@ -148,6 +159,7 @@ let create { genesis ; store_root ; context_root ;
|
|||||||
init_p2p p2p_params >>=? fun p2p ->
|
init_p2p p2p_params >>=? fun p2p ->
|
||||||
State.read
|
State.read
|
||||||
~store_root ~context_root ?patch_context genesis >>=? fun (state, mainchain_state) ->
|
~store_root ~context_root ?patch_context genesis >>=? fun (state, mainchain_state) ->
|
||||||
|
may_update_checkpoint mainchain_state checkpoint >>= fun () ->
|
||||||
let distributed_db = Distributed_db.create state p2p in
|
let distributed_db = Distributed_db.create state p2p in
|
||||||
Validator.create state distributed_db
|
Validator.create state distributed_db
|
||||||
peer_validator_limits
|
peer_validator_limits
|
||||||
|
@ -16,6 +16,7 @@ type config = {
|
|||||||
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_chain_max_tll: int option ;
|
test_chain_max_tll: int option ;
|
||||||
|
checkpoint: (Int32.t * Block_hash.t) option ;
|
||||||
}
|
}
|
||||||
|
|
||||||
and peer_validator_limits = {
|
and peer_validator_limits = {
|
||||||
|
@ -643,6 +643,13 @@ module Block = struct
|
|||||||
else fail (Block_not_invalid block)
|
else fail (Block_not_invalid block)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let is_valid_for_checkpoint block checkpoint =
|
||||||
|
let chain_state = block.chain_state in
|
||||||
|
Shared.use chain_state.block_store begin fun store ->
|
||||||
|
Locked_block.is_valid_for_checkpoint
|
||||||
|
store block.hash block.contents.header checkpoint
|
||||||
|
end
|
||||||
|
|
||||||
let known chain_state hash =
|
let known chain_state hash =
|
||||||
Shared.use chain_state.block_store begin fun store ->
|
Shared.use chain_state.block_store begin fun store ->
|
||||||
Store.Block.Contents.known (store, hash) >>= fun known ->
|
Store.Block.Contents.known (store, hash) >>= fun known ->
|
||||||
@ -983,6 +990,54 @@ let fork_testchain block protocol expiration =
|
|||||||
return chain
|
return chain
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let best_known_head_for_checkpoint chain_state (level, _ as checkpoint) =
|
||||||
|
Shared.use chain_state.block_store begin fun store ->
|
||||||
|
Shared.use chain_state.chain_data begin fun data ->
|
||||||
|
let head_hash = data.data.current_head.hash in
|
||||||
|
let head_header = data.data.current_head.contents.header in
|
||||||
|
Locked_block.is_valid_for_checkpoint
|
||||||
|
store head_hash head_header checkpoint >>= fun valid ->
|
||||||
|
if valid then
|
||||||
|
Lwt.return data.data.current_head
|
||||||
|
else
|
||||||
|
let find_valid_predecessor hash =
|
||||||
|
Store.Block.Contents.read_exn
|
||||||
|
(store, hash) >>= fun contents ->
|
||||||
|
if Compare.Int32.(contents.header.shell.level < level) then
|
||||||
|
Lwt.return { hash ; contents ; chain_state }
|
||||||
|
else
|
||||||
|
predecessor_n store hash
|
||||||
|
(1 + (Int32.to_int @@
|
||||||
|
Int32.sub contents.header.shell.level level)) >>= function
|
||||||
|
| None -> assert false
|
||||||
|
| Some pred ->
|
||||||
|
Store.Block.Contents.read_exn
|
||||||
|
(store, pred) >>= fun pred_contents ->
|
||||||
|
Lwt.return { hash = pred ; contents = pred_contents ;
|
||||||
|
chain_state } in
|
||||||
|
Store.Chain_data.Known_heads.read_all
|
||||||
|
data.chain_data_store >>= fun heads ->
|
||||||
|
Store.Block.Contents.read_exn
|
||||||
|
(store, chain_state.genesis.block) >>= fun genesis_contents ->
|
||||||
|
let genesis =
|
||||||
|
{ hash = chain_state.genesis.block ;
|
||||||
|
contents = genesis_contents ;
|
||||||
|
chain_state } in
|
||||||
|
Block_hash.Set.fold
|
||||||
|
(fun head best ->
|
||||||
|
let valid_predecessor = find_valid_predecessor head in
|
||||||
|
best >>= fun best ->
|
||||||
|
valid_predecessor >>= fun pred ->
|
||||||
|
if Fitness.(pred.contents.header.shell.fitness >
|
||||||
|
best.contents.header.shell.fitness) then
|
||||||
|
Lwt.return pred
|
||||||
|
else
|
||||||
|
Lwt.return best)
|
||||||
|
heads
|
||||||
|
(Lwt.return genesis)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
module Protocol = struct
|
module Protocol = struct
|
||||||
|
|
||||||
include Protocol
|
include Protocol
|
||||||
|
@ -146,6 +146,8 @@ module Block : sig
|
|||||||
val predecessor: t -> block option Lwt.t
|
val predecessor: t -> block option Lwt.t
|
||||||
val predecessor_n: t -> int -> Block_hash.t option Lwt.t
|
val predecessor_n: t -> int -> Block_hash.t option Lwt.t
|
||||||
|
|
||||||
|
val is_valid_for_checkpoint: t -> (Int32.t * Block_hash.t) -> bool Lwt.t
|
||||||
|
|
||||||
val context: t -> Context.t Lwt.t
|
val context: t -> Context.t Lwt.t
|
||||||
val protocol_hash: t -> Protocol_hash.t Lwt.t
|
val protocol_hash: t -> Protocol_hash.t Lwt.t
|
||||||
val test_chain: t -> Test_chain_status.t Lwt.t
|
val test_chain: t -> Test_chain_status.t Lwt.t
|
||||||
@ -186,6 +188,13 @@ val read_block_exn:
|
|||||||
|
|
||||||
val watcher: t -> Block.t Lwt_stream.t * Lwt_watcher.stopper
|
val watcher: t -> Block.t Lwt_stream.t * Lwt_watcher.stopper
|
||||||
|
|
||||||
|
(** Computes the block with the best fitness amongst the known blocks
|
||||||
|
which are compatible with the given checkpoint. *)
|
||||||
|
val best_known_head_for_checkpoint:
|
||||||
|
Chain.t ->
|
||||||
|
Int32.t * Block_hash.t ->
|
||||||
|
Block.t Lwt.t
|
||||||
|
|
||||||
val compute_locator: Chain.t -> ?size:int -> Block.t -> Block_locator.seed -> Block_locator.t Lwt.t
|
val compute_locator: Chain.t -> ?size:int -> Block.t -> Block_locator.seed -> Block_locator.t Lwt.t
|
||||||
|
|
||||||
val fork_testchain:
|
val fork_testchain:
|
||||||
|
Loading…
Reference in New Issue
Block a user