main.ml
(*****************************************************************************)
(* *)
(* Open Source License *)
(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* Permission is hereby granted, free of charge, to any person obtaining a *)
(* copy of this software and associated documentation files (the "Software"),*)
(* to deal in the Software without restriction, including without limitation *)
(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)
(* and/or sell copies of the Software, and to permit persons to whom the *)
(* Software is furnished to do so, subject to the following conditions: *)
(* *)
(* The above copyright notice and this permission notice shall be included *)
(* in all copies or substantial portions of the Software. *)
(* *)
(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)
(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)
(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)
(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)
(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)
(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)
(* DEALINGS IN THE SOFTWARE. *)
(* *)
(*****************************************************************************)
(* Tezos Protocol Implementation - Protocol Signature Instance *)
type block_header_data = Alpha_context.Block_header.protocol_data
type block_header = Alpha_context.Block_header.t = {
shell : Block_header.shell_header;
protocol_data : block_header_data;
}
let block_header_data_encoding =
Alpha_context.Block_header.protocol_data_encoding
type block_header_metadata = Apply_results.block_metadata
let block_header_metadata_encoding = Apply_results.block_metadata_encoding
type operation_data = Alpha_context.packed_protocol_data =
| Operation_data :
'kind Alpha_context.Operation.protocol_data
-> operation_data
let operation_data_encoding = Alpha_context.Operation.protocol_data_encoding
type operation_receipt = Apply_results.packed_operation_metadata =
| Operation_metadata :
'kind Apply_results.operation_metadata
-> operation_receipt
| No_operation_metadata : operation_receipt
let operation_receipt_encoding = Apply_results.operation_metadata_encoding
let operation_data_and_receipt_encoding =
Apply_results.operation_data_and_metadata_encoding
type operation = Alpha_context.packed_operation = {
shell : Operation.shell_header;
protocol_data : operation_data;
}
let acceptable_passes = Alpha_context.Operation.acceptable_passes
let max_block_length = Alpha_context.Block_header.max_header_length
let max_operation_data_length =
Alpha_context.Constants.max_operation_data_length
let validation_passes =
let open Alpha_context.Constants in
Updater.
[
(* 2048 endorsements *)
{max_size = 2048 * 2048; max_op = Some 2048};
(* 32k of voting operations *)
{max_size = 32 * 1024; max_op = None};
(* revelations, wallet activations and denunciations *)
{
max_size = max_anon_ops_per_block * 1024;
max_op = Some max_anon_ops_per_block;
};
(* 512kB *)
{max_size = 512 * 1024; max_op = None};
]
let rpc_services =
Alpha_services.register () ;
Services_registration.get_rpc_services ()
type validation_mode =
| Application of {
block_header : Alpha_context.Block_header.t;
fitness : Alpha_context.Fitness.t;
payload_producer : Alpha_context.public_key_hash;
block_producer : Alpha_context.public_key_hash;
predecessor_round : Alpha_context.Round.t;
predecessor_level : Alpha_context.Level.t;
}
| Partial_application of {
block_header : Alpha_context.Block_header.t;
fitness : Alpha_context.Fitness.t;
payload_producer : Alpha_context.public_key_hash;
block_producer : Alpha_context.public_key_hash;
predecessor_level : Alpha_context.Level.t;
predecessor_round : Alpha_context.Round.t;
}
(* Mempool only *)
| Partial_construction of {
predecessor : Block_hash.t;
predecessor_fitness : Fitness.t;
predecessor_level : Alpha_context.Level.t;
predecessor_round : Alpha_context.Round.t;
}
(* Baker only *)
| Full_construction of {
predecessor : Block_hash.t;
payload_producer : Alpha_context.public_key_hash;
block_producer : Alpha_context.public_key_hash;
protocol_data_contents : Alpha_context.Block_header.contents;
level : Int32.t;
round : Alpha_context.Round.t;
predecessor_level : Alpha_context.Level.t;
predecessor_round : Alpha_context.Round.t;
}
type validation_state = {
mode : validation_mode;
chain_id : Chain_id.t;
ctxt : Alpha_context.t;
op_count : int;
migration_balance_updates : Alpha_context.Receipt.balance_updates;
liquidity_baking_escape_ema : Int32.t;
implicit_operations_results :
Apply_results.packed_successful_manager_operation_result list;
}
let cache_layout = Apply.cache_layout
let begin_partial_application ~chain_id ~ancestor_context:ctxt
~predecessor_timestamp ~(predecessor_fitness : Fitness.t)
(block_header : Alpha_context.Block_header.t) =
(* Note: we don't have access to the predecessor context. *)
let level = block_header.shell.level in
let timestamp = block_header.shell.timestamp in
Alpha_context.Fitness.from_raw block_header.shell.fitness >>?= fun fitness ->
Alpha_context.Fitness.round_from_raw predecessor_fitness
>>?= fun predecessor_round ->
Alpha_context.prepare ~level ~predecessor_timestamp ~timestamp ctxt
>>=? fun (ctxt, migration_balance_updates, migration_operation_results) ->
Alpha_context.Raw_level.of_int32 (Int32.pred level)
>>?= fun predecessor_level ->
let predecessor_level =
Alpha_context.Level.(from_raw ctxt predecessor_level)
in
Apply.begin_application
ctxt
chain_id
block_header
fitness
~predecessor_timestamp
~predecessor_level
~predecessor_round
>>=? fun ( ctxt,
payload_producer_pk,
block_producer,
liquidity_baking_operations_results,
liquidity_baking_escape_ema ) ->
let mode =
Partial_application
{
block_header;
fitness;
predecessor_level;
predecessor_round;
payload_producer = Signature.Public_key.hash payload_producer_pk;
block_producer;
}
in
return
{
mode;
chain_id;
ctxt;
op_count = 0;
migration_balance_updates;
liquidity_baking_escape_ema;
implicit_operations_results =
Apply_results.pack_migration_operation_results
migration_operation_results
@ liquidity_baking_operations_results;
}
(* During applications the valid consensus operations are:
* Endorsements on previous block with the right round, level, payload_hash (of the predecessor block)
* Preendorsements on current level, previous round, and the payload_hash of the current block
Those endorsements justify that the previous block was finalized.
Those preendorsements justify the locked_round part of the fitness of the current block
*)
let begin_application ~chain_id ~predecessor_context:ctxt ~predecessor_timestamp
~predecessor_fitness (block_header : Alpha_context.Block_header.t) =
let level = block_header.shell.level in
let timestamp = block_header.shell.timestamp in
Alpha_context.Fitness.from_raw block_header.shell.fitness >>?= fun fitness ->
Alpha_context.Fitness.round_from_raw predecessor_fitness
>>?= fun predecessor_round ->
Alpha_context.Raw_level.of_int32 (Int32.pred level)
>>?= fun predecessor_level ->
Alpha_context.prepare ~level ~predecessor_timestamp ~timestamp ctxt
>>=? fun (ctxt, migration_balance_updates, migration_operation_results) ->
let predecessor_level = Alpha_context.Level.from_raw ctxt predecessor_level in
Apply.begin_application
ctxt
chain_id
block_header
fitness
~predecessor_timestamp
~predecessor_level
~predecessor_round
>>=? fun ( ctxt,
payload_producer,
block_producer,
liquidity_baking_operations_results,
liquidity_baking_escape_ema ) ->
let mode =
Application
{
block_header;
fitness;
predecessor_round;
predecessor_level;
payload_producer = Signature.Public_key.hash payload_producer;
block_producer;
}
in
return
{
mode;
chain_id;
ctxt;
op_count = 0;
migration_balance_updates;
liquidity_baking_escape_ema;
implicit_operations_results =
Apply_results.pack_migration_operation_results
migration_operation_results
@ liquidity_baking_operations_results;
}
let begin_construction ~chain_id ~predecessor_context:ctxt
~predecessor_timestamp ~predecessor_level ~predecessor_fitness ~predecessor
~timestamp ?(protocol_data : block_header_data option) () =
let level = Int32.succ predecessor_level in
Alpha_context.prepare ~level ~predecessor_timestamp ~timestamp ctxt
>>=? fun (ctxt, migration_balance_updates, migration_operation_results) ->
Alpha_context.Raw_level.of_int32 predecessor_level
>>?= fun predecessor_level ->
let predecessor_level =
Alpha_context.Level.(from_raw ctxt predecessor_level)
in
(match protocol_data with
| None ->
Alpha_context.Fitness.round_from_raw predecessor_fitness
>>?= fun predecessor_round ->
let escape_vote = false in
Apply.begin_partial_construction ctxt ~predecessor_level ~escape_vote
>>=? fun ( ctxt,
liquidity_baking_operations_results,
liquidity_baking_escape_ema ) ->
let mode =
Partial_construction
{
predecessor;
predecessor_fitness;
predecessor_level;
predecessor_round;
}
in
return
( mode,
ctxt,
liquidity_baking_operations_results,
liquidity_baking_escape_ema )
| Some proto_header ->
Alpha_context.Fitness.round_from_raw predecessor_fitness
>>?= fun predecessor_round ->
let round_durations = Alpha_context.Constants.round_durations ctxt in
Alpha_context.Round.round_of_timestamp
round_durations
~predecessor_timestamp
~predecessor_round
~timestamp
>>?= fun round ->
(* The endorsement/preendorsement validation rules for construction are the
same as for application. *)
Apply.begin_full_construction
ctxt
~predecessor_timestamp
~predecessor_round
~predecessor_level
~round
proto_header.contents
>>=? fun {
ctxt;
protocol_data = protocol_data_contents;
payload_producer;
block_producer;
round;
liquidity_baking_escape_ema;
implicit_operations_results =
liquidity_baking_operations_results;
} ->
let mode =
Full_construction
{
predecessor;
payload_producer;
block_producer;
level;
round;
protocol_data_contents;
predecessor_round;
predecessor_level;
}
in
return
( mode,
ctxt,
liquidity_baking_operations_results,
liquidity_baking_escape_ema ))
>|=? fun ( mode,
ctxt,
liquidity_baking_operations_results,
liquidity_baking_escape_ema ) ->
{
mode;
chain_id;
ctxt;
op_count = 0;
migration_balance_updates;
liquidity_baking_escape_ema;
implicit_operations_results =
Apply_results.pack_migration_operation_results migration_operation_results
@ liquidity_baking_operations_results;
}
let apply_operation_with_mode mode ctxt chain_id data op_count operation
~payload_producer =
let {shell; protocol_data = Operation_data protocol_data} = operation in
let operation : _ Alpha_context.operation = {shell; protocol_data} in
Apply.apply_operation
ctxt
chain_id
mode
Optimized
~payload_producer
(Alpha_context.Operation.hash operation)
operation
>|=? fun (ctxt, result) ->
let op_count = op_count + 1 in
({data with ctxt; op_count}, Operation_metadata result)
let apply_operation ({mode; chain_id; ctxt; op_count; _} as data)
(operation : Alpha_context.packed_operation) =
match mode with
| Partial_application _
when not
(List.exists
(Compare.Int.equal 0)
(Alpha_context.Operation.acceptable_passes operation)) ->
(* Multipass validation only considers operations in pass 0. *)
let op_count = op_count + 1 in
return ({data with ctxt; op_count}, No_operation_metadata)
| Partial_application
{
block_header =
{
shell = {predecessor; _};
protocol_data = {contents = {payload_hash; _}; _};
};
fitness;
payload_producer;
predecessor_round;
predecessor_level;
_;
} ->
let locked_round = Alpha_context.Fitness.locked_round fitness in
apply_operation_with_mode
(Apply.Application
{
payload_hash;
predecessor_block = predecessor;
predecessor_round;
predecessor_level;
locked_round;
round = Alpha_context.Fitness.round fitness;
})
ctxt
chain_id
data
op_count
operation
~payload_producer
| Application
{
block_header =
{
shell = {predecessor; _};
protocol_data = {contents = {payload_hash; _}; _};
};
fitness;
payload_producer;
predecessor_round;
predecessor_level;
_;
} ->
let locked_round = Alpha_context.Fitness.locked_round fitness in
apply_operation_with_mode
(Apply.Application
{
payload_hash;
predecessor_block = predecessor;
predecessor_round;
predecessor_level;
locked_round;
round = Alpha_context.Fitness.round fitness;
})
ctxt
chain_id
data
op_count
operation
~payload_producer
| Partial_construction
{predecessor_level; predecessor_round; predecessor_fitness; _} ->
Alpha_context.Fitness.predecessor_round_from_raw predecessor_fitness
>>?= fun grand_parent_round ->
apply_operation_with_mode
(Apply.Partial_construction
{predecessor_round; predecessor_level; grand_parent_round})
ctxt
chain_id
data
op_count
operation
~payload_producer:Signature.Public_key_hash.zero
| Full_construction
{
payload_producer;
predecessor;
predecessor_round;
predecessor_level;
protocol_data_contents = {payload_hash; _};
round;
_;
} ->
apply_operation_with_mode
(Apply.Full_construction
{
payload_hash;
predecessor_block = predecessor;
predecessor_level;
predecessor_round;
round;
})
ctxt
chain_id
data
op_count
operation
~payload_producer
let cache_nonce_from_block_header shell contents =
let open Alpha_context.Block_header in
let shell =
Block_header.
{
level = 0l;
proto_level = 0;
predecessor = shell.predecessor;
timestamp = Time.of_seconds 0L;
validation_passes = 0;
operations_hash = shell.operations_hash;
fitness = [];
context = Context_hash.zero;
}
in
let contents =
{
contents with
payload_hash = Block_payload_hash.zero;
proof_of_work_nonce =
Bytes.make Constants_repr.proof_of_work_nonce_size '0';
}
in
let protocol_data = {signature = Signature.zero; contents} in
let x = {shell; protocol_data} in
Block_hash.to_bytes (hash x)
let finalize_block_application ctxt round ~cache_nonce finalize_application_mode
protocol_data payload_producer block_producer liquidity_baking_escape_ema
implicit_operations_results predecessor migration_balance_updates op_count =
Apply.finalize_application
ctxt
finalize_application_mode
protocol_data
~payload_producer
~block_producer
liquidity_baking_escape_ema
implicit_operations_results
~round
~predecessor
~migration_balance_updates
>>=? fun (ctxt, fitness, receipt) ->
Alpha_context.Cache.Admin.sync ctxt ~cache_nonce >>= fun ctxt ->
let level = Alpha_context.Level.current ctxt in
let raw_level = Alpha_context.Raw_level.to_int32 level.level in
let commit_message =
Format.asprintf
"lvl %ld, fit:%a, round %a, %d ops"
raw_level
Alpha_context.Fitness.pp
fitness
Alpha_context.Round.pp
round
op_count
in
let validation_result =
Alpha_context.finalize
~commit_message
ctxt
(Alpha_context.Fitness.to_raw fitness)
in
return (validation_result, receipt)
type error += Missing_shell_header
let () =
register_error_kind
`Permanent
~id:"main.missing_shell_header"
~title:"Missing shell_header during finalisation of a block"
~description:
"During finalisation of a block header in Application mode or Full \
construction mode, a shell header should be provided so that a cache \
nonce can be computed."
~pp:(fun ppf () ->
Format.fprintf
ppf
"No shell header provided during the finalisation of a block.")
Data_encoding.unit
(function Missing_shell_header -> Some () | _ -> None)
(fun () -> Missing_shell_header)
let finalize_block
{
mode;
ctxt;
op_count;
migration_balance_updates;
liquidity_baking_escape_ema;
implicit_operations_results;
_;
} shell_header =
match mode with
| Partial_construction {predecessor_fitness; _} ->
Alpha_context.Voting_period.get_rpc_current_info ctxt
>>=? fun voting_period_info ->
let level_info = Alpha_context.Level.current ctxt in
let fitness = predecessor_fitness in
let ctxt = Alpha_context.finalize ctxt fitness in
return
( ctxt,
Apply_results.
{
proposer = Signature.Public_key_hash.zero;
baker = Signature.Public_key_hash.zero;
level_info;
voting_period_info;
nonce_hash = None;
consumed_gas = Alpha_context.Gas.Arith.zero;
deactivated = [];
balance_updates = migration_balance_updates;
liquidity_baking_escape_ema;
implicit_operations_results;
} )
| Partial_application {fitness; block_producer; _} ->
(* For partial application we do not completely check the block validity.
Validating the endorsements is sufficient for a good precheck *)
let level = Alpha_context.Level.current ctxt in
let included_endorsements =
Alpha_context.Consensus.current_endorsement_power ctxt
in
let minimum = Alpha_context.Constants.consensus_threshold ctxt in
Apply.are_endorsements_required ctxt ~level:level.level
>>=? fun endorsements_required ->
(if endorsements_required then
Apply.check_minimum_endorsements
~endorsing_power:included_endorsements
~minimum
else return_unit)
>>=? fun () ->
Alpha_context.Voting_period.get_rpc_current_info ctxt
>|=? fun voting_period_info ->
let level_info = Alpha_context.Level.current ctxt in
let ctxt =
Alpha_context.finalize ctxt (Alpha_context.Fitness.to_raw fitness)
in
( ctxt,
Apply_results.
{
proposer = Signature.Public_key_hash.zero;
(* We cannot retrieve the proposer as it requires the
frozen deposit that might not be available depending on
the context given to the partial application. *)
baker = block_producer;
level_info;
voting_period_info;
nonce_hash = None;
consumed_gas = Alpha_context.Gas.Arith.zero;
deactivated = [];
balance_updates = migration_balance_updates;
liquidity_baking_escape_ema;
implicit_operations_results;
} )
| Application
{
payload_producer;
fitness;
block_producer;
block_header = {protocol_data = {contents = protocol_data; _}; shell};
_;
} ->
let round = Alpha_context.Fitness.round fitness in
let cache_nonce = cache_nonce_from_block_header shell protocol_data in
finalize_block_application
ctxt
~cache_nonce
round
(Finalize_application fitness)
protocol_data
payload_producer
block_producer
liquidity_baking_escape_ema
implicit_operations_results
shell.predecessor
migration_balance_updates
op_count
| Full_construction
{
predecessor;
predecessor_round;
protocol_data_contents;
round;
level;
payload_producer;
block_producer;
_;
} ->
Option.value_e
shell_header
~error:(Error_monad.trace_of_error Missing_shell_header)
>>?= fun shell_header ->
let cache_nonce =
cache_nonce_from_block_header shell_header protocol_data_contents
in
Alpha_context.Raw_level.of_int32 level >>?= fun level ->
finalize_block_application
ctxt
round
~cache_nonce
(Finalize_full_construction {level; predecessor_round})
protocol_data_contents
payload_producer
block_producer
liquidity_baking_escape_ema
implicit_operations_results
predecessor
migration_balance_updates
op_count
let relative_position_within_block op1 op2 =
let open Alpha_context in
let (Operation_data op1) = op1.protocol_data in
let (Operation_data op2) = op2.protocol_data in
match[@coq_match_with_default] (op1.contents, op2.contents) with
| (Single (Preendorsement _), Single (Preendorsement _)) -> 0
| (Single (Preendorsement _), _) -> -1
| (_, Single (Preendorsement _)) -> 1
| (Single (Endorsement _), Single (Endorsement _)) -> 0
| (Single (Endorsement _), _) -> -1
| (_, Single (Endorsement _)) -> 1
| (Single (Seed_nonce_revelation _), Single (Seed_nonce_revelation _)) -> 0
| (_, Single (Seed_nonce_revelation _)) -> 1
| (Single (Seed_nonce_revelation _), _) -> -1
| ( Single (Double_preendorsement_evidence _),
Single (Double_preendorsement_evidence _) ) ->
0
| (_, Single (Double_preendorsement_evidence _)) -> 1
| (Single (Double_preendorsement_evidence _), _) -> -1
| ( Single (Double_endorsement_evidence _),
Single (Double_endorsement_evidence _) ) ->
0
| (_, Single (Double_endorsement_evidence _)) -> 1
| (Single (Double_endorsement_evidence _), _) -> -1
| (Single (Double_baking_evidence _), Single (Double_baking_evidence _)) -> 0
| (_, Single (Double_baking_evidence _)) -> 1
| (Single (Double_baking_evidence _), _) -> -1
| (Single (Activate_account _), Single (Activate_account _)) -> 0
| (_, Single (Activate_account _)) -> 1
| (Single (Activate_account _), _) -> -1
| (Single (Proposals _), Single (Proposals _)) -> 0
| (_, Single (Proposals _)) -> 1
| (Single (Proposals _), _) -> -1
| (Single (Ballot _), Single (Ballot _)) -> 0
| (_, Single (Ballot _)) -> 1
| (Single (Ballot _), _) -> -1
| (Single (Failing_noop _), Single (Failing_noop _)) -> 0
| (_, Single (Failing_noop _)) -> 1
| (Single (Failing_noop _), _) -> -1
(* Manager operations with smaller counter are pre-validated first. *)
| (Single (Manager_operation op1), Single (Manager_operation op2)) ->
Z.compare op1.counter op2.counter
| (Cons (Manager_operation op1, _), Single (Manager_operation op2)) ->
Z.compare op1.counter op2.counter
| (Single (Manager_operation op1), Cons (Manager_operation op2, _)) ->
Z.compare op1.counter op2.counter
| (Cons (Manager_operation op1, _), Cons (Manager_operation op2, _)) ->
Z.compare op1.counter op2.counter
let init_cache ctxt =
Context.Cache.set_cache_layout ctxt cache_layout >>= fun ctxt ->
Lwt.return (Context.Cache.clear ctxt)
let init ctxt block_header =
let level = block_header.Block_header.level in
let timestamp = block_header.timestamp in
let typecheck (ctxt : Alpha_context.context) (script : Alpha_context.Script.t)
=
let allow_forged_in_storage =
false
(* There should be no forged value in bootstrap contracts. *)
in
Script_ir_translator.parse_script
ctxt
~legacy:true
~allow_forged_in_storage
script
>>=? fun (Ex_script parsed_script, ctxt) ->
Script_ir_translator.extract_lazy_storage_diff
ctxt
Optimized
parsed_script.storage_type
parsed_script.storage
~to_duplicate:Script_ir_translator.no_lazy_storage_id
~to_update:Script_ir_translator.no_lazy_storage_id
~temporary:false
>>=? fun (storage, lazy_storage_diff, ctxt) ->
Script_ir_translator.unparse_data
ctxt
Optimized
parsed_script.storage_type
storage
>|=? fun (storage, ctxt) ->
let storage =
Alpha_context.Script.lazy_expr (Micheline.strip_locations storage)
in
(({script with storage}, lazy_storage_diff), ctxt)
in
(* The cache must be synced at the end of block validation, so we do
so here for the first block in a protocol where `finalize_block`
is not called. *)
Alpha_context.Raw_level.of_int32 level >>?= fun raw_level ->
let init_fitness =
Alpha_context.Fitness.create_without_locked_round
~level:raw_level
~round:Alpha_context.Round.zero
~predecessor_round:Alpha_context.Round.zero
in
init_cache ctxt >>= fun ctxt ->
Alpha_context.prepare_first_block ~typecheck ~level ~timestamp ctxt
>>=? fun ctxt ->
let cache_nonce =
cache_nonce_from_block_header
block_header
{
payload_hash = Block_payload_hash.zero;
payload_round = Alpha_context.Round.zero;
liquidity_baking_escape_vote = false;
seed_nonce_hash = None;
proof_of_work_nonce =
Bytes.make Constants_repr.proof_of_work_nonce_size '0';
}
in
Alpha_context.Cache.Admin.sync ctxt ~cache_nonce >>= fun ctxt ->
return
(Alpha_context.finalize ctxt (Alpha_context.Fitness.to_raw init_fitness))
let value_of_key ~chain_id:_ ~predecessor_context:ctxt ~predecessor_timestamp
~predecessor_level:pred_level ~predecessor_fitness:_ ~predecessor:_
~timestamp =
let level = Int32.succ pred_level in
Alpha_context.prepare ctxt ~level ~predecessor_timestamp ~timestamp
>>=? fun (ctxt, _, _) -> return (Apply.value_of_key ctxt)
let check_manager_signature {chain_id; ctxt; _} op raw_op =
Apply.check_manager_signature ctxt chain_id op raw_op
let precheck_manager {ctxt; _} op =
(* We do not account for the gas limit of the batch in the block
since this function does not return a context, but we check that
this limit is within bounds (and fail otherwise with a
permanenent error). *)
Apply.precheck_manager_contents_list ctxt op ~mempool_mode:true
>|=? fun (_ :
Alpha_context.t
* 'kind Alpha_context.Kind.manager
Apply_results.prechecked_contents_list) -> ()
(* Vanity nonce: 1031119008347755 *)