Skip to content

Commit

Permalink
Blob tx and instructions (#592)
Browse files Browse the repository at this point in the history
Work towards #589. The VM
PR FuelLabs/fuel-vm#780 contains a working
implementation.

To allow contracts larger than the contract size limit, and to allow
upgradability, we'll be adding a new tx type that's just a bunch of
bytes, and opcodes to load subsections of that. A *blob* will be like a
contract, but without state or balances, allowing it to be quite a bit
cheaper. The new instructions `BSIZ` and `BLDD` and the new blob mode
for `LDC` closely follow how `CSIZ`, `LDC` and `CCP` work, but only
operation on blob data.

### Before requesting review
- [x] I have reviewed the code myself
  • Loading branch information
Dentosal authored Jul 31, 2024
1 parent 6ebbe21 commit f182c55
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 10 deletions.
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
68 changes: 58 additions & 10 deletions src/fuel-vm/instruction-set.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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:

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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.
Expand Down
10 changes: 10 additions & 0 deletions src/identifiers/blob-id.md
Original file line number Diff line number Diff line change
@@ -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)
```
1 change: 1 addition & 0 deletions src/identifiers/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions src/tx-format/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
29 changes: 29 additions & 0 deletions src/tx-format/transaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ enum TransactionType : uint8 {
Mint = 2,
Upgrade = 3,
Upload = 4,
Blob = 5,
}
```

Expand Down Expand Up @@ -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`

0 comments on commit f182c55

Please sign in to comment.