Module type Updater.PROTOCOL

This is the signature of a Tezos protocol implementation. It has access to the standard library and the Environment module.

val max_block_length : int

The maximum size of a block header in bytes.

val max_operation_data_length : int

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 : quota list

Operations quota for each validation pass. The length of the list denotes the number of validation passes.

type block_header_data

The economic protocol-specific type of blocks.

val block_header_data_encoding : block_header_data Data_encoding.t

Encoding for economic protocol-specific part of block headers.

type block_header = {
  1. shell : Block_header.shell_header;
  2. protocol_data : block_header_data;
}

A fully parsed block header.

type block_header_metadata

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_with_legacy_attestation_name : block_header_metadata Data_encoding.t

Encoding for economic protocol-specific block metadata. This encoding uses the attestation legacy name: endorsement.

val block_header_metadata_encoding : block_header_metadata Data_encoding.t

Encoding for economic protocol-specific block metadata.

type operation_data

The economic protocol-specific type of operations.

type operation_receipt

Economic protocol-specific side information computed by the protocol during the validation of each operation, to be used conjointly with block_header_metadata.

type operation = {
  1. shell : Operation.shell_header;
  2. protocol_data : operation_data;
}

A fully parsed operation.

val operation_data_encoding : operation_data Data_encoding.t

Encoding for protocol-specific operation data.

val operation_data_encoding_with_legacy_attestation_name : operation_data Data_encoding.t

Encoding for protocol-specific operation data. This encoding uses the attestation legacy name: endorsement.

val operation_receipt_encoding : operation_receipt Data_encoding.t

Encoding for protocol-specific operation receipts.

val operation_receipt_encoding_with_legacy_attestation_name : operation_receipt Data_encoding.t

Encoding for protocol-specific operation receipts. This encoding uses the attestation legacy name: endorsement.

val operation_data_and_receipt_encoding : (operation_data * operation_receipt) Data_encoding.t

Encoding that mixes an operation data and its receipt.

val operation_data_and_receipt_encoding_with_legacy_attestation_name : (operation_data * operation_receipt) Data_encoding.t

Encoding that mixes an operation data and its receipt. This encoding uses the attestation legacy name: endorsement.

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.

Block (and operation) validation and application

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 =
  1. | Application of block_header
    (*

    Standard validation or application of a preexisting block.

    *)
  2. | 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.

    *)
  3. | Construction of {
    1. predecessor_hash : Block_hash.t;
    2. timestamp : Time.t;
    3. 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).

    *)
  4. | Partial_construction of {
    1. predecessor_hash : Block_hash.t;
    2. 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.

type validation_state

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.

type application_state

Similar to validation_state, but for the application process.

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_finalized_block_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.

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.

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.

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 : rpc_context RPC_directory.t

rpc_services provides the list of remote procedures exported by this protocol implementation.

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