diff --git a/src/SUMMARY.md b/src/SUMMARY.md index c04475c9..a9a44b78 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -13,6 +13,7 @@ - [Transaction Pointer](./tx-format/tx-pointer.md) - [Computing Identifiers](./identifiers/index.md) - [Asset ID](./identifiers/asset.md) + - [Blob ID](./identifiers/blob-id.md) - [Contract ID](./identifiers/contract-id.md) - [Predicate ID](./identifiers/predicate-id.md) - [Transaction ID](./identifiers/transaction-id.md) diff --git a/src/fuel-vm/instruction-set.md b/src/fuel-vm/instruction-set.md index 1f4c4ab1..811c12b7 100644 --- a/src/fuel-vm/instruction-set.md +++ b/src/fuel-vm/instruction-set.md @@ -91,7 +91,7 @@ - [`CCP`: Code copy](#ccp-code-copy) - [`CROO`: Code Merkle root](#croo-code-merkle-root) - [`CSIZ`: Code size](#csiz-code-size) - - [`LDC`: Load code from an external contract](#ldc-load-code-from-an-external-contract) + - [`LDC`: Load code from an external contract](#ldc-load-code-from-an-external-contract-or-blob) - [`LOG`: Log event](#log-log-event) - [`LOGD`: Log data event](#logd-log-data-event) - [`MINT`: Mint new coins](#mint-mint-new-coins) @@ -106,6 +106,9 @@ - [`TIME`: Timestamp at height](#time-timestamp-at-height) - [`TR`: Transfer coins to contract](#tr-transfer-coins-to-contract) - [`TRO`: Transfer coins to output](#tro-transfer-coins-to-output) +- [Blob Instructions](#blob-instructions) + - [`BSIZ`: Blob size](#bsiz-blob-size) + - [`BLDD`: Load data from a blob](#bldd-load-data-from-a-blob) - [Cryptographic Instructions](#cryptographic-instructions) - [`ECK1`: Secp251k1 signature recovery](#eck1-secp256k1-signature-recovery) - [`ECR1`: Secp256r1 signature recovery](#ecr1-secp256r1-signature-recovery) @@ -1749,7 +1752,7 @@ Panic if: | Notes | If `$rD` is greater than the code size, zero bytes are filled in. | This is used only for reading and inspecting code of other contracts. -Use [`LDC`](#ldc-load-code-from-an-external-contract) to load code for executing. +Use [`LDC`](#ldc-load-code-from-an-external-contract-or-blob) to load code for executing. Panic if: @@ -1793,27 +1796,37 @@ Panic if: - `$rB + 32` overflows or `> VM_MAX_RAM` - Contract with ID `MEM[$rB, 32]` is not in `tx.inputs` -### `LDC`: Load code from an external contract +### `LDC`: Load code from an external contract or blob | | | |-------------|---------------------------------------------------------------------------------------------------------------------------------------------------| -| Description | Copy `$rC` bytes of code starting at `$rB` for contract with ID equal to the 32 bytes in memory starting at `$rA` into memory starting at `$ssp`. | -| Operation | ```MEM[$ssp, $rC] = code($rA, $rB, $rC);``` | -| Syntax | `ldc $rA, $rB, $rC` | -| Encoding | `0x00 rA rB rC -` | +| Description | Copy `$rC` bytes of code at offset `$rB` from object with 32 byte id starting at `$rA` into memory starting at `$ssp`. Object type is in `imm`. | +| Operation | `id = mem[$rA,32]; code = match imm { 0 => contract_code($id), 1 => blob_payload($id) }; MEM[$ssp, $rC] = code[$rB, $rC];` | +| Syntax | `ldc $rA, $rB, $rC, imm` | +| Encoding | `0x00 rA rB rC imm` | | Notes | If `$rC` is greater than the code size, zero bytes are filled in. | +Object type from `imm` determined the source for loading as follows: + +| `imm` | Object type | +|-------|---------------| +| `0` | Contract code | +| `1` | Blob payload | +| other | _reserved_ | + Panic if: - `$ssp + $rC` overflows or `> VM_MAX_RAM` - `$rA + 32` overflows or `> VM_MAX_RAM` - `$ssp + $rC >= $hp` -- `$rC > CONTRACT_MAX_SIZE` -- Contract with ID `MEM[$rA, 32]` is not in `tx.inputs` +- `imm == 0` and `$rC > CONTRACT_MAX_SIZE` +- `imm == 0` and contract with ID `MEM[$rA, 32]` is not in `tx.inputs` +- `imm == 1` and contract with ID `MEM[$rA, 32]` is not found in the chain state +- `imm >= 2` (reserved value) Increment `$fp->codesize`, `$ssp` by `$rC` padded to word alignment. Then set `$sp` to `$ssp`. -This instruction can be used to concatenate the code of multiple contracts together. It can only be used when the stack area of the call frame is zero-sized. +This instruction can be used to concatenate the code of multiple contracts or blobs together. It can only be used when the stack area of the call frame is zero-sized. ### `LOG`: Log event @@ -2217,6 +2230,41 @@ In an external context, decrease `MEM[balanceOfStart(MEM[$rD, 32]), 8]` by `$rC` This modifies the `balanceRoot` field of the appropriate output(s). +## Blob Instructions + +All these instructions advance the program counter `$pc` by `4` after performing their operation. + +### `BSIZ`: Blob size + +| | | +|-------------|-----------------------------------------------------------------------------------------------------------| +| Description | Set `$rA` to the size of the blob with ID equal to the 32 bytes in memory starting at `$rB`. | +| Operation | `$rA = len(blob(MEM[$rB, 32]));` | +| Syntax | `bsiz $rA, $rB` | +| Encoding | `0x00 rA rB - -` | +| Notes | | + +Panic if: + +- `$rA` is a [reserved register](./index.md#semantics) +- `$rB + 32` overflows or `> VM_MAX_RAM` +- Blob ID `MEM[$rB, 32]` is not found + +### `BLDD`: Load data from a blob + +|-------------|-------------------------------------------------------------------------------------------------------------| +| Description | Load 32-byte blob id at `$rB`, and copy `$rD` bytes starting from `$rC` into `$sA`. | +| Operation | `MEM[$rA, $rD] = blob(MEM[$rB, 32])[$rC, $rD];` | +| Syntax | `bldd $rA, $rB, rC, $rD` | +| Encoding | `0x00 rA rB rC rD` | +| Notes | If `$rC >` blob size, zero bytes are filled in. | + +Panic if: + +- `$rA + $rD` overflows or `> VM_MAX_RAM` or `> $hp` +- `$rB + 32` overflows or `> VM_MAX_RAM` +- Blob ID `MEM[$rB, 32]` is not found + ## Cryptographic Instructions All these instructions advance the program counter `$pc` by `4` after performing their operation. diff --git a/src/identifiers/blob-id.md b/src/identifiers/blob-id.md new file mode 100644 index 00000000..8c7e062e --- /dev/null +++ b/src/identifiers/blob-id.md @@ -0,0 +1,10 @@ +# Blob ID + +The _blob ID_ (also called _blob hash_) of a transaction is computed as +the [hash](../protocol/cryptographic-primitives.md#hashing) of the blob data. + +Blob ID calculation doesn't vary between chains. + +```python +sha256(blob_data) +``` diff --git a/src/identifiers/index.md b/src/identifiers/index.md index 0cff02bb..52bf2c84 100644 --- a/src/identifiers/index.md +++ b/src/identifiers/index.md @@ -3,6 +3,7 @@ This chapter defines how to compute unique identifiers. - [Asset ID](./asset.md) +- [Blob ID](./blob-id.md) - [Contract ID](./contract-id.md) - [Predicate ID](./predicate-id.md) - [Transaction ID](./transaction-id.md) diff --git a/src/tx-format/index.md b/src/tx-format/index.md index bfc91a1f..ade5b18e 100644 --- a/src/tx-format/index.md +++ b/src/tx-format/index.md @@ -7,6 +7,9 @@ The Fuel Transaction Format. - [`TransactionScript`](./transaction.md#transactionscript) - [`TransactionCreate`](./transaction.md#transactioncreate) - [`TransactionMint`](./transaction.md#transactionmint) + - [`TransactionUpgrade`](./transaction.md#transactionupgrade) + - [`TransactionUpload`](./transaction.md#transactionupload) + - [`TransactionBlob`](./transaction.md#transactionblob) - [Input](./input.md) - [`InputCoin`](./input.md#inputcoin) - [`InputContract`](./input.md#inputcontract) diff --git a/src/tx-format/transaction.md b/src/tx-format/transaction.md index 06bfc67a..1d223abe 100644 --- a/src/tx-format/transaction.md +++ b/src/tx-format/transaction.md @@ -7,6 +7,7 @@ enum TransactionType : uint8 { Mint = 2, Upgrade = 3, Upload = 4, + Blob = 5, } ``` @@ -232,3 +233,31 @@ Transaction is invalid if: - `subsectionIndex` >= `subsectionsNumber` - `subsectionsNumber > MAX_BYTECODE_SUBSECTIONS` - The [Binary Merkle tree](../protocol/cryptographic-primitives.md#binary-merkle-tree) root calculated from `(witnesses[witnessIndex], subsectionIndex, subsectionsNumber, proofSet)` is not equal to the `root`. Root calculation is affected by all fields, so modification of one of them invalidates the proof. + +## `TransactionBlob` + +The `Blob` inserts a simple binary blob in the chain. It's raw immutable data that can be cheaply loaded by the VM and used as instructions or just data. Unlike `Create`, it doesn't hold any state or balances. + +`Blob`s are content-addressed, i.e. the they are uniquely identified by hash of the data field. Programs running on the VM can load an already-posted blob just by the hash, without having to specify it in contract inputs. + +| name | type | description | +|---------------------|-----------------------------|----------------------------------| +| `id` | `byte[32]` | Blob id, i.e. hash of the data. | +| `witnessIndex` | `uint16` | The witness index of the data. | +| `policyTypes` | `uint32` | Bitfield of used policy types. | +| `inputsCount` | `uint16` | Number of inputs. | +| `outputsCount` | `uint16` | Number of outputs. | +| `witnessesCount` | `uint16` | Number of witnesses. | +| `policies` | [Policy](./policy.md)`[]` | List of policies. | +| `inputs` | [Input](./input.md)`[]` | List of inputs. | +| `outputs` | [Output](./output.md)`[]` | List of outputs. | +| `witnesses` | [Witness](./witness.md)`[]` | List of witnesses. | + +Transaction is invalid if: + +- Any input is of type `InputType.Contract` or `InputType.Message` where `input.dataLength > 0` +- Any input uses non-base asset. +- Any output is of type `OutputType.Contract` or `OutputType.Variable` or `OutputType.Message` or `OutputType.ContractCreated` +- Any output is of type `OutputType.Change` with non-base `asset_id` +- `witnessIndex >= tx.witnessesCount` +- `sha256(witnesses[witnessIndex]) != id`