Lift.P
The maximum size of an operation
in bytes. This value is bigger than the size of the bytes required for operation_data
, because this value accounts for the shell header.
val validation_passes : Updater.quota list
Operations quota for each validation pass. The length of the list denotes the number of validation passes.
val block_header_data_encoding : block_header_data Data_encoding.t
Encoding for economic protocol-specific part of block headers.
A fully parsed block header.
Economic protocol-specific side information computed by the protocol during the validation of a block. Should not include information about the evaluation of operations which is handled separately by operation_metadata
. To be used as an execution trace by tools (client, indexer). Not necessary for validation.
val block_header_metadata_encoding : block_header_metadata Data_encoding.t
Encoding for economic protocol-specific block metadata.
Economic protocol-specific side information computed by the protocol during the validation of each operation, to be used conjointly with block_header_metadata
.
A fully parsed operation.
val operation_data_encoding : operation_data Data_encoding.t
Encoding for economoic protocol-specific operation data.
val operation_receipt_encoding : operation_receipt Data_encoding.t
Encoding for eonomic protocol-specific operation receipts.
val operation_data_and_receipt_encoding :
(operation_data * operation_receipt) Data_encoding.t
Encoding that mixes an operation data and its receipt.
val acceptable_pass : operation -> int option
acceptable_pass op
gives the validation pass in which the input operation op
can appear. For instance, it results in Some 0
if op
only belongs to the first pass. When op
is ill-formed, acceptable_pass op
returns None
.
val compare_operations :
(Operation_hash.t * operation) ->
(Operation_hash.t * operation) ->
int
compare_operations (oph1,op1) (oph2,op2)
defines a total ordering relation on valid operations.
The following requirements must be satisfied: oph1
is the Operation.hash.p1
, oph2
is Operation.hash op2
and that op1
and op2
are valid in the same context.
compare_operations (oph1,op1) (oph2,op2) = 0
happens only if Operation_hash.compare oph1 oph2 = 0
, meaning op1 = op2
only when op1
and op2
are structurally identical.
Two operations of different validation_passes are compared in the reverse order of their validation_pass
: the one with the smaller validation_pass
is compared as being the greater.
When belonging to the same validation_pass, two operations comparison depends on their static parameters. An abstract weight is computed for each operation based on its static parameters. When two operations' weights are compared as equal, compare_operation (oph1,op1) (oph2,op2)
is Operation_hash.compare oph1 oph2
.
compare_operations
can be used as a compare
component of an Stdlib
.Map.OrderedType, or any such collection which relies on a total comparison function.
The following functions may be used when an existing block is received through the network, when a new block is created, or when operations are considered on their own e.g. in a mempool or during an RPC call.
Validation aims at deciding quickly whether a block or an operation is valid, with minimal computations and without writing anything in the storage. A block is valid if it can be applied without failure. An operation is valid if it can be safely included in a block without causing it to fail.
The application of an operation updates the Context.t
with regards to its semantics (e.g. updating balances after a transaction). The application of a block updates the context with all its operations and some additional global effects. Isolated operations may be applied as part of an RPC call to simulate their effects.
Blocks and operations must always be validated before they are applied. Indeed, the application assumes their validity as a precondition, meaning that the application of an invalid block might yield incorrect results instead of failing cleanly.
Note that in protocol versions <= K, where the validation functions do not yet exist, the validation of existing blocks is done by trying to apply it using the Partial_validation
mode below. Therefore, the application of a validated block may still fail in these protocols.
type mode =
| Application of block_header
Standard validation or application of a preexisting block.
*)| Partial_validation of block_header
Partial validation of a preexisting block. This mode is meant to quickly reject obviously invalid alternate branches by only performing a subset of checks. Therefore, application of blocks or operations makes no sense in this mode: calling begin_application
with this mode returns an error.
| Construction of {
predecessor_hash : Block_hash.t;
timestamp : Time.t;
block_header_data : block_header_data;
}
Construction of a new block. The main difference with the previous modes is that we cannot provide the block header to the begin_
functions, since the block does not exist yet. Note that the begin_
functions may be called in this mode without knowing yet which operations will be included in the future block.
The provided block_header_data
is not expected to be the final value of the field of the same type in the block_header
of the constructed block. Instead, it should be a protocol-specific, good enough, "prototype" of the final value. E.g. if the block_header_data
type for the current economic protocol includes a signature, then the provided block_header_data
should contain a fake signature (since providing a correct signature is not possible at this stage).
| Partial_construction of {
predecessor_hash : Block_hash.t;
timestamp : Time.t;
}
Minimal construction of a new virtual block, with the purpose of being able to validate/apply operations of interest. This mode may be used by the mempool (though the Mempool
module below is better suited for this) or by some RPCs e.g. preapply/operations
. Calling the finalize_
functions makes no sense in this mode.
The mode indicates the circumstances in which a block and/or operations are validated or applied, and contains specific information. It must be provided as an argument to begin_validation
and begin_application
.
A functional state that is transmitted throughout the validation of a block (or during the lifetime of a mempool or RPC). It is created by begin_validation
below, updated by validate_operation
, and required by finalize_validation
. This state is immutable thus validator or baker implementations are allowed to pause, replay or backtrack throughout validation steps.
Similar to validation_state
, but for the application process.
val begin_validation :
Context.t ->
Chain_id.t ->
mode ->
predecessor:Block_header.shell_header ->
validation_state Error_monad.tzresult Lwt.t
begin_validation predecessor_context chain_id mode
~predecessor
initializes the validation_state
for the validation process of an existing or new block.
predecessor_context
and predecessor
are the resulting context and shell header of the predecessor block. Exceptionally in Partial_validation
mode, they may instead come from any ancestor block that is more recent (i.e. has a greater level) than the current head's "last_allowed_fork_level".
mode
specifies the circumstances of validation and also carries additional information: see mode
.
Note that for protocol versions <= K where begin_validation
does not exist yet, this calls the old begin_application
by necessity. However, in Application
mode, this calls the old begin_application
in Partial_validation
mode in order to run more quickly. This preserves the behavior of precheck
in lib_validation/block_validation.ml
for old protocols. It does mean that the application of a validated block may fail in these protocols.
val validate_operation :
?check_signature:bool ->
validation_state ->
Operation_hash.t ->
operation ->
validation_state Error_monad.tzresult Lwt.t
Validate an operation. If successful, return the updated validation_state
.
check_signature
indicates whether the signature should be checked. It defaults to true
because the signature needs to be correct for the operation to be valid. This argument exists for special cases where it is acceptable to bypass this check, e.g. if we know that the operation has already been successfully validated in another context.
val finalize_validation : validation_state -> unit Error_monad.tzresult Lwt.t
Run final and global checks on the block that must come after the validation of all its operations to establish its validity.
val begin_application :
Context.t ->
Chain_id.t ->
mode ->
predecessor:Block_header.shell_header ->
application_state Error_monad.tzresult Lwt.t
Initialize the application_state
for the application process of an existing or new block. See begin_validation
for details on the arguments.
In protocol versions > K, calling this function with the Partial_validation
mode returns an error.
val apply_operation :
application_state ->
Operation_hash.t ->
operation ->
(application_state * operation_receipt) Error_monad.tzresult Lwt.t
Apply an operation. If successful, return the updated application_state
and the corresponding operation_receipt
.
This should be called for all operations in a block, after begin_application
and before finalize_application
. Moreover, the operation should have already been validated by validate_operation
.
val finalize_application :
application_state ->
Block_header.shell_header option ->
(Updater.validation_result * block_header_metadata) Error_monad.tzresult
Lwt.t
Finalize the context resulting from the application of the contents of the block.
If there is no protocol migration, i.e. if the block being applied is not the last block of the current economic protocol, then the resulting context can be used in the future as input for the validation and application of its successor blocks.
In Construction
mode, the Block_header.shell_header option
argument must contain a value, which will be used to compute the cache_nonce
. In other modes, it can as well be None
since it will not be used.
val rpc_services : Updater.rpc_context RPC_directory.t
rpc_services
provides the list of remote procedures exported by this protocol implementation.
val init :
Chain_id.t ->
Context.t ->
Block_header.shell_header ->
Updater.validation_result Error_monad.tzresult Lwt.t
init chain_id ctxt hd
initializes the context, or upgrades the context after a protocol amendment. This function receives as arguments the chain_id
of the current chain and the context ctxt
resulting from the application of the block that triggered the amendment, as well as its header hd
. This function should fail if the "protocol stitching", i.e., the transition from a valid previous protocol to the one being activated, has not been implemented.
val value_of_key :
chain_id:Chain_id.t ->
predecessor_context:Context.t ->
predecessor_timestamp:Time.t ->
predecessor_level:Int32.t ->
predecessor_fitness:Fitness.t ->
predecessor:Block_hash.t ->
timestamp:Time.t ->
(Context.Cache.key ->
Context.Cache.value Error_monad.tzresult Lwt.t)
Error_monad.tzresult
Lwt.t
value_of_key chain_id predecessor_context
predecessor_timestamp predecessor_level predecessor_fitness
predecessor timestamp
returns a function to build one value of the cache from its key.
This function is used to restore all or part of the cache, for instance when booting a validator to preheat the cache, or when a reorganization happens. This function should never fail, returned errors are fatal.
The generated function is passed to Context.Cache.load_caches
which will use it either immediately a cache-loading time or on-demand, when a given cached value is accessed.
module Mempool : sig ... end