diff --git a/docs/learn/operation-format-execution.mdx b/docs/learn/operation-format-execution.mdx index cc8a43ed2..7dc6745b0 100644 --- a/docs/learn/operation-format-execution.mdx +++ b/docs/learn/operation-format-execution.mdx @@ -7,10 +7,11 @@ sidebar_label: Detailed operation format and execution sequence Massa's maximal theoretical throughput is about 10k operations per second, with low hardware requirements for validators to improve decentralization. This puts constraints on how operations are executed and finalized in Massa: -* parallelization techniques are required for processing operations fast enough -* nodes are unable to store the whole history of previously executed operations (for example to ensure that an old operation is not being re-executed) -* block producers do not have enough computing power to simulate the execution of all candidate operations to choose which ones to include in their blocks -* security must always be guaranteed against malicious actors + +- parallelization techniques are required for processing operations fast enough +- nodes are unable to store the whole history of previously executed operations (for example to ensure that an old operation is not being re-executed) +- block producers do not have enough computing power to simulate the execution of all candidate operations to choose which ones to include in their blocks +- security must always be guaranteed against malicious actors Massa addresses these issues through multiple techniques. @@ -24,21 +25,22 @@ and it passes signature verification. Binary serialization format of an operation: +---------------------------------+-----------------------------------+-------------------+ -| Operation Binary Representation | +| Operation Binary Representation | +---------------------------------+-----------------------------------+-------------------+ -| Field | Description | Type | +| Field | Description | Type | +=================================+===================================+===================+ -| `signature` | See [Signature section](#signature) | +| `signature` | See [Signature section](#signature) | +---------------------------------+-----------------------------------+-------------------+ -| `sender public key` | See [Public Key section](#public-key) | +| `sender public key` | See [Public Key section](#public-key) | +---------------------------------+-----------------------------------+-------------------+ | `serialized operation contents` | See [Operation Contents section](#operation-contents) | +---------------------------------+-----------------------------------+-------------------+ Legality checks performed on deserialization: -* the signature is legal (see [Signature section](#signature)) -* the public key is legal (see [Public Key section](#public-key)) -* the serialized operation contents are legal (see [Operation Contents section](#operation-contents)) + +- the signature is legal (see [Signature section](#signature)) +- the public key is legal (see [Public Key section](#public-key)) +- the serialized operation contents are legal (see [Operation Contents section](#operation-contents)) ### Operation contents hash @@ -56,39 +58,39 @@ This hash is a deterministic fingerprint of the non-malleable parts of the opera Because the operation contents hash uniquely identifies an operation, if another operation containing the same values in its operation contents is created, both operations will be considered to be the same operation that can only be executed at most a single time (see [Operation execution](#operation-execution)). -In Massa, there is no Nounce in operations. -Resolving potential conflicts can be done adjusting the expiry period of the operation being created. +In Massa, there is no Nonce in operations. +Resolving potential conflicts can be done adjusting the expiry period of the operation being created. ### Operation ID The ID of an operation has the following binary representation: +---------------------------+-----------------------------------------------------------------+-----------------------------------+ -| Operation ID Binary Representation | +| Operation ID Binary Representation | +---------------------------+-----------------------------------------------------------------+-----------------------------------+ -| Field | Description | Type | +| Field | Description | Type | +===========================+=================================================================+===================================+ -| `version number` | Varint unsigned 64-bit integer using protobuf conventions. | between 1 and 9 bytes (inclusive) | -| | Indicates the operation's version. | | +| `version number` | Varint unsigned 64-bit integer using protobuf conventions. | between 1 and 9 bytes (inclusive) | +| | Indicates the operation's version. | | +---------------------------+-----------------------------------------------------------------+-----------------------------------+ -| `operation_contents_hash` | See [Operation contents hash section](#operation-contents-hash) | 32 bytes | +| `operation_contents_hash` | See [Operation contents hash section](#operation-contents-hash) | 32 bytes | +---------------------------+-----------------------------------------------------------------+-----------------------------------+ Legality checks performed on binary deserialization: -* the version number must be 0 -* the operation contents hash must be legal (see [Operation contents hash section](#operation-contents-hash)) +- the version number must be 0 +- the operation contents hash must be legal (see [Operation contents hash section](#operation-contents-hash)) The ID of an operation has the following UTF-8 ASCII-compatible text representation: +-------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------+ -| Operation ID Text Representation | +| Operation ID Text Representation | +-------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------+ -| Field | Description | Type | +| Field | Description | Type | +=========================+====================================================================================================================+======================================+ -| `prefix letter 'O'` | Not a zero but the letter O. | | -| | A constant prefix indicating that it is an operation ID | | -| | to avoid ambiguity with other IDs (e.g., Block IDs are prefixed with 'B') | 1 letter (1 byte) | +| `prefix letter 'O'` | Not a zero but the letter O. | | +| | A constant prefix indicating that it is an operation ID | | +| | to avoid ambiguity with other IDs (e.g., Block IDs are prefixed with 'B') | 1 letter (1 byte) | +-------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------+ | `operation ID contents` | Base58check (no version, with checksum) representation of the binary serialization of the operation ID (see above) | 18 to 62 characters (18 to 62 bytes) | +-------------------------+--------------------------------------------------------------------------------------------------------------------+--------------------------------------+ @@ -96,17 +98,19 @@ The ID of an operation has the following UTF-8 ASCII-compatible text representat Note that the base58check encoding is the same one as the one used by bitcoin but without version number as it is already included in the underlying binary serialization of the operation ID. Here is the entire encoding process for an operation ID in text format: -* serialize the operation ID in binary format (see above) -* compute the SHA256 hash of the binary serialization -* append the first 4 bytes of the sha256 hash at the end of the binary serialization of the ID. This is used as a checksum to detect typing errors as operation IDs are also meant to be written on paper by humans. -* encode the resulting byte array using the base alphabet `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`. Similar looking characters (eg 0 vs O) are excluded to avoid human confusion. -* prepend the letter 'O' + +- serialize the operation ID in binary format (see above) +- compute the SHA256 hash of the binary serialization +- append the first 4 bytes of the sha256 hash at the end of the binary serialization of the ID. This is used as a checksum to detect typing errors as operation IDs are also meant to be written on paper by humans. +- encode the resulting byte array using the base alphabet `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`. Similar looking characters (eg 0 vs O) are excluded to avoid human confusion. +- prepend the letter 'O' Legality checks performed on text deserialization: -* the text must be valid UTF-8 and ASCII with only alphanumeric characters -* the prefix letter must be 'O' -* the base58check must use the legal alphabet described above and the checksum must verify -* the decoded binary serialization of the operation ID must be legal (see above) + +- the text must be valid UTF-8 and ASCII with only alphanumeric characters +- the prefix letter must be 'O' +- the base58check must use the legal alphabet described above and the checksum must verify +- the decoded binary serialization of the operation ID must be legal (see above) Example of legal operation ID: `O19DQAos5Dw6z4BVzQPYxj9g8v6H5W3HuKV7dFuYEpc2YNWopEz` @@ -127,74 +131,75 @@ The following function is used for signature verification: https://docs.rs/ed255 For maximal robustness and future-proofing, Massa tolerates operation signature malleability. - Binary serialization format of the signature: +---------------------+-------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| Signature Binary Representation | +| Signature Binary Representation | +---------------------+-------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| Field | Description | Type | +| Field | Description | Type | +=====================+=======================================================================================================+=============================================+ -| `version number` | Varint unsigned 64-bit integer using protobuf conventions | Between 1 (included) and 9 (included) bytes | +| `version number` | Varint unsigned 64-bit integer using protobuf conventions | Between 1 (included) and 9 (included) bytes | +---------------------+-------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| `signature content` | Constant-size ed25519 signature made of the concatenation of its R (32-bit) and s (32-bit) components | 64 bytes | +| `signature content` | Constant-size ed25519 signature made of the concatenation of its R (32-bit) and s (32-bit) components | 64 bytes | +---------------------+-------------------------------------------------------------------------------------------------------+---------------------------------------------+ Legality checks performed on deserialization: -* the version number must be 0 -* the signature must be 64 bytes long + +- the version number must be 0 +- the signature must be 64 bytes long Signature verification with respect to data and public key is not performed on signature deserialization. Invalid field elements in the signature are not checked on signature deserialization but on signature verification. ### Secret key - The secret key has the following binary representation: +----------------------------+------------------------------------------------------------------------------------------------+---------------------------------------------+ -| Secret Key Binary Representation | +| Secret Key Binary Representation | +----------------------------+------------------------------------------------------------------------------------------------+---------------------------------------------+ -| Field | Description | Type | +| Field | Description | Type | +============================+================================================================================================+=============================================+ -| `version number` | Varint unsigned 64-bit integer using protobuf conventions. Indicates the secret key version. | Between 1 (included) and 9 (included) bytes | +| `version number` | Varint unsigned 64-bit integer using protobuf conventions. Indicates the secret key version. | Between 1 (included) and 9 (included) bytes | +----------------------------+------------------------------------------------------------------------------------------------+---------------------------------------------+ -| `cryptographic secret key` | ed25519 secret key bytes | 32 bytes | +| `cryptographic secret key` | ed25519 secret key bytes | 32 bytes | +----------------------------+------------------------------------------------------------------------------------------------+---------------------------------------------+ Legality checks performed on binary deserialization: -* the version number must be 0 -* the cryptographic secret key bytes must be 32 bytes long +- the version number must be 0 +- the cryptographic secret key bytes must be 32 bytes long Secret keys have the following UTF-8 ASCII-compatible text representation: +-----------------------+-------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| Secret Key Text Representation | +| Secret Key Text Representation | +-----------------------+-------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| Field | Description | Type | +| Field | Description | Type | +=======================+=======================================================================================================+=============================================+ -| `prefix letter 'S'` | A constant prefix indicating that it is a secret key to avoid ambiguity with other IDs | 1 letter (1 byte) | -| | (e.g., Block IDs are prefixed with 'B') | | +| `prefix letter 'S'` | A constant prefix indicating that it is a secret key to avoid ambiguity with other IDs | 1 letter (1 byte) | +| | (e.g., Block IDs are prefixed with 'B') | | +-----------------------+-------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| `secret key contents` | Base58check (no version, with checksum) representation of the binary serialization of the secret key | 18 (included) to 62 (included) characters | -| | (see above) | (18 to 62 bytes) | +| `secret key contents` | Base58check (no version, with checksum) representation of the binary serialization of the secret key | 18 (included) to 62 (included) characters | +| | (see above) | (18 to 62 bytes) | +-----------------------+-------------------------------------------------------------------------------------------------------+---------------------------------------------+ Note that the base58check encoding is the same one as the one used by bitcoin but without version number as it is already included in the underlying binary serialization of the secret key. Here is the entire encoding process for a secret key in text format: -* serialize the secret key in binary format (see above) -* compute the SHA256 hash of the binary serialization -* append the first 4 bytes of the sha256 hash at the end of the binary serialization of the key. This is used as a checksum to detect typing errors as secret keys are also meant to be written on paper by humans. -* encode the resulting byte array using the base alphabet `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`. Similar looking characters (eg 0 vs O) are excluded to avoid human confusion. -* prepend the letter 'S' + +- serialize the secret key in binary format (see above) +- compute the SHA256 hash of the binary serialization +- append the first 4 bytes of the sha256 hash at the end of the binary serialization of the key. This is used as a checksum to detect typing errors as secret keys are also meant to be written on paper by humans. +- encode the resulting byte array using the base alphabet `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`. Similar looking characters (eg 0 vs O) are excluded to avoid human confusion. +- prepend the letter 'S' Legality checks performed on text deserialization: -* the text must be valid UTF-8 and ASCCII with only alphanumeric characters -* the prefix letter must be 'S' -* the base58check must use the legal alphabet described above and the checksum must verify -* the decoded binary serialization of the secret key must be legal (see above) + +- the text must be valid UTF-8 and ASCII with only alphanumeric characters +- the prefix letter must be 'S' +- the base58check must use the legal alphabet described above and the checksum must verify +- the decoded binary serialization of the secret key must be legal (see above) Example of legal secret key: `S1CkpvD4WMjJWxR2WZcrDEkJ1kWG2kKe1e3Afe8miqmskHqovvA` @@ -203,79 +208,84 @@ Example of legal secret key: `S1CkpvD4WMjJWxR2WZcrDEkJ1kWG2kKe1e3Afe8miqmskHqovv Binary serialization format of the public key: +----------------------------+------------------------------------------------------------+---------------------------------------------+ -| Public Key Binary Representation | +| Public Key Binary Representation | +----------------------------+------------------------------------------------------------+---------------------------------------------+ -| Field | Description | Type | +| Field | Description | Type | +============================+============================================================+=============================================+ -| `version number` | Varint unsigned 64-bit integer using protobuf conventions | Between 1 (included) and 9 (included) bytes | +| `version number` | Varint unsigned 64-bit integer using protobuf conventions | Between 1 (included) and 9 (included) bytes | +----------------------------+------------------------------------------------------------+---------------------------------------------+ -| `cryptographic public key` | Compressed ed25519 public key | 32 bytes | +| `cryptographic public key` | Compressed ed25519 public key | 32 bytes | +----------------------------+------------------------------------------------------------+---------------------------------------------+ The cryptographic public key is compressed in the following way to take only 32 bytes instead of 64: -* the first 255 bits represent the `y` coordinate -* the high bit of the 32nd byte gives the sign of `x` -Using this data, and through symetries in the ed25519 curve, it is possible to deduce the `x` coordinate. -In Massa, public key decompression is performed on public key deserialization, -and because decompression is a CPU time-heavy operation, -each connected peer has a dedicated CPU thread performing its deserializations. + +- the first 255 bits represent the `y` coordinate +- the high bit of the 32nd byte gives the sign of `x` + Using this data, and through symmetries in the ed25519 curve, it is possible to deduce the `x` coordinate. + In Massa, public key decompression is performed on public key deserialization, + and because decompression is a CPU time-heavy operation, + each connected peer has a dedicated CPU thread performing its deserializations. Legality checks performed on deserialization: -* the version number must be 0 -* the cryptographic public key must be 32 bytes long -* the compressed public key `y` component must be valid for the ed25519 curve + +- the version number must be 0 +- the cryptographic public key must be 32 bytes long +- the compressed public key `y` component must be valid for the ed25519 curve Public keys have the following UTF-8 ASCII-compatible text representation: +-----------------------+-------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| Public Key Text Representation | +| Public Key Text Representation | +-----------------------+-------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| Field | Description | Type | +| Field | Description | Type | +=======================+=======================================================================================================+=============================================+ -| `prefix letter 'P'` | A constant prefix indicating that it is a secret key to avoid ambiguity with other IDs | 1 letter (1 byte) | -| | (e.g., Block IDs are prefixed with 'B') | | +| `prefix letter 'P'` | A constant prefix indicating that it is a secret key to avoid ambiguity with other IDs | 1 letter (1 byte) | +| | (e.g., Block IDs are prefixed with 'B') | | +-----------------------+-------------------------------------------------------------------------------------------------------+---------------------------------------------+ -| `public key contents` | Base58check (no version, with checksum) representation of the binary serialization of the public key. | 18 (included) to 62 (included) characters. | -| | See above. | 18 to 62 bytes | +| `public key contents` | Base58check (no version, with checksum) representation of the binary serialization of the public key. | 18 (included) to 62 (included) characters. | +| | See above. | 18 to 62 bytes | +-----------------------+-------------------------------------------------------------------------------------------------------+---------------------------------------------+ Note that the base58check encoding is the same one as the one used by bitcoin but without version number as it is already included in the underlying binary serialization of the public key. Here is the entire encoding process for a public key in text format: -* serialize the public key in binary format (see above) -* compute the SHA256 hash of the binary serialization -* append the first 4 bytes of the sha256 hash at the end of the binary serialization of the key. This is used as a checksum to detect typing errors as public keys are also meant to be written on paper by humans. -* encode the resulting byte array using the base alphabet `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`. Similar looking characters (eg 0 vs O) are excluded to avoid human confusion. -* prepend the letter 'P' + +- serialize the public key in binary format (see above) +- compute the SHA256 hash of the binary serialization +- append the first 4 bytes of the sha256 hash at the end of the binary serialization of the key. This is used as a checksum to detect typing errors as public keys are also meant to be written on paper by humans. +- encode the resulting byte array using the base alphabet `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`. Similar looking characters (eg 0 vs O) are excluded to avoid human confusion. +- prepend the letter 'P' Legality checks performed on text deserialization: -* the text must be valid UTF-8 and ASCCII with only alphanumeric characters -* the prefix letter must be 'P' -* the base58check must use the legal alphabet described above and the checksum must verify -* the decoded binary serialization of the public key must be legal (see above) + +- the text must be valid UTF-8 and ASCII with only alphanumeric characters +- the prefix letter must be 'P' +- the base58check must use the legal alphabet described above and the checksum must verify +- the decoded binary serialization of the public key must be legal (see above) Example of legal public key: `P1t4JZwHhWNLt4xYabCbukyVNxSbhYPdF6wCYuRmDuHD784juxd` ### Address Addresses can be of two categories in Massa: -* Externally Owned Account addresses are used to identify users that hold a private key and can sign operations -* Smart Contract Account addresses are used to identify smart contracts that are not linked to any private key + +- Externally Owned Account addresses are used to identify users that hold a private key and can sign operations +- Smart Contract Account addresses are used to identify smart contracts that are not linked to any private key Binary serialization format of an address: +---------------------+------------------------------------------------------------+---------------------------------------------+ -| Address Binary Representation | +| Address Binary Representation | +---------------------+------------------------------------------------------------+---------------------------------------------+ -| Field | Description | Type | +| Field | Description | Type | +=====================+============================================================+=============================================+ -| `address category` | Varint unsigned 64-bit integer using protobuf conventions: | Between 1 (included) and 9 (included) bytes | -| | - value 0 for externally owned accounts, | | -| | - value 1 for smart contracts | | +| `address category` | Varint unsigned 64-bit integer using protobuf conventions: | Between 1 (included) and 9 (included) bytes | +| | - value 0 for externally owned accounts, | | +| | - value 1 for smart contracts | | +---------------------+------------------------------------------------------------+---------------------------------------------+ -| `version number` | Varint unsigned 64-bit integer using protobuf conventions | Between 1 (included) and 9 (included) bytes | +| `version number` | Varint unsigned 64-bit integer using protobuf conventions | Between 1 (included) and 9 (included) bytes | +---------------------+------------------------------------------------------------+---------------------------------------------+ -| `underlying hash` | Underlying blake3 hash | 32 bytes | +| `underlying hash` | Underlying blake3 hash | 32 bytes | +---------------------+------------------------------------------------------------+---------------------------------------------+ The underlying hash of an externally owned account address is computed by taking the blake3 hash @@ -289,40 +299,42 @@ Because this seed can be rewritten by Blockclique changes, always wait for finality before using the address of a newly created smart contract. Legality checks performed on binary deserialization: -* the address category must be 0 or 1 -* the version number must be 0 -* the underlying hash must be 32 bytes long +- the address category must be 0 or 1 +- the version number must be 0 +- the underlying hash must be 32 bytes long Text serialization of an address: +---------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------+ -| Address Text Representation | +| Address Text Representation | +---------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------+ -| Field | Description | Type | +| Field | Description | Type | +=====================+====================================================================================================+===========================================+ -| `prefix letter 'A'` | A constant prefix indicating that it is an address to avoid ambiguity with other IDs. | 1 ASCII letter (1 byte) | -| | (e.g., Block IDs are prefixed with 'B') | | +| `prefix letter 'A'` | A constant prefix indicating that it is an address to avoid ambiguity with other IDs. | 1 ASCII letter (1 byte) | +| | (e.g., Block IDs are prefixed with 'B') | | +---------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------+ -| `address category` | Single letter indicating the category of the address. 'U' for externally owned addresses, | 1 ASCII character (1 byte) | -| | and 'S' for smart contracts, see above. | | +| `address category` | Single letter indicating the category of the address. 'U' for externally owned addresses, | 1 ASCII character (1 byte) | +| | and 'S' for smart contracts, see above. | | +---------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------+ -| `address contents` | Base58check (no version, with checksum) representation of the binary serialization of the address | 37 (included) to 62 (included) characters | -| | as detailes above, but without the category field (only version then hash). | 37 to 62 bytes | +| `address contents` | Base58check (no version, with checksum) representation of the binary serialization of the address | 37 (included) to 62 (included) characters | +| | as detailed above, but without the category field (only version then hash). | 37 to 62 bytes | +---------------------+----------------------------------------------------------------------------------------------------+-------------------------------------------+ Here is the entire encoding process for an address in text format: -* serialize the address in binary format but without the address category (only version then hash in the binary serialization described above) -* compute the SHA256 hash of the binary serialization -* append the first 4 bytes of the sha256 hash at the end of the binary serialization of the address. This is used as a checksum to detect typing errors as addresses are also meant to be written on paper by humans. -* encode the resulting byte array using the base alphabet `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`. Similar looking characters (eg 0 vs O) are excluded to avoid human confusion. -* prepend the prefix 'AU' for externally owned accounts or 'AS' for smart contracts + +- serialize the address in binary format but without the address category (only version then hash in the binary serialization described above) +- compute the SHA256 hash of the binary serialization +- append the first 4 bytes of the sha256 hash at the end of the binary serialization of the address. This is used as a checksum to detect typing errors as addresses are also meant to be written on paper by humans. +- encode the resulting byte array using the base alphabet `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz`. Similar looking characters (eg 0 vs O) are excluded to avoid human confusion. +- prepend the prefix 'AU' for externally owned accounts or 'AS' for smart contracts Legality checks performed on text deserialization: -* the text must be valid UTF-8 and ASCCII with only alphanumeric characters -* the prefix must be 'AU' or 'AS' -* the base58check must use the legal alphabet described above and the checksum must verify -* the decoded binary serialization of the address must be legal (see above, but without the category field) + +- the text must be valid UTF-8 and ASCII with only alphanumeric characters +- the prefix must be 'AU' or 'AS' +- the base58check must use the legal alphabet described above and the checksum must verify +- the decoded binary serialization of the address must be legal (see above, but without the category field) Example of legal address in text format: `AU12v83xmHg2UrLM8GLsXRMrm7LQgn3DZVT6kUeFsuFyhZKLkbQtY` @@ -337,12 +349,12 @@ Floating point numbers should never be used for amount computations to avoid det Binary serialization format of a coin amount: +---------------------+-------------------------------------------------------------------------------------------------------+---------------------------+ -| Coin Amount Binary Representation | +| Coin Amount Binary Representation | +---------------------+-------------------------------------------------------------------------------------------------------+---------------------------+ -| Field | Description | Type | +| Field | Description | Type | +=====================+=======================================================================================================+===========================+ -| `mantissa` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | -| | The mantissa is deduced by multiplying the represented coin amount by `1e9`. | 9 bytes (included) | +| `mantissa` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | +| | The mantissa is deduced by multiplying the represented coin amount by `1e9`. | 9 bytes (included) | +---------------------+-------------------------------------------------------------------------------------------------------+---------------------------+ No checks are performed on deserialization except the validity of the varint itself @@ -351,91 +363,97 @@ and that its value fits in an unsigned 64bit integer. In text representation, coin amounts are represented as a traditional decimal number utf-8 string without zero padding and with the `.` decimal separator. Here are some examples of valid coin amounts in text format: -* `123456.789012345` -* `0.001` -* `0` + +- `123456.789012345` +- `0.001` +- `0` On text format deserialization, the following legality checks are performed: -* the string is valid UTF-8 -* there is at least one character -* only alphanumeric characters and the `.` decimal separator are allowed -* the `.` decimal separator must appear zero or one time -* the `.` decimal separator must not be the first nor the last character -* deserialization does not under/over-flow the allowed coin amount range -* deserialization into the underlying unsigned 64 bit representation does not cause precision loss (no rounding or truncation allowed) + +- the string is valid UTF-8 +- there is at least one character +- only alphanumeric characters and the `.` decimal separator are allowed +- the `.` decimal separator must appear zero or one time +- the `.` decimal separator must not be the first nor the last character +- deserialization does not under/over-flow the allowed coin amount range +- deserialization into the underlying unsigned 64 bit representation does not cause precision loss (no rounding or truncation allowed) ### Operation contents Operation contents are represented with a common set of properties (`fee`, `expire_period`) and a specific payload depending on the operation type among: -* `Transaction` -* `CallSC` -* `ExecuteSC` -* `RollBuy` -* `RollSell` + +- `Transaction` +- `CallSC` +- `ExecuteSC` +- `RollBuy` +- `RollSell` Binary serialization format of operation contents: +---------------------+-------------------------------------------------------------------------------------------------------+---------------------------+ -| Operation Contents Binary Representation | +| Operation Contents Binary Representation | +---------------------+-------------------------------------------------------------------------------------------------------+---------------------------+ -| Field | Description | Type | +| Field | Description | Type | +=====================+=======================================================================================================+===========================+ -| `fee` | Coin amount in binary format (see [Coin amount section](#coin-amounts)) | From 1 byte (included) to | -| | | 9 bytes (included) | +| `fee` | Coin amount in binary format (see [Coin amount section](#coin-amounts)) | From 1 byte (included) to | +| | | 9 bytes (included) | +---------------------+-------------------------------------------------------------------------------------------------------+---------------------------+ -| `expire_period` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | -| | | 9 bytes (included) | +| `expire_period` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | +| | | 9 bytes (included) | +---------------------+-------------------------------------------------------------------------------------------------------+---------------------------+ -| `type identifier` | Varint unsigned 32-bit integer using protobuf conventions. | From 1 byte (included) to | -| | | 5 bytes (included) | +| `type identifier` | Varint unsigned 32-bit integer using protobuf conventions. | From 1 byte (included) to | +| | | 5 bytes (included) | +---------------------+-------------------------------------------------------------------------------------------------------+---------------------------+ -| `op` | Binary-serialized operation payload (see below). | Size varies | +| `op` | Binary-serialized operation payload (see below). | Size varies | +---------------------+-------------------------------------------------------------------------------------------------------+---------------------------+ The type identifier indicates the payload type: -* `Transaction = 0` -* `RollBuy = 1` -* `RollSell = 2` -* `ExecuteSC = 3` -* `CallSC = 4` + +- `Transaction = 0` +- `RollBuy = 1` +- `RollSell = 2` +- `ExecuteSC = 3` +- `CallSC = 4` Legality checks performed on deserialization: -* the fee must be legal (see [Coin amount section](#coin-amounts)) -* the type identifier must be one of the ones listed above -* the operation payload defined by the type identifier must be legal (see below) + +- the fee must be legal (see [Coin amount section](#coin-amounts)) +- the type identifier must be one of the ones listed above +- the operation payload defined by the type identifier must be legal (see below) #### Transaction operation payload The binary serialization format of the payload of a transaction operation follows: +---------------------+-------------------------------------------------------------------------------------------------------+-----------------------+ -| Transaction Operation Payload Binary Representation | +| Transaction Operation Payload Binary Representation | +---------------------+-------------------------------------------------------------------------------------------------------+-----------------------+ -| Field | Description | Type | +| Field | Description | Type | +=====================+=======================================================================================================+=======================+ -|`destination address`| Transfer destination address binary representation, see [Address section](#address). | From 34 (included) to | -| | | 50 bytes (included) | +|`destination address`| Transfer destination address binary representation, see [Address section](#address). | From 34 (included) to | +| | | 50 bytes (included) | +---------------------+-------------------------------------------------------------------------------------------------------+-----------------------+ -| `amount` | Coin amount binary representation, see [Coin amount section](#coin-amounts). | From 1 (included) to | -| | | 9 bytes (included) | +| `amount` | Coin amount binary representation, see [Coin amount section](#coin-amounts). | From 1 (included) to | +| | | 9 bytes (included) | +---------------------+-------------------------------------------------------------------------------------------------------+-----------------------+ Legality checks performed on deserialization: -* the destination address must be legal (see [Address section](#address)) -* the amount must be legal (see [Coin amount section](#coin-amounts)) + +- the destination address must be legal (see [Address section](#address)) +- the amount must be legal (see [Coin amount section](#coin-amounts)) #### RollBuy operation payload The binary serialization format of the payload of a roll buy operation follows: +---------------------+-------------------------------------------------------------------------------------------------------+---------------------------+ -| Payload of a Roll Buy Operation Binary Representation | +| Payload of a Roll Buy Operation Binary Representation | +---------------------+-------------------------------------------------------------------------------------------------------+---------------------------+ -| Field | Description | Type | +| Field | Description | Type | +=====================+=======================================================================================================+===========================+ -| `rolls` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | -| | | 9 bytes (included) | +| `rolls` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | +| | | 9 bytes (included) | +---------------------+-------------------------------------------------------------------------------------------------------+---------------------------+ No particular checks performed at deserialization except that the varint must be valid @@ -446,12 +464,12 @@ and fit in an unsigned 64bit integer. The binary serialization format of the payload of a roll sell operation follows: +---------------------+------------------------------------------------------------+---------------------------+ -| Payload of a Roll Sell Operation Binary Representation | +| Payload of a Roll Sell Operation Binary Representation | +---------------------+------------------------------------------------------------+---------------------------+ -| Field | Description | Type | +| Field | Description | Type | +=====================+============================================================+===========================+ -| `rolls` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | -| | | 9 bytes (included) | +| `rolls` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | +| | | 9 bytes (included) | +---------------------+------------------------------------------------------------+---------------------------+ No particular checks performed at deserialization except that the varint must be valid @@ -462,129 +480,128 @@ and fit in an unsigned 64bit integer. The binary serialization format of the payload of a an Execute SC operation follows: +------------------------------+------------------------------------------------------------------------------+---------------------------+ -| Payload of a ExecuteSC Operation Binary Representation | +| Payload of a ExecuteSC Operation Binary Representation | +------------------------------+------------------------------------------------------------------------------+---------------------------+ -| Field | Description | Type | +| Field | Description | Type | +==============================+==============================================================================+===========================+ -| `max_gas` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | -| | | 9 bytes (included) | +| `max_gas` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | +| | | 9 bytes (included) | +------------------------------+------------------------------------------------------------------------------+---------------------------+ -| `max_coins` | Coin amount binary serialization (see [Coin amount section](#coin-amounts)). | From 1 byte (included) to | -| | | 9 bytes (included) | +| `max_coins` | Coin amount binary serialization (see [Coin amount section](#coin-amounts)). | From 1 byte (included) to | +| | | 9 bytes (included) | +------------------------------+------------------------------------------------------------------------------+---------------------------+ -| `bytecode_length` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | -| | | 9 bytes (included) | +| `bytecode_length` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | +| | | 9 bytes (included) | +------------------------------+------------------------------------------------------------------------------+---------------------------+ -| `bytecode` | Raw bytes of bytecode to execute. | From 0 to 10,000,000 bytes| +| `bytecode` | Raw bytes of bytecode to execute. | From 0 to 10,000,000 bytes| +------------------------------+------------------------------------------------------------------------------+---------------------------+ -| `operation_datastore_length` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | -| | | 9 bytes (included) | +| `operation_datastore_length` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | +| | | 9 bytes (included) | +------------------------------+------------------------------------------------------------------------------+---------------------------+ -| `operation_datastore_items` | Concatenated datastore items. | See below. | +| `operation_datastore_items` | Concatenated datastore items. | See below. | +------------------------------+------------------------------------------------------------------------------+---------------------------+ Datastore item binary format: +---------------------+------------------------------------------------------------+----------------------------+ -| Datastore Item Binary Representation | +| Datastore Item Binary Representation | +---------------------+------------------------------------------------------------+----------------------------+ -| Field | Description | Type | +| Field | Description | Type | +=====================+============================================================+============================+ -| `key length` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | -| | | 9 bytes (included) | +| `key length` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | +| | | 9 bytes (included) | +---------------------+------------------------------------------------------------+----------------------------+ -| `key` | Raw key byte array. | From 0 byte (included) to | -| | | 255 bytes (included) | +| `key` | Raw key byte array. | From 0 byte (included) to | +| | | 255 bytes (included) | +---------------------+------------------------------------------------------------+----------------------------+ -| `value length` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | -| | | 9 bytes (included) | +| `value length` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to | +| | | 9 bytes (included) | +---------------------+------------------------------------------------------------+----------------------------+ -| `value` | Raw value byte array. | From 0 byte (included) to | -| | | 10,000,000 bytes (included)| +| `value` | Raw value byte array. | From 0 byte (included) to | +| | | 10,000,000 bytes (included)| +---------------------+------------------------------------------------------------+----------------------------+ Legality checks performed at binary deserialization: -* bytecode length is inferior or equal to 10,000,000 -* datastore length is inferior or equal to 128 -* all datastore key lengths are inferior or equal to 255 -* all datastore value lengths are inferior or equal to 10,000,000 +- bytecode length is inferior or equal to 10,000,000 +- datastore length is inferior or equal to 128 +- all datastore key lengths are inferior or equal to 255 +- all datastore value lengths are inferior or equal to 10,000,000 #### CallSC operation payload - The binary serialization format of the payload of a an Call SC operation follows: +------------------------+--------------------------------------------------------------------------------+-------------------------------------------------------+ -| Payload of a Call SC Operation | +| Payload of a Call SC Operation | +------------------------+--------------------------------------------------------------------------------+-------------------------------------------------------+ -| Field | Description | Type | +| Field | Description | Type | +========================+================================================================================+=======================================================+ -| `max_gas` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to 9 bytes (included) | +| `max_gas` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to 9 bytes (included) | +------------------------+--------------------------------------------------------------------------------+-------------------------------------------------------+ -| `coins` | Coin amount binary serialization (see [Coin amount section](#coin-amounts)). | From 1 byte (included) to 9 bytes (included) | +| `coins` | Coin amount binary serialization (see [Coin amount section](#coin-amounts)). | From 1 byte (included) to 9 bytes (included) | +------------------------+--------------------------------------------------------------------------------+-------------------------------------------------------+ -| `target_address` | Target address binary representation, see [Address section](#address). | From 34 bytes (included) to 50 bytes (included) | +| `target_address` | Target address binary representation, see [Address section](#address). | From 34 bytes (included) to 50 bytes (included) | +------------------------+--------------------------------------------------------------------------------+-------------------------------------------------------+ -| `function_name_length` | Varint unsigned 16-bit integer using protobuf conventions. | From 1 byte (included) to 3 bytes (included) | +| `function_name_length` | Varint unsigned 16-bit integer using protobuf conventions. | From 1 byte (included) to 3 bytes (included) | +------------------------+--------------------------------------------------------------------------------+-------------------------------------------------------+ -| `function_name` | Name of the function to call encoded as UTF-8 string without null termination. | From 0 bytes (included) to 65535 bytes (included) | +| `function_name` | Name of the function to call encoded as UTF-8 string without null termination. | From 0 bytes (included) to 65535 bytes (included) | +------------------------+--------------------------------------------------------------------------------+-------------------------------------------------------+ -| `param_length` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to 9 bytes (included) | +| `param_length` | Varint unsigned 64-bit integer using protobuf conventions. | From 1 byte (included) to 9 bytes (included) | +------------------------+--------------------------------------------------------------------------------+-------------------------------------------------------+ -| `param` | Raw bytes to pass as argument to the called function. | From 0 byte (included) to 10,000,000 bytes (included) | +| `param` | Raw bytes to pass as argument to the called function. | From 0 byte (included) to 10,000,000 bytes (included) | +------------------------+--------------------------------------------------------------------------------+-------------------------------------------------------+ - Legality checks performed at binary deserialization: -* coins must be a legal coin amount (see [Coin amount section](#coin-amounts)) -* target address must be a legal address (see [Address section](#address)) -* function name length must be inferior or equal to 65535 -* function name must be valid UTF-8 -* param length must be inferior or equal to 10,000,000 + +- coins must be a legal coin amount (see [Coin amount section](#coin-amounts)) +- target address must be a legal address (see [Address section](#address)) +- function name length must be inferior or equal to 65535 +- function name must be valid UTF-8 +- param length must be inferior or equal to 10,000,000 ### Chain id The chain id is an unsigned 64 bit value used to avoid replay attacks between Massa networks. +---------------------+-------------------------------------------+ -| Chain id values | +| Chain id values | +---------------------+-------------------------------------------+ -| Network | Value | +| Network | Value | +=====================+===========================================+ -| MainNet | 77658377 | +| MainNet | 77658377 | +---------------------+-------------------------------------------+ -| BuildNet | 77658366 | +| BuildNet | 77658366 | +---------------------+-------------------------------------------+ -| SecureNet | 77658383 | +| SecureNet | 77658383 | +---------------------+-------------------------------------------+ -| LabNet | 77658376 | +| LabNet | 77658376 | +---------------------+-------------------------------------------+ -| Sandbox | 77 | +| Sandbox | 77 | +---------------------+-------------------------------------------+ Binary serialization format of the chain id: +---------------------+---------------------------------------------+---------------------------------------------+ -| Signature Binary Representation | +| Signature Binary Representation | +---------------------+---------------------------------------------+---------------------------------------------+ -| Field | Description | Type | +| Field | Description | Type | +=====================+=============================================+=============================================+ -| `chain id` | unsigned 64-bit integer as big endian bytes | 8 bytes | +| `chain id` | unsigned 64-bit integer as big endian bytes | 8 bytes | +---------------------+---------------------------------------------+---------------------------------------------+ ### Example of legal operation with valid signature -* Chain id: 77658383 -* Sender Secret key in text format: `S1CkpvD4WMjJWxR2WZcrDEkJ1kWG2kKe1e3Afe8miqmskHqovvA` -* Sender Public key in text format: `P1t4JZwHhWNLt4xYabCbukyVNxSbhYPdF6wCYuRmDuHD784juxd` -* Sender Address in text format: `AU12m1gXHUGxBZsDF4veeWfYaRmpztBCieHhPBaqf3fcRF2LdAuZ7` -* Operation fee: `0.001` -* Operation expiry period: `1000` -* Operation type: `Transaction` -* Transaction operation payload: - * Destination address in text format: `AU12v83xmHg2UrLM8GLsXRMrm7LQgn3DZVT6kUeFsuFyhZKLkbQtY` - * Amount: `3.1` +- Chain id: 77658383 +- Sender Secret key in text format: `S1CkpvD4WMjJWxR2WZcrDEkJ1kWG2kKe1e3Afe8miqmskHqovvA` +- Sender Public key in text format: `P1t4JZwHhWNLt4xYabCbukyVNxSbhYPdF6wCYuRmDuHD784juxd` +- Sender Address in text format: `AU12m1gXHUGxBZsDF4veeWfYaRmpztBCieHhPBaqf3fcRF2LdAuZ7` +- Operation fee: `0.001` +- Operation expiry period: `1000` +- Operation type: `Transaction` +- Transaction operation payload: + - Destination address in text format: `AU12v83xmHg2UrLM8GLsXRMrm7LQgn3DZVT6kUeFsuFyhZKLkbQtY` + - Amount: `3.1` Resulting operation ID in text format: `O12CRpeqSW1NenBZ7pN79ZZz454xkbeQBGspyu4gKVXcYndm8gxw` @@ -610,19 +627,19 @@ operations are propagated using optimized gossip algorithms. ### Operation submission When the API of a peer is called to submit an operation: -* the operation is [checked for legality](#operation-format-and-legality) - * if the operation is not legal, it is rejected and an error message is returned by the API -* the operation is [added to the operation pool of the peer](#operation-pool-and-operation-inclusion) -* the operation is submitted to a [broadcasting thread](#operation-broadcasting) +- the operation is [checked for legality](#operation-format-and-legality) + - if the operation is not legal, it is rejected and an error message is returned by the API +- the operation is [added to the operation pool of the peer](#operation-pool-and-operation-inclusion) +- the operation is submitted to a [broadcasting thread](#operation-broadcasting) ### Operation broadcasting -The broadcasting thread keeps sumbitted operations in memory for at least 32 seconds with a cap of 32000 operations being propagated at the same time. +The broadcasting thread keeps submitted operations in memory for at least 32 seconds with a cap of 32000 operations being propagated at the same time. It also keeps LRU caches of operations already processed by the current peer, and by other peers it is connected to. When an operation is submitted to the broadcasting thread, it is first checked for expiry (expired operations are dropped), -and ignored if it is already being propagated. +and ignored if it is already being propagated. The broadcasting thread announces the operation IDs of the operations being broadcast to connected peers with batching. Only operation IDs not already known by a given peer are announced to it. @@ -639,23 +656,25 @@ Remote peers that are known to be aware of a given operation ID are prioritized Timeouts are applied as well to re-attempt retrieval from other peers in case of failure. When a batch of full operations is received: -* the sender peer is marked as knowing about these operations in the current peer's caches. -* the operations are checked for legality with batched parallel signature verification (see [operation legality section](#operation-format-and-legality)) - * if any of the operations is not legal, the batch is dropped, and the sender peer is bannned -* the operations are added to the peer's operation pool (see [Pool and Operation inclusion](#operation-pool-and-operation-inclusion)) -* the operations are submitted to the broadcasting thread + +- the sender peer is marked as knowing about these operations in the current peer's caches. +- the operations are checked for legality with batched parallel signature verification (see [operation legality section](#operation-format-and-legality)) + - if any of the operations is not legal, the batch is dropped, and the sender peer is banned +- the operations are added to the peer's operation pool (see [Pool and Operation inclusion](#operation-pool-and-operation-inclusion)) +- the operations are submitted to the broadcasting thread ### Operation propagation within blocks -Blocks contain arbtirary operations chosen by the block producer. +Blocks contain arbitrary operations chosen by the block producer. Block retrieval in Massa makes use of the propagation caches to only ask for operations that are not already known by the current peer. This effectively avoids re-doing operation propagation and legality checks for block operations that have already propagated by themselves previously. When a block is received, if any of the following happen the block is rejected (and its senders are banned): -* any included operation is not legal (see the [legality section](#operation-format-and-legality)) -* the batched parallel signature verification of all the block operations is not a success -* the block operations root hash does not match the one in the header -* the cumulated size of all the operations in the block is strictly above 1MB + +- any included operation is not legal (see the [legality section](#operation-format-and-legality)) +- the batched parallel signature verification of all the block operations is not a success +- the block operations root hash does not match the one in the header +- the cumulated size of all the operations in the block is strictly above 1MB This detects non-legal blocks early and prevents them from propagating in the network. @@ -664,7 +683,6 @@ This detects non-legal blocks early and prevents them from propagating in the ne The `total_gas` of an operation is the total amount of gas reserved for its processing, preparation and execution. It depends on the type of operation. - ### Transaction, RollBuy, RollSell operations The `total_gas` of those types of operations is always 800000 which corresponds to their base processing cost. @@ -672,6 +690,7 @@ The `total_gas` of those types of operations is always 800000 which corresponds ### CallSC operations The `total_gas` of a CallSC operation `op` is computed as follows: + ``` total_gas = 800000 (base operation processing gas cost) @@ -681,6 +700,7 @@ total_gas = ### ExecuteSC operations The `total_gas` of an ExecuteSC operation `op` is computed as follows: + ``` total_gas = 800000 (base operation processing gas cost) @@ -688,7 +708,6 @@ total_gas = + op.max_gas (the maximum gas reserved for bytecode execution, as provided in the `max_gas` field of the operation) ``` - ## Operation execution When the consensus algorithm outputs the list of slots to execute, @@ -705,10 +724,10 @@ in order to save resources. This means that the candidate execution state of an operation can be observed after two seconds (or more) following the propagation of the block in which it was included. Overall, the deeper the slot is in the past, the exponentially more stable its candidate execution state is, -up to finality after which it is guaranteed not to change anymore. +up to finality after which it is guaranteed not to change anymore. The final cursor attempts to execute all final slots up to the latest one. -Final execution is prioritary over candidate execution: +Final execution is prioritized over candidate execution: as long as there are slots to finalize, they are processed before candidate slots. If a finalizing slot was previously executed as candidate and neither itself nor any if its ancestors has changed since the execution, the results of the slot's candidate execution are simply written to the final state to avoid re-executing it. @@ -716,75 +735,81 @@ the results of the slot's candidate execution are simply written to the final st When a slot is executed, if it contains a block, that block is executed. THe block's operations are tentatively executed in the order they appear in the block. For each operation in a block, the following is performed: -* Gas check: if the remaining block gas (starting from `MAX_BLOCK_GAS = 4294967295`) is not enough to supply the operation's `total_gas`, the operation is ignored. -* Thread check: if the thread of the operation sender does not match the thread of the block, the operation is ignored. -* Period check: if the slot period of the block is not within the range of validity periods of the operation, the operation is ignored. The validity period interval of an operation `Op` is: `[expiration_period - 10, expiration_period]`. -* Reuse check: if the operation is in the list of executed operations, the operation is ignored. -* Fee spending: spend the fee from the sender's account. If this spending fails, ignore the operation. -* Subtract the operation's `total_gas` from the remaining block gas. -* Add the operation to the list of executed operations. Note that operations with an expiry period that is earlier or equal to the latest final period in the operation's thread are removed from this list after 10 extra periods in order to cap memory use. -* If any of the previous steps failed, the operation is considered **NOT EXECUTED**, it is ignored and the block producer does not pocket any fees from it while wasting block space. Block producers should therefore be careful about the operations they choose to include or they might not get any fees from them. Thanks to sharding and the declarative `max_gas` and `max_coins` operation fields, block prodcuers can keep track of balances and gas usage without having to simulate the complete execution of candidate operations in order to avoid this pitfall. -* From there on, the operation is considered executed. -* Run the payload of the operation (for example call a smart contract). This can succeed or fail. - * In case of payload run failure, all the consequences of the payload run are rolled back, but the fee is still spent and the operation is still considered executed. This is because block producers have not enough computing power to simulate running all pending operations: this failure is the operation producer's responsibility. In this case, the operation is then considered **EXECUTED WITH FAILURE**. - * In case of payload run success, the consequences of the execution are kept, and the operation is considered **EXECUTED WITH SUCCESS**. + +- Gas check: if the remaining block gas (starting from `MAX_BLOCK_GAS = 4294967295`) is not enough to supply the operation's `total_gas`, the operation is ignored. +- Thread check: if the thread of the operation sender does not match the thread of the block, the operation is ignored. +- Period check: if the slot period of the block is not within the range of validity periods of the operation, the operation is ignored. The validity period interval of an operation `Op` is: `[expiration_period - 10, expiration_period]`. +- Reuse check: if the operation is in the list of executed operations, the operation is ignored. +- Fee spending: spend the fee from the sender's account. If this spending fails, ignore the operation. +- Subtract the operation's `total_gas` from the remaining block gas. +- Add the operation to the list of executed operations. Note that operations with an expiry period that is earlier or equal to the latest final period in the operation's thread are removed from this list after 10 extra periods in order to cap memory use. +- If any of the previous steps failed, the operation is considered **NOT EXECUTED**, it is ignored and the block producer does not pocket any fees from it while wasting block space. Block producers should therefore be careful about the operations they choose to include or they might not get any fees from them. Thanks to sharding and the declarative `max_gas` and `max_coins` operation fields, block producers can keep track of balances and gas usage without having to simulate the complete execution of candidate operations in order to avoid this pitfall. +- From there on, the operation is considered executed. +- Run the payload of the operation (for example call a smart contract). This can succeed or fail. + - In case of payload run failure, all the consequences of the payload run are rolled back, but the fee is still spent and the operation is still considered executed. This is because block producers have not enough computing power to simulate running all pending operations: this failure is the operation producer's responsibility. In this case, the operation is then considered **EXECUTED WITH FAILURE**. + - In case of payload run success, the consequences of the execution are kept, and the operation is considered **EXECUTED WITH SUCCESS**. Different types of operations have different payload run failure cases: -* `Transaction`: fails if the balance of the origin account is not enough to cover the amount of the transaction. -* `RollBuy`: fails if the balance of the origin account is not enough to cover the amount of the roll buy. -* `RollSell`: fails if the the origin account has not enough rolls to sell. -* `CallSC`: fails if any of the following happen: - * the balance of the origin account is not enough to cover the coins being transferred - * the target smart contract is not found - * the target smart contract has invalid bytecode - * the target smart contract exposes no function with the given name and expected prototype. - * the smart contract execution in the VM exceeds `max_gas` - * the smart contract execution in the VM raises a runtime exception -* `ExecuteSC`: fails if any of the following happen: - * the bytecode is invalid - * the bytecode does not expose a `main` function with the right prototype - * the smart contract execution in the VM exceeds `max_gas` - * the smart contract execution in the VM raises a runtime exception - * the smart contract execution spends more than `max_coins` from the sender account + +- `Transaction`: fails if the balance of the origin account is not enough to cover the amount of the transaction. +- `RollBuy`: fails if the balance of the origin account is not enough to cover the amount of the roll buy. +- `RollSell`: fails if the the origin account has not enough rolls to sell. +- `CallSC`: fails if any of the following happen: + - the balance of the origin account is not enough to cover the coins being transferred + - the target smart contract is not found + - the target smart contract has invalid bytecode + - the target smart contract exposes no function with the given name and expected prototype. + - the smart contract execution in the VM exceeds `max_gas` + - the smart contract execution in the VM raises a runtime exception +- `ExecuteSC`: fails if any of the following happen: + - the bytecode is invalid + - the bytecode does not expose a `main` function with the right prototype + - the smart contract execution in the VM exceeds `max_gas` + - the smart contract execution in the VM raises a runtime exception + - the smart contract execution spends more than `max_coins` from the sender account The operation execution process in Massa implies some peculiarities: -* the same operation can be included zero, one or many times in the same block or in different blocks but is executed either 0 or 1 times in total -* it is not because an operation is included in a final block that the operation is executed as final + +- the same operation can be included zero, one or many times in the same block or in different blocks but is executed either 0 or 1 times in total +- it is not because an operation is included in a final block that the operation is executed as final ## Operation pool and operation inclusion When creating blocks, block producers are free to include the operations they want in their blocks with certain constraints that would make the block non-legal and rejected at reception if they are not respected: -* all operations in the block need to be well-formed -* all the signatures of the included operations need to be legal -* the cumulated size of all the operations in the block must be at most 1MB + +- all operations in the block need to be well-formed +- all the signatures of the included operations need to be legal +- the cumulated size of all the operations in the block must be at most 1MB Block producers keep candidate operations in their operation pool. However, memory constraints on block producer hardware require regular pruning of this pool to keep it small and tailored to the block producer's needs: -* discard operations that do not match the legality constraints listed above -* discard operations that can not be included by this block producer given the expiry periods of the operation and proof-of-stake draws + +- discard operations that do not match the legality constraints listed above +- discard operations that can not be included by this block producer given the expiry periods of the operation and proof-of-stake draws Block producers maximize their gains by prioritizing the operations that maximize their expected rewards. However, they don't have the computational power to simulate the execution of all potential operations. To solve this problem, operations are scored by block producers to estimate their expected rewards. This is done by a scoring algorithm that takes into account: -* the expected rewards coming from the operation's `fee` -* the probability of executing of the operation based on: - * whether the operation was already executed previously - * the number of opportunities other block producers have to execute the operation before the current node gets a chance to include it based on proof-of-stake selections -* the usage of resources by the operation: - * the operation size (occupying space in the finite block size) - * the operation `total_gas` (occupying gas in the finite block gas `MAX_BLOCK_GAS`) -Operations are then kept sorted by score, and the ones with the worst scores are discarded to respect the max size of the pool. + +- the expected rewards coming from the operation's `fee` +- the probability of executing of the operation based on: + - whether the operation was already executed previously + - the number of opportunities other block producers have to execute the operation before the current node gets a chance to include it based on proof-of-stake selections +- the usage of resources by the operation: + - the operation size (occupying space in the finite block size) + - the operation `total_gas` (occupying gas in the finite block gas `MAX_BLOCK_GAS`) + Operations are then kept sorted by score, and the ones with the worst scores are discarded to respect the max size of the pool. Sorted operations are then scanned based on their declarative coin spending (`fee + max_coins`) -and operations that overflow their sender's candidate balance given those cumulated spendings are discarded. +and operations that overflow their sender's candidate balance given those cumulated spending are discarded. The accurate evaluation of the balance without execution is made possible by sharding: no operation executed in blocks being created elsewhere at the same time can spend those coins. This protects the pool from flood attacks and guarantees that the operation fees can be spent. -In Massa, operation pools are highly non-deterministic and depend on each block producer's proof-of-stake draws. +In Massa, operation pools are highly non-deterministic and depend on each block producer's proof-of-stake draws. The operation pool can therefore not be used as a reliable source of information about the propagation state of an operation. ## Operation execution status and finality @@ -793,23 +818,25 @@ Because of the peculiar way Massa handles operations to achieve its scalability, tracking the state of execution of an operation requires understanding certain principles. At the output of an executed slot `S`, an operation can be in one of the following observable states: -* `EXECUTABLE_OR_EXPIRED`: the operation is not in the list of previously executed operations at the output of `S`: - * If the operation's expiry date is earlier or equal to the period of `S`, then the operation can not be executed anymore: - * The operation might never have been executed previously - * The operation might have been executed in a slot that finalized more than 10 periods ago. This is because the list of executed operations is pruned to limit its memory usage (see [operation execution section](#operation-execution)). - * Otherwise, it means that the operation was never executed and can be executed in the future. -* `EXECUTED_WITH_SUCCESS`: the operation was executed at or before `S` and its payload run was successful (see [operation execution section](#operation-execution)). The operation can not be executed anymore. -* `EXECUTED_WITH_FAILURE`: the operation was executed at or before `S` and its payload run generated errors (see [operation execution section](#operation-execution)). The operation can not be executed anymore. + +- `EXECUTABLE_OR_EXPIRED`: the operation is not in the list of previously executed operations at the output of `S`: + - If the operation's expiry date is earlier or equal to the period of `S`, then the operation can not be executed anymore: + - The operation might never have been executed previously + - The operation might have been executed in a slot that finalized more than 10 periods ago. This is because the list of executed operations is pruned to limit its memory usage (see [operation execution section](#operation-execution)). + - Otherwise, it means that the operation was never executed and can be executed in the future. +- `EXECUTED_WITH_SUCCESS`: the operation was executed at or before `S` and its payload run was successful (see [operation execution section](#operation-execution)). The operation can not be executed anymore. +- `EXECUTED_WITH_FAILURE`: the operation was executed at or before `S` and its payload run generated errors (see [operation execution section](#operation-execution)). The operation can not be executed anymore. If the slot `S` is the latest candidate slot, then the observed status of a given operation at the output of `S` is considered candidate. As candidate slots are executed, candidate operation states can transition from any state into any other because blockclique changes might happen and rewrite the slot history. If the slot `S` is the latest executed final slot, then the observed status of a given operation at the output of `S` is considered final. As final slots are executed, the following final operation state transitions can be observed: -* `EXECUTABLE_OR_EXPIRED` -> `EXECUTED_WITH_SUCCESS`: the operation was executed as final with success -* `EXECUTABLE_OR_EXPIRED` -> `EXECUTED_WITH_FAILURE`: the operation was executed as final with failure -* `EXECUTED_WITH_SUCCESS` -> `EXECUTABLE_OR_EXPIRED`: the operation was executed as final with success and then it expired and was pruned away -* `EXECUTED_WITH_FAILURE` -> `EXECUTABLE_OR_EXPIRED`: the operation was executed as final with failure and then it expired and was pruned away + +- `EXECUTABLE_OR_EXPIRED` -> `EXECUTED_WITH_SUCCESS`: the operation was executed as final with success +- `EXECUTABLE_OR_EXPIRED` -> `EXECUTED_WITH_FAILURE`: the operation was executed as final with failure +- `EXECUTED_WITH_SUCCESS` -> `EXECUTABLE_OR_EXPIRED`: the operation was executed as final with success and then it expired and was pruned away +- `EXECUTED_WITH_FAILURE` -> `EXECUTABLE_OR_EXPIRED`: the operation was executed as final with failure and then it expired and was pruned away Operations are guaranteed to be kept in the `EXECUTED_WITH_SUCCESS` or `EXECUTED_WITH_FAILURE` state for at least 10 periods (2 minutes and 40 seconds) to give enough time for operators to register those states before they are pruned.