Alpha/Baking: add minimal fees and wait for late endorsement

This commit is contained in:
Grégoire Henry 2018-11-22 20:37:38 +01:00
parent 56936c7a1e
commit 4b6f471ead
No known key found for this signature in database
GPG Key ID: 50D984F20BD445D2
12 changed files with 310 additions and 115 deletions

View File

@ -132,7 +132,7 @@ init_contract_from_file () {
} }
bake () { bake () {
$client bake for bootstrap1 --max-priority 512 --minimal-timestamp $client bake for bootstrap1 --max-priority 512 --minimal-timestamp --minimal-fees 0 --minimal-fees-per-byte 0 --minimal-fees-per-gas-unit 0
} }
bake_after () { bake_after () {

View File

@ -29,7 +29,7 @@ open Clic
type error += Bad_tez_arg of string * string (* Arg_name * value *) type error += Bad_tez_arg of string * string (* Arg_name * value *)
type error += Bad_max_priority of string type error += Bad_max_priority of string
type error += Bad_fee_threshold of string type error += Bad_minimal_fees of string
type error += Bad_max_waiting_time of string type error += Bad_max_waiting_time of string
type error += Bad_endorsement_delay of string type error += Bad_endorsement_delay of string
type error += Bad_preserved_levels of string type error += Bad_preserved_levels of string
@ -61,14 +61,14 @@ let () =
(fun parameter -> Bad_max_priority parameter) ; (fun parameter -> Bad_max_priority parameter) ;
register_error_kind register_error_kind
`Permanent `Permanent
~id:"badFeeThresholdArg" ~id:"badMinimalFeesArg"
~title:"Bad -fee-threshold arg" ~title:"Bad -minimal-fees arg"
~description:("invalid fee threshold in -fee-threshold") ~description:("invalid fee threshold in -fee-threshold")
~pp:(fun ppf literal -> ~pp:(fun ppf literal ->
Format.fprintf ppf "invalid fee threshold '%s' in -fee-threshold" literal) Format.fprintf ppf "invalid minimal fees '%s'" literal)
Data_encoding.(obj1 (req "parameter" string)) Data_encoding.(obj1 (req "parameter" string))
(function Bad_fee_threshold parameter -> Some parameter | _ -> None) (function Bad_minimal_fees parameter -> Some parameter | _ -> None)
(fun parameter -> Bad_fee_threshold parameter) ; (fun parameter -> Bad_minimal_fees parameter) ;
register_error_kind register_error_kind
`Permanent `Permanent
~id:"badMaxWaitingTimeArg" ~id:"badMaxWaitingTimeArg"
@ -246,30 +246,47 @@ let max_priority_arg =
try return (int_of_string s) try return (int_of_string s)
with _ -> fail (Bad_max_priority s))) with _ -> fail (Bad_max_priority s)))
let fee_threshold_arg = let minimal_fees_arg =
arg arg
~long:"fee-threshold" ~long:"minimal-fees"
~placeholder:"amount" ~placeholder:"amount"
~doc:"exclude operations with fees lower than this threshold (in tz)" ~doc:"exclude operations with fees lower than this threshold (in tez)"
(parameter (fun _ s -> (parameter (fun _ s ->
match Tez.of_string s with match Tez.of_string s with
| Some t -> return t | Some t -> return t
| None -> fail (Bad_fee_threshold s))) | None -> fail (Bad_minimal_fees s)))
let max_waiting_time_arg = let minimal_fees_per_gas_unit_arg =
default_arg arg
~long:"max-waiting-time" ~long:"minimal-fees-per-gas-unit"
~placeholder:"seconds" ~placeholder:"amount"
~doc:"Specify how long the baker is allowed to wait late \ ~doc:"exclude operations with fees per gas lower than this threshold (in tez)"
endorsements (if necessary) after its delegate's injection \
date."
~default:"25"
(parameter (fun _ s -> (parameter (fun _ s ->
try match Tez.of_string s with
let i = int_of_string s in | Some t -> return t
fail_when (i < 0) (Bad_max_waiting_time s) >>=? fun () -> | None -> fail (Bad_minimal_fees s)))
return (int_of_string s)
with _ -> fail (Bad_max_waiting_time s))) let minimal_fees_per_byte_arg =
arg
~long:"minimal-fees-per-byte"
~placeholder:"amount"
~doc:"exclude operations with fees per byte lower than this threshold (in tez)"
(parameter (fun _ s ->
match Tez.of_string s with
| Some t -> return t
| None -> fail (Bad_minimal_fees s)))
let no_waiting_for_endorsements_arg =
switch
~long:"no-waiting-for-late-endorsements"
~doc:"Disable waiting for late endorsements"
()
let await_endorsements_arg =
switch
~long:"await-late-endorsements"
~doc:"Await late endorsements when baking a block"
()
let endorsement_delay_arg = let endorsement_delay_arg =
default_arg default_arg
@ -278,7 +295,7 @@ let endorsement_delay_arg =
~doc:"delay before endorsing blocks\n\ ~doc:"delay before endorsing blocks\n\
Delay between notifications of new blocks from the node and \ Delay between notifications of new blocks from the node and \
production of endorsements for these blocks." production of endorsements for these blocks."
~default:"15" ~default:"5"
(parameter (fun _ s -> (parameter (fun _ s ->
try try
let i = int_of_string s in let i = int_of_string s in

View File

@ -40,8 +40,11 @@ val delegate_arg: (Signature.Public_key_hash.t option, Proto_alpha.full) Clic.ar
val delegatable_switch: (bool, Proto_alpha.full) Clic.arg val delegatable_switch: (bool, Proto_alpha.full) Clic.arg
val spendable_switch: (bool, Proto_alpha.full) Clic.arg val spendable_switch: (bool, Proto_alpha.full) Clic.arg
val max_priority_arg: (int option, Proto_alpha.full) Clic.arg val max_priority_arg: (int option, Proto_alpha.full) Clic.arg
val fee_threshold_arg: (Tez.tez option, Proto_alpha.full) Clic.arg val minimal_fees_arg: (Tez.tez option, Proto_alpha.full) Clic.arg
val max_waiting_time_arg: (int, Proto_alpha.full) Clic.arg val minimal_fees_per_gas_unit_arg: (Tez.tez option, Proto_alpha.full) Clic.arg
val minimal_fees_per_byte_arg: (Tez.tez option, Proto_alpha.full) Clic.arg
val no_waiting_for_endorsements_arg: (bool, Proto_alpha.full) Clic.arg
val await_endorsements_arg: (bool, Proto_alpha.full) Clic.arg
val force_switch: (bool, Proto_alpha.full) Clic.arg val force_switch: (bool, Proto_alpha.full) Clic.arg
val minimal_timestamp_switch: (bool, Proto_alpha.full) Clic.arg val minimal_timestamp_switch: (bool, Proto_alpha.full) Clic.arg
val endorsement_delay_arg: (int, Proto_alpha.full) Clic.arg val endorsement_delay_arg: (int, Proto_alpha.full) Clic.arg

View File

@ -40,6 +40,11 @@ let anonymous_index = 2
let managers_index = 3 let managers_index = 3
let default_max_priority = 64 let default_max_priority = 64
let default_minimal_fees = Tez.zero
let default_minimal_fees_per_gas_unit =
Option.unopt_exn (Failure "bad conversion") (Tez.of_mutez 10L)
let default_minimal_fees_per_byte = Tez.zero
let default_await_endorsements = true
type state = { type state = {
genesis: Block_hash.t ; genesis: Block_hash.t ;
@ -49,25 +54,33 @@ type state = {
delegates: public_key_hash list ; delegates: public_key_hash list ;
(* lazy-initialisation with retry-on-error *) (* lazy-initialisation with retry-on-error *)
constants: Constants.t tzlazy ; constants: Constants.t tzlazy ;
(* Minimum operation fee required to include in a block *) (* Minimal operation fee required to include an operation in a block *)
fee_threshold : Tez.t ; minimal_fees : Tez.t ;
(* Maximum waiting time allowed for late endorsements *) (* Minimal operation fee per gas required to include an operation in a block *)
max_waiting_time : int ; minimal_fees_per_gas_unit : Tez.t ;
(* Minimal operation fee per byte required to include an operation in a block *)
minimal_fees_per_byte : Tez.t ;
(* Await endorsements *)
await_endorsements: bool ;
(* truly mutable *) (* truly mutable *)
mutable best_slot: (Time.t * (Client_baking_blocks.block_info * int * public_key_hash)) option ; mutable best_slot: (Time.t * (Client_baking_blocks.block_info * int * public_key_hash)) option ;
} }
let create_state let create_state
?(fee_threshold = Tez.zero) ~max_waiting_time ?(minimal_fees = default_minimal_fees)
genesis context_path index ?(minimal_fees_per_gas_unit = default_minimal_fees_per_gas_unit)
delegates constants = ?(minimal_fees_per_byte = default_minimal_fees_per_byte)
?(await_endorsements = default_await_endorsements)
genesis context_path index delegates constants =
{ genesis ; { genesis ;
context_path ; context_path ;
index ; index ;
delegates ; delegates ;
constants ; constants ;
fee_threshold ; minimal_fees ;
max_waiting_time ; minimal_fees_per_gas_unit ;
minimal_fees_per_byte ;
await_endorsements ;
best_slot = None ; best_slot = None ;
} }
@ -140,8 +153,7 @@ let inject_block
?force ~chain signed_header operations >>=? fun block_hash -> ?force ~chain signed_header operations >>=? fun block_hash ->
return block_hash return block_hash
type error += type error += Failed_to_preapply of Tezos_base.Operation.t * error list
| Failed_to_preapply of Tezos_base.Operation.t * error list
let () = let () =
register_error_kind register_error_kind
@ -179,7 +191,9 @@ let get_manager_operation_gas_and_fee op =
let sort_manager_operations let sort_manager_operations
~max_size ~max_size
~hard_gas_limit_per_block ~hard_gas_limit_per_block
~fee_threshold ~minimal_fees
~minimal_fees_per_gas_unit
~minimal_fees_per_byte
(operations : Proto_alpha.operation list) = (operations : Proto_alpha.operation list) =
let compute_weight op (fee, gas) = let compute_weight op (fee, gas) =
let size = Data_encoding.Binary.length Operation.encoding op in let size = Data_encoding.Binary.length Operation.encoding op in
@ -193,10 +207,23 @@ let sort_manager_operations
filter_map_s filter_map_s
(fun op -> (fun op ->
get_manager_operation_gas_and_fee op >>=? fun (fee, gas) -> get_manager_operation_gas_and_fee op >>=? fun (fee, gas) ->
if Tez.(<) fee fee_threshold then if Tez.(fee < minimal_fees) then
return_none return_none
else else
return (Some (op, (compute_weight op (fee, gas)))) let (size, gas, _ratio) as weight = compute_weight op (fee, gas) in
let open Alpha_environment in
let enough_gas_fees =
match Tez.(minimal_fees_per_gas_unit *? Z.to_int64 gas) with
| Ok expected_fees -> Tez.(expected_fees <= fee)
| _ -> false in
let enough_size_fees =
match Tez.(minimal_fees_per_byte *? Int64.of_int size) with
| Ok fee_per_byte -> Tez.(fee_per_byte >= minimal_fees_per_byte)
| Error _ -> false in
if enough_size_fees && enough_gas_fees then
return_some (op, weight)
else
return_none
) operations >>=? fun operations -> ) operations >>=? fun operations ->
(* We sort by the biggest weight *) (* We sort by the biggest weight *)
return return
@ -255,7 +282,9 @@ let classify_operations
(cctxt : #Proto_alpha.full) (cctxt : #Proto_alpha.full)
~block ~block
~hard_gas_limit_per_block ~hard_gas_limit_per_block
~fee_threshold ~minimal_fees
~minimal_fees_per_gas_unit
~minimal_fees_per_byte
(ops: Proto_alpha.operation list) = (ops: Proto_alpha.operation list) =
Alpha_block_services.live_blocks cctxt ~chain:`Main ~block () Alpha_block_services.live_blocks cctxt ~chain:`Main ~block ()
>>=? fun live_blocks -> >>=? fun live_blocks ->
@ -278,7 +307,13 @@ let classify_operations
let manager_operations = t.(managers_index) in let manager_operations = t.(managers_index) in
let { Alpha_environment.Updater.max_size } = let { Alpha_environment.Updater.max_size } =
List.nth Proto_alpha.Main.validation_passes managers_index in List.nth Proto_alpha.Main.validation_passes managers_index in
sort_manager_operations ~max_size ~hard_gas_limit_per_block ~fee_threshold manager_operations sort_manager_operations
~max_size
~hard_gas_limit_per_block
~minimal_fees
~minimal_fees_per_gas_unit
~minimal_fees_per_byte
manager_operations
>>=? fun ordered_operations -> >>=? fun ordered_operations ->
(* Greedy heuristic *) (* Greedy heuristic *)
trim_manager_operations ~max_size ~hard_gas_limit_per_block (List.map fst ordered_operations) trim_manager_operations ~max_size ~hard_gas_limit_per_block (List.map fst ordered_operations)
@ -430,14 +465,15 @@ let filter_and_apply_operations
let validate_operation inc op = let validate_operation inc op =
add_operation inc op >>= function add_operation inc op >>= function
| Error errs -> | Error errs ->
lwt_log_info Tag.DSL.(fun f -> lwt_debug Tag.DSL.(fun f ->
f "Client-side validation: invalid operation filtered %a\n@[<v 4>%a@]" f "Client-side validation: invalid operation filtered %a\n@[<v 4>%a@]"
-% t event "baking_rejected_invalid_operation" -% t event "baking_rejected_invalid_operation"
-% a Operation_hash.Logging.tag (Operation.hash_packed op) -% a Operation_hash.Logging.tag (Operation.hash_packed op)
-% a errs_tag errs) -% a errs_tag errs)
>>= fun () -> >>= fun () ->
return_none return_none
| Ok inc -> return_some inc | Ok (resulting_state, _receipt) ->
return_some resulting_state
in in
let filter_valid_operations inc ops = let filter_valid_operations inc ops =
fold_left_s (fun (inc, acc) op -> fold_left_s (fun (inc, acc) op ->
@ -493,7 +529,9 @@ let filter_and_apply_operations
filter_valid_operations inc accepted_managers >>=? fun (inc, accepted_managers) -> filter_valid_operations inc accepted_managers >>=? fun (inc, accepted_managers) ->
filter_map_s (is_valid_endorsement inc) endorsements >>=? fun endorsements -> filter_map_s (is_valid_endorsement inc) endorsements >>=? fun endorsements ->
(* Endorsements won't fail now *) (* Endorsements won't fail now *)
fold_left_s add_operation inc endorsements >>=? fun inc -> fold_left_s (fun inc op ->
add_operation inc op >>=? fun (inc, _receipt) ->
return inc) inc endorsements >>=? fun inc ->
(* Endorsement and double baking/endorsement evidence do not commute: (* Endorsement and double baking/endorsement evidence do not commute:
we apply denunciation operations after endorsements. *) we apply denunciation operations after endorsements. *)
filter_valid_operations inc evidences >>=? fun (final_inc, evidences) -> filter_valid_operations inc evidences >>=? fun (final_inc, evidences) ->
@ -535,7 +573,10 @@ let forge_block
?operations ?operations
?(best_effort = operations = None) ?(best_effort = operations = None)
?(sort = best_effort) ?(sort = best_effort)
?(fee_threshold = Tez.zero) ?(minimal_fees = default_minimal_fees)
?(minimal_fees_per_gas_unit = default_minimal_fees_per_gas_unit)
?(minimal_fees_per_byte = default_minimal_fees_per_byte)
?(await_endorsements = default_await_endorsements)
?timestamp ?timestamp
?mempool ?mempool
?context_path ?context_path
@ -552,7 +593,14 @@ let forge_block
let protocol_data = forge_faked_protocol_data ~priority ~seed_nonce_hash in let protocol_data = forge_faked_protocol_data ~priority ~seed_nonce_hash in
Alpha_services.Constants.all cctxt (`Main, block) >>=? Alpha_services.Constants.all cctxt (`Main, block) >>=?
fun Constants.{ parametric = { hard_gas_limit_per_block ; endorsers_per_block } } -> fun Constants.{ parametric = { hard_gas_limit_per_block ; endorsers_per_block } } ->
classify_operations cctxt ~hard_gas_limit_per_block ~block:block ~fee_threshold operations_arg classify_operations
cctxt
~hard_gas_limit_per_block
~block:block
~minimal_fees
~minimal_fees_per_gas_unit
~minimal_fees_per_byte
operations_arg
>>=? fun (operations, overflowing_ops) -> >>=? fun (operations, overflowing_ops) ->
(* Ensure that we retain operations up to the quota *) (* Ensure that we retain operations up to the quota *)
let quota : Alpha_environment.Updater.quota list = Main.validation_passes in let quota : Alpha_environment.Updater.quota list = Main.validation_passes in
@ -599,8 +647,10 @@ let forge_block
constants = tzlazy (fun () -> Alpha_services.Constants.all cctxt (`Main, `Head 0)) ; constants = tzlazy (fun () -> Alpha_services.Constants.all cctxt (`Main, `Head 0)) ;
delegates = [] ; delegates = [] ;
best_slot = None ; best_slot = None ;
max_waiting_time = 0 ; await_endorsements ;
fee_threshold = Tez.zero ; minimal_fees = default_minimal_fees ;
minimal_fees_per_gas_unit = default_minimal_fees_per_gas_unit ;
minimal_fees_per_byte = default_minimal_fees_per_byte ;
} in } in
filter_and_apply_operations ~timestamp ~protocol_data state bi (operations, overflowing_ops) filter_and_apply_operations ~timestamp ~protocol_data state bi (operations, overflowing_ops)
>>=? fun (final_context, validation_result, operations) -> >>=? fun (final_context, validation_result, operations) ->
@ -649,6 +699,59 @@ let shell_prevalidation
return return
(Some (bi, priority, shell_header, raw_ops, delegate, seed_nonce_hash)) (Some (bi, priority, shell_header, raw_ops, delegate, seed_nonce_hash))
let filter_outdated_endorsements expected_level ops =
List.filter (function
| { Alpha_context.protocol_data =
Operation_data { contents = Single (Endorsement { level }) }} ->
Raw_level.equal expected_level level
| _ -> true
) ops
let next_baking_delay state priority =
tzforce state.constants >>=? fun { Constants.parametric = { time_between_blocks }} ->
let rec associated_period durations prio =
if List.length durations = 0 then
(* Mimic [Baking.minimal_time] behaviour *)
associated_period [ Period.one_minute ] prio
else
match durations with
| [] -> assert false
| [ last ] ->
Period.to_seconds last
| first :: durations ->
if prio = 0 then
Period.to_seconds first
else
associated_period durations (prio - 1)
in
let span = associated_period time_between_blocks (priority + 1) in
return span
let count_slots_endorsements inc (_timestamp, (head, _priority, _delegate)) operations =
fold_left_s (fun acc -> function
| { Alpha_context.protocol_data =
Operation_data { contents = Single (Endorsement { level }) }} as op
when Raw_level.(level = head.Client_baking_blocks.level) ->
begin
let open Apply_results in
Client_baking_simulator.add_operation inc op >>= function
| Ok (_inc,
Operation_metadata
{ contents = Single_result (Endorsement_result { slots })} ) ->
return (acc + List.length slots)
| Error _ | _ ->
(* We do not handle errors here *)
return acc
end
| _ -> return acc
) 0 operations
let rec filter_limits tnow limits =
match limits with
| [] -> []
| (time, _) :: _ as limits when Time.(tnow < time) -> limits
| _ :: limits -> filter_limits tnow limits
(** [fetch_operations] retrieve the operations present in the (** [fetch_operations] retrieve the operations present in the
mempool. If no endorsements are present in the initial set, it mempool. If no endorsements are present in the initial set, it
waits until [state.max_waiting_time] seconds after its injection range start date. *) waits until [state.max_waiting_time] seconds after its injection range start date. *)
@ -656,7 +759,7 @@ let fetch_operations
(cctxt : #Proto_alpha.full) (cctxt : #Proto_alpha.full)
~chain ~chain
state state
(timestamp, (head, _, _delegate)) (timestamp, (head, priority, _delegate) as slot)
= =
Alpha_block_services.Mempool.monitor_operations cctxt ~chain Alpha_block_services.Mempool.monitor_operations cctxt ~chain
~applied:true ~branch_delayed:true ~applied:true ~branch_delayed:true
@ -666,28 +769,36 @@ let fetch_operations
| None -> (* New head received : not supposed to happen. *) | None -> (* New head received : not supposed to happen. *)
return_none return_none
| Some current_mempool -> | Some current_mempool ->
let operations = ref current_mempool in let operations = ref (filter_outdated_endorsements head.Client_baking_blocks.level current_mempool) in
let head_level = head.Client_baking_blocks.level in Client_baking_simulator.begin_construction ~timestamp state.index head >>=? fun inc ->
let contains_head_endorsements operations = count_slots_endorsements inc slot !operations >>=? fun nb_arrived_endorsements ->
List.exists (function tzforce state.constants >>=? fun { Constants.parametric = { endorsers_per_block }} ->
| { Alpha_context.protocol_data = (* If 100% of the endorsements arrived, we don't need to wait *)
Operation_data { contents = Single (Endorsement { level }) }} -> if (not state.await_endorsements) || nb_arrived_endorsements = endorsers_per_block then
Raw_level.(level = head_level) return_some !operations
| _ -> false
) operations in
(* If the list already contains valid endorsements, we do not
need to wait. *)
if contains_head_endorsements !operations then
return (Some !operations)
else else
(* Wait 1/3 of the allocated time *) next_baking_delay state priority >>=? fun next_slot_delay ->
let limit_date = Time.add timestamp (Int64.of_int state.max_waiting_time) in let hard_delay = Int64.div next_slot_delay 2L in
(* The time limit is defined as 1/2 of the next baking slot's time *)
let limit_date = Time.add timestamp hard_delay in
(* Time limits :
- We expect all of the endorsements until 1/3 of the time limit has passed ;
- We expect 2/3 of the endorsements until 2/3 of the time limit has passed ;
- We expect 1/3 of the endorsements until the time limit has passed ;
- We bake with what we have when the time limit has been reached.
*)
let limits =
[ (Time.add timestamp (Int64.div hard_delay 3L), endorsers_per_block) ;
(Time.add timestamp (Int64.div (Int64.mul hard_delay 2L) 3L), 2 * endorsers_per_block / 3) ;
(limit_date, endorsers_per_block / 3) ]
in
lwt_log_notice Tag.DSL.(fun f -> lwt_log_notice Tag.DSL.(fun f ->
f "No endorsements present in the mempool. Waiting until %a (%a) for new operations." f "No endorsements present in the mempool. Waiting until %a (%a) for new operations."
-% t event "waiting_operations" -% t event "waiting_operations"
-% a timestamp_tag limit_date -% a timestamp_tag limit_date
-% a timespan_tag (max 0L Time.(diff limit_date (now ()))) -% a timespan_tag (max 0L Time.(diff limit_date (now ())))
) >>= fun () -> ) >>= fun () ->
Shell_services.Mempool.request_operations cctxt ~chain () >>=? fun () ->
let timeout = match Client_baking_scheduling.sleep_until limit_date with let timeout = match Client_baking_scheduling.sleep_until limit_date with
| None -> Lwt.return_unit | None -> Lwt.return_unit
| Some timeout -> timeout in | Some timeout -> timeout in
@ -699,20 +810,33 @@ let fetch_operations
last_get_event := Some t ; last_get_event := Some t ;
t t
| Some t -> t in | Some t -> t in
let rec loop () = let rec loop nb_arrived_endorsements limits =
Lwt.choose [ (timeout >|= fun () -> `Timeout) ; Lwt.choose [ (timeout >|= fun () -> `Timeout) ;
(get_event () >|= fun e -> `Event e) ; ] (get_event () >|= fun e -> `Event e) ; ]
>>= function >>= function
| `Event (Some op_list) -> begin | `Event (Some op_list) -> begin
last_get_event := None ; last_get_event := None ;
operations := op_list @ !operations ; operations := op_list @ !operations ;
loop () end count_slots_endorsements inc slot op_list >>=? fun new_endorsements ->
let nb_arrived_endorsements = nb_arrived_endorsements + new_endorsements in
let limits = filter_limits (Time.now ()) limits in
let required =
match limits with
| [] -> 0 (* If we are late, we do not require endorsements *)
| (_time, required) :: _ -> required in
let enough = nb_arrived_endorsements >= required in
if enough then
return_some !operations
else
loop nb_arrived_endorsements limits
end
| `Timeout -> return_some !operations | `Timeout -> return_some !operations
| `Event None -> | `Event None ->
(* New head received : should not happen. *) (* New head received. Should not happen : let the
caller handle this case. *)
return_none return_none
in in
loop () loop nb_arrived_endorsements limits
(** Given a delegate baking slot [build_block] constructs a full block (** Given a delegate baking slot [build_block] constructs a full block
with consistent operations that went through the client-side with consistent operations that went through the client-side
@ -751,11 +875,15 @@ let build_block
lwt_log_info Tag.DSL.(fun f -> lwt_log_info Tag.DSL.(fun f ->
f "Received a new head while waiting for operations. Aborting this block." f "Received a new head while waiting for operations. Aborting this block."
-% t event "new_head_received") >>= fun () -> -% t event "new_head_received") >>= fun () ->
return None return_none
| Some operations -> | Some operations ->
tzforce state.constants >>=? fun Constants.{ parametric = { hard_gas_limit_per_block } } -> tzforce state.constants >>=? fun Constants.{ parametric = { hard_gas_limit_per_block } } ->
classify_operations cctxt classify_operations cctxt
~hard_gas_limit_per_block ~fee_threshold:state.fee_threshold ~block operations ~hard_gas_limit_per_block
~minimal_fees:state.minimal_fees
~minimal_fees_per_gas_unit:state.minimal_fees_per_gas_unit
~minimal_fees_per_byte:state.minimal_fees_per_byte
~block operations
>>=? fun (operations, overflowing_ops) -> >>=? fun (operations, overflowing_ops) ->
let next_version = let next_version =
match Tezos_base.Block_header.get_forced_protocol_upgrade ~level:(Raw_level.to_int32 next_level.Level.level) with match Tezos_base.Block_header.get_forced_protocol_upgrade ~level:(Raw_level.to_int32 next_level.Level.level) with
@ -1029,9 +1157,11 @@ let reveal_potential_nonces cctxt new_head =
the [delegates] *) the [delegates] *)
let create let create
(cctxt : #Proto_alpha.full) (cctxt : #Proto_alpha.full)
?fee_threshold ?minimal_fees
?minimal_fees_per_gas_unit
?minimal_fees_per_byte
?await_endorsements
?max_priority ?max_priority
~max_waiting_time
~context_path ~context_path
delegates delegates
block_stream = block_stream =
@ -1040,7 +1170,10 @@ let create
tzlazy (fun () -> Alpha_services.Constants.all cctxt (`Main, `Hash (bi.Client_baking_blocks.hash, 0))) in tzlazy (fun () -> Alpha_services.Constants.all cctxt (`Main, `Hash (bi.Client_baking_blocks.hash, 0))) in
Client_baking_simulator.load_context ~context_path >>= fun index -> Client_baking_simulator.load_context ~context_path >>= fun index ->
Client_baking_simulator.check_context_consistency index bi.context >>=? fun () -> Client_baking_simulator.check_context_consistency index bi.context >>=? fun () ->
let state = create_state ?fee_threshold ~max_waiting_time genesis_hash context_path index delegates constants in let state = create_state
?minimal_fees ?minimal_fees_per_gas_unit ?minimal_fees_per_byte
?await_endorsements
genesis_hash context_path index delegates constants in
return state return state
in in

View File

@ -71,7 +71,10 @@ val forge_block:
?operations: Operation.packed list -> ?operations: Operation.packed list ->
?best_effort:bool -> ?best_effort:bool ->
?sort:bool -> ?sort:bool ->
?fee_threshold:Tez.t -> ?minimal_fees: Tez.t ->
?minimal_fees_per_gas_unit: Tez.t ->
?minimal_fees_per_byte: Tez.t ->
?await_endorsements: bool ->
?timestamp:Time.t -> ?timestamp:Time.t ->
?mempool:string -> ?mempool:string ->
?context_path:string -> ?context_path:string ->
@ -103,9 +106,11 @@ val forge_block:
val create: val create:
#Proto_alpha.full -> #Proto_alpha.full ->
?fee_threshold:Tez.t -> ?minimal_fees: Tez.t ->
?minimal_fees_per_gas_unit: Tez.t ->
?minimal_fees_per_byte: Tez.t ->
?await_endorsements: bool ->
?max_priority: int -> ?max_priority: int ->
max_waiting_time: int ->
context_path: string -> context_path: string ->
public_key_hash list -> public_key_hash list ->
Client_baking_blocks.block_info tzresult Lwt_stream.t -> Client_baking_blocks.block_info tzresult Lwt_stream.t ->

View File

@ -29,7 +29,10 @@ open Alpha_context
let bake_block let bake_block
(cctxt : #Proto_alpha.full) (cctxt : #Proto_alpha.full)
?(chain = `Main) ?(chain = `Main)
?fee_threshold ?minimal_fees
?minimal_fees_per_gas_unit
?minimal_fees_per_byte
?(await_endorsements = false)
?force ?force
?max_priority ?max_priority
?(minimal_timestamp = false) ?(minimal_timestamp = false)
@ -63,9 +66,12 @@ let bake_block
else else
None, None in None, None in
Client_baking_forge.forge_block cctxt Client_baking_forge.forge_block cctxt
?timestamp:(if minimal_timestamp then None else Some (Time.now ()))
?fee_threshold
?force ?force
?minimal_fees
?minimal_fees_per_gas_unit
?minimal_fees_per_byte
~await_endorsements
?timestamp:(if minimal_timestamp then None else Some (Time.now ()))
?seed_nonce_hash ?seed_nonce_hash
?mempool ?mempool
?context_path ?context_path

View File

@ -30,7 +30,10 @@ open Alpha_context
val bake_block: val bake_block:
#Proto_alpha.full -> #Proto_alpha.full ->
?chain:Chain_services.chain -> ?chain:Chain_services.chain ->
?fee_threshold:Tez.t -> ?minimal_fees: Tez.t ->
?minimal_fees_per_gas_unit: Tez.t ->
?minimal_fees_per_byte: Tez.t ->
?await_endorsements: bool ->
?force:bool -> ?force:bool ->
?max_priority: int -> ?max_priority: int ->
?minimal_timestamp: bool -> ?minimal_timestamp: bool ->

View File

@ -109,8 +109,8 @@ let begin_construction ~timestamp ?protocol_data index predecessor =
} }
let add_operation st ( op : Operation.packed ) = let add_operation st ( op : Operation.packed ) =
LiftedMain.apply_operation st.state op >>=? fun (state, _) -> LiftedMain.apply_operation st.state op >>=? fun (state, receipt) ->
return { st with state ; rev_operations = op :: st.rev_operations } return ({ st with state ; rev_operations = op :: st.rev_operations }, receipt)
let finalize_construction inc = let finalize_construction inc =
LiftedMain.finalize_block inc.state LiftedMain.finalize_block inc.state

View File

@ -41,6 +41,6 @@ val check_context_consistency : Context.index -> Context_hash.t -> unit tzresult
val begin_construction : timestamp:Time.t -> ?protocol_data: block_header_data -> Context.index -> Client_baking_blocks.block_info -> incremental tzresult Lwt.t val begin_construction : timestamp:Time.t -> ?protocol_data: block_header_data -> Context.index -> Client_baking_blocks.block_info -> incremental tzresult Lwt.t
val add_operation : incremental -> Operation.packed -> incremental tzresult Lwt.t val add_operation : incremental -> Operation.packed -> (incremental * LiftedMain.operation_receipt) tzresult Lwt.t
val finalize_construction : incremental -> (T.validation_result * LiftedMain.block_header_metadata) tzresult Lwt.t val finalize_construction : incremental -> (T.validation_result * LiftedMain.block_header_metadata) tzresult Lwt.t

View File

@ -33,14 +33,13 @@ let await_bootstrapped_node (cctxt: #Proto_alpha.full) =
module Endorser = struct module Endorser = struct
let run (cctxt : #Proto_alpha.full) ~delay ?min_date delegates = let run (cctxt : #Proto_alpha.full) ~delay delegates =
await_bootstrapped_node cctxt >>=? fun _ -> await_bootstrapped_node cctxt >>=? fun _ ->
Client_baking_blocks.monitor_heads Client_baking_blocks.monitor_heads
~next_protocols:(Some [Proto_alpha.hash]) ~next_protocols:(Some [Proto_alpha.hash])
cctxt `Main >>=? fun block_stream -> cctxt `Main >>=? fun block_stream ->
cctxt#message "Endorser started." >>= fun () -> cctxt#message "Endorser started." >>= fun () ->
Client_baking_endorsement.create cctxt ~delay delegates block_stream >>=? fun () -> Client_baking_endorsement.create cctxt ~delay delegates block_stream >>=? fun () ->
ignore min_date;
return_unit return_unit
end end
@ -49,11 +48,12 @@ module Baker = struct
let run let run
(cctxt : #Proto_alpha.full) (cctxt : #Proto_alpha.full)
?fee_threshold ?minimal_fees
?minimal_fees_per_gas_unit
?minimal_fees_per_byte
?await_endorsements
?max_priority ?max_priority
?min_date
~context_path ~context_path
~max_waiting_time
delegates = delegates =
await_bootstrapped_node cctxt >>=? fun _ -> await_bootstrapped_node cctxt >>=? fun _ ->
Client_baking_blocks.monitor_heads Client_baking_blocks.monitor_heads
@ -61,8 +61,12 @@ module Baker = struct
cctxt `Main >>=? fun block_stream -> cctxt `Main >>=? fun block_stream ->
cctxt#message "Baker started." >>= fun () -> cctxt#message "Baker started." >>= fun () ->
Client_baking_forge.create cctxt Client_baking_forge.create cctxt
?fee_threshold ?max_priority ~max_waiting_time ~context_path delegates block_stream >>=? fun () -> ?minimal_fees
ignore min_date; ?minimal_fees_per_gas_unit
?minimal_fees_per_byte
?await_endorsements
?max_priority
~context_path delegates block_stream >>=? fun () ->
return_unit return_unit
end end

View File

@ -30,18 +30,18 @@ module Endorser : sig
val run: val run:
#Proto_alpha.full -> #Proto_alpha.full ->
delay: int -> delay: int ->
?min_date: Time.t ->
public_key_hash list -> unit tzresult Lwt.t public_key_hash list -> unit tzresult Lwt.t
end end
module Baker : sig module Baker : sig
val run: val run:
#Proto_alpha.full -> #Proto_alpha.full ->
?fee_threshold: Tez.tez -> ?minimal_fees: Tez.t ->
?minimal_fees_per_gas_unit: Tez.t ->
?minimal_fees_per_byte: Tez.t ->
?await_endorsements: bool ->
?max_priority: int -> ?max_priority: int ->
?min_date: Time.t ->
context_path: string -> context_path: string ->
max_waiting_time: int ->
public_key_hash list -> unit tzresult Lwt.t public_key_hash list -> unit tzresult Lwt.t
end end

View File

@ -55,14 +55,31 @@ let delegate_commands () =
let open Clic in let open Clic in
[ [
command ~group ~desc: "Forge and inject block using the delegate rights." command ~group ~desc: "Forge and inject block using the delegate rights."
(args6 max_priority_arg fee_threshold_arg force_switch minimal_timestamp_switch mempool_arg context_path_arg) (args9
max_priority_arg
minimal_fees_arg
minimal_fees_per_gas_unit_arg
minimal_fees_per_byte_arg
await_endorsements_arg
force_switch
minimal_timestamp_switch
mempool_arg
context_path_arg)
(prefixes [ "bake"; "for" ] (prefixes [ "bake"; "for" ]
@@ Client_keys.Public_key_hash.source_param @@ Client_keys.Public_key_hash.source_param
~name:"baker" ~desc: "name of the delegate owning the baking right" ~name:"baker" ~desc: "name of the delegate owning the baking right"
@@ stop) @@ stop)
(fun (max_priority, fee_threshold, force, minimal_timestamp, mempool, context_path) delegate cctxt -> (fun (max_priority, minimal_fees,
minimal_fees_per_gas_unit, minimal_fees_per_byte,
await_endorsements, force,
minimal_timestamp, mempool, context_path)
delegate cctxt ->
bake_block cctxt cctxt#block bake_block cctxt cctxt#block
?fee_threshold ~force ?max_priority ~minimal_timestamp ?minimal_fees
?minimal_fees_per_gas_unit
?minimal_fees_per_byte
~await_endorsements
~force ?max_priority ~minimal_timestamp
?mempool ?context_path delegate) ; ?mempool ?context_path delegate) ;
command ~group ~desc: "Forge and inject a seed-nonce revelation operation." command ~group ~desc: "Forge and inject a seed-nonce revelation operation."
no_options no_options
@ -93,21 +110,29 @@ let baker_commands () =
in in
[ [
command ~group ~desc: "Launch the baker daemon." command ~group ~desc: "Launch the baker daemon."
(args3 max_priority_arg fee_threshold_arg max_waiting_time_arg) (args5
max_priority_arg
minimal_fees_arg
minimal_fees_per_gas_unit_arg
minimal_fees_per_byte_arg
no_waiting_for_endorsements_arg)
(prefixes [ "run" ; "with" ; "local" ; "node" ] (prefixes [ "run" ; "with" ; "local" ; "node" ]
@@ param @@ param
~name:"context_path" ~name:"context_path"
~desc:"Path to the node data directory (e.g. $HOME/.tezos-node)" ~desc:"Path to the node data directory (e.g. $HOME/.tezos-node)"
directory_parameter directory_parameter
@@ seq_of_param Client_keys.Public_key_hash.alias_param) @@ seq_of_param Client_keys.Public_key_hash.alias_param)
(fun (max_priority, fee_threshold, max_waiting_time) node_path delegates cctxt -> (fun (max_priority, minimal_fees, minimal_fees_per_gas_unit,
minimal_fees_per_byte, no_waiting_for_endorsements)
node_path delegates cctxt ->
Tezos_signer_backends.Encrypted.decrypt_list Tezos_signer_backends.Encrypted.decrypt_list
cctxt (List.map fst delegates) >>=? fun () -> cctxt (List.map fst delegates) >>=? fun () ->
Client_daemon.Baker.run cctxt Client_daemon.Baker.run cctxt
?fee_threshold ?minimal_fees
?minimal_fees_per_gas_unit
?minimal_fees_per_byte
?max_priority ?max_priority
~max_waiting_time ~await_endorsements:(not no_waiting_for_endorsements)
~min_date:((Time.add (Time.now ()) (Int64.neg 1800L)))
~context_path:(Filename.concat node_path "context") ~context_path:(Filename.concat node_path "context")
(List.map snd delegates) (List.map snd delegates)
) )
@ -129,7 +154,6 @@ let endorser_commands () =
cctxt (List.map fst delegates) >>=? fun () -> cctxt (List.map fst delegates) >>=? fun () ->
Client_daemon.Endorser.run cctxt Client_daemon.Endorser.run cctxt
~delay:endorsement_delay ~delay:endorsement_delay
~min_date:((Time.add (Time.now ()) (Int64.neg 1800L)))
(List.map snd delegates) (List.map snd delegates)
) )
] ]