Skip to content

Commit

Permalink
Add Message Input/Output & receipt (#149)
Browse files Browse the repository at this point in the history
Include message input and output with their respective validation rules.

This commit will introduce a stateful property to the transaction
validation. A valid transaction might not be validated anymore in
post-execution since its outputs might be mutated at runtime in the VM.

Related issue: FuelLabs/fuel-specs#318
  • Loading branch information
vlopes11 authored Jul 1, 2022
1 parent 22919ae commit 0292d22
Show file tree
Hide file tree
Showing 24 changed files with 1,293 additions and 426 deletions.
2 changes: 2 additions & 0 deletions fuel-tx/.github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ jobs:
args: --all --verbose -- --check
- command: clippy
args: --all-targets --all-features
- command: check
args: --all-targets
- command: check
args: --all-targets --all-features
- command: check
Expand Down
9 changes: 7 additions & 2 deletions fuel-tx/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repository = "https://github.com/FuelLabs/fuel-tx"
description = "FuelVM transaction."

[dependencies]
fuel-asm = { version = "0.5", default-features = false }
fuel-asm = { version = "0.6", default-features = false }
fuel-crypto = { version = "0.5", default-features = false }
fuel-merkle = { version = "0.2", default-features = false, optional = true }
fuel-types = { version = "0.5", default-features = false }
Expand All @@ -33,7 +33,7 @@ rstest = "0.13"
[features]
default = ["fuel-asm/default", "fuel-crypto/default", "fuel-merkle?/default", "fuel-types/default", "std"]
alloc = ["fuel-merkle", "fuel-types/alloc", "itertools/use_alloc", "serde/alloc"]
builder = ["alloc"]
builder = ["alloc", "internals"]
internals = []
random = ["fuel-crypto/random", "fuel-types/random", "rand"]
std = ["alloc", "fuel-asm/std", "fuel-crypto/std", "fuel-merkle?/std", "fuel-types/std", "itertools/default", "rand/default", "serde?/default"]
Expand All @@ -49,6 +49,11 @@ name = "test-offsets"
path = "tests/offset.rs"
required-features = ["std"]

[[test]]
name = "test-prepared-init"
path = "tests/prepared_init.rs"
required-features = ["std"]

[[test]]
name = "test-valid"
path = "tests/valid.rs"
Expand Down
21 changes: 20 additions & 1 deletion fuel-tx/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ impl<'a> TransactionBuilder<'a> {
#[cfg(feature = "std")]
pub fn add_unsigned_coin_input(
&mut self,
utxo_id: crate::UtxoId,
secret: &'a SecretKey,
utxo_id: crate::UtxoId,
amount: Word,
asset_id: fuel_types::AssetId,
maturity: Word,
Expand All @@ -99,6 +99,25 @@ impl<'a> TransactionBuilder<'a> {
self
}

#[cfg(feature = "std")]
pub fn add_unsigned_message_input(
&mut self,
secret: &'a SecretKey,
sender: fuel_types::Address,
recipient: fuel_types::Address,
nonce: Word,
amount: Word,
data: Vec<u8>,
) -> &mut Self {
let pk = secret.public_key();

self.sign_keys.push(secret);
self.tx
.add_unsigned_message_input(sender, recipient, nonce, &pk, amount, data);

self
}

pub fn inputs(&self) -> &[Input] {
self.tx.inputs()
}
Expand Down
147 changes: 143 additions & 4 deletions fuel-tx/src/receipt.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use fuel_asm::InstructionResult;
use fuel_types::bytes::{padded_len_usize, SizedBytes, WORD_SIZE};
use fuel_types::{Address, AssetId, Bytes32, ContractId, Word};
use fuel_types::bytes::{self, padded_len_usize, SizedBytes, WORD_SIZE};
use fuel_types::{Address, AssetId, Bytes32, ContractId, MessageId, Word};

use alloc::vec::Vec;

Expand All @@ -14,6 +14,8 @@ use receipt_repr::ReceiptRepr;

pub use script_result::ScriptExecutionResult;

use crate::Output;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Receipt {
Expand Down Expand Up @@ -104,6 +106,17 @@ pub enum Receipt {
result: ScriptExecutionResult,
gas_used: Word,
},

MessageOut {
message_id: MessageId,
sender: Address,
recipient: Address,
amount: Word,
nonce: Bytes32,
len: Word,
digest: Bytes32,
data: Vec<u8>,
},
}

impl Receipt {
Expand Down Expand Up @@ -136,7 +149,20 @@ impl Receipt {
Self::Return { id, val, pc, is }
}

pub const fn return_data(
pub fn return_data(
id: ContractId,
ptr: Word,
digest: Bytes32,
data: Vec<u8>,
pc: Word,
is: Word,
) -> Self {
let len = bytes::padded_len(&data) as Word;

Self::return_data_with_len(id, ptr, len, digest, data, pc, is)
}

pub const fn return_data_with_len(
id: ContractId,
ptr: Word,
len: Word,
Expand Down Expand Up @@ -184,7 +210,22 @@ impl Receipt {
}
}

pub const fn log_data(
pub fn log_data(
id: ContractId,
ra: Word,
rb: Word,
ptr: Word,
digest: Bytes32,
data: Vec<u8>,
pc: Word,
is: Word,
) -> Self {
let len = bytes::padded_len(&data) as Word;

Self::log_data_with_len(id, ra, rb, ptr, len, digest, data, pc, is)
}

pub const fn log_data_with_len(
id: ContractId,
ra: Word,
rb: Word,
Expand Down Expand Up @@ -248,6 +289,59 @@ impl Receipt {
Self::ScriptResult { result, gas_used }
}

pub fn message_out_from_tx_output(
txid: &Bytes32,
idx: Word,
sender: Address,
recipient: Address,
amount: Word,
data: Vec<u8>,
) -> Self {
let nonce = Output::message_nonce(txid, idx);
let message_id = Output::message_id(&sender, &recipient, &nonce, amount, &data);
let digest = Output::message_digest(&data);

Self::message_out(message_id, sender, recipient, amount, nonce, digest, data)
}

pub fn message_out(
message_id: MessageId,
sender: Address,
recipient: Address,
amount: Word,
nonce: Bytes32,
digest: Bytes32,
data: Vec<u8>,
) -> Self {
let len = bytes::padded_len(&data) as Word;

Self::message_out_with_len(
message_id, sender, recipient, amount, nonce, len, digest, data,
)
}

pub const fn message_out_with_len(
message_id: MessageId,
sender: Address,
recipient: Address,
amount: Word,
nonce: Bytes32,
len: Word,
digest: Bytes32,
data: Vec<u8>,
) -> Self {
Self::MessageOut {
message_id,
sender,
recipient,
amount,
nonce,
len,
digest,
data,
}
}

pub const fn id(&self) -> Option<&ContractId> {
match self {
Self::Call { id, .. } => Some(id),
Expand All @@ -260,6 +354,7 @@ impl Receipt {
Self::Transfer { id, .. } => Some(id),
Self::TransferOut { id, .. } => Some(id),
Self::ScriptResult { .. } => None,
Self::MessageOut { .. } => None,
}
}

Expand All @@ -275,6 +370,7 @@ impl Receipt {
Self::Transfer { pc, .. } => Some(*pc),
Self::TransferOut { pc, .. } => Some(*pc),
Self::ScriptResult { .. } => None,
Self::MessageOut { .. } => None,
}
}

Expand All @@ -290,6 +386,7 @@ impl Receipt {
Self::Transfer { is, .. } => Some(*is),
Self::TransferOut { is, .. } => Some(*is),
Self::ScriptResult { .. } => None,
Self::MessageOut { .. } => None,
}
}

Expand All @@ -313,6 +410,7 @@ impl Receipt {
Self::Call { amount, .. } => Some(*amount),
Self::Transfer { amount, .. } => Some(*amount),
Self::TransferOut { amount, .. } => Some(*amount),
Self::MessageOut { amount, .. } => Some(*amount),
_ => None,
}
}
Expand Down Expand Up @@ -366,6 +464,7 @@ impl Receipt {
match self {
Self::ReturnData { len, .. } => Some(*len),
Self::LogData { len, .. } => Some(*len),
Self::MessageOut { len, .. } => Some(*len),
_ => None,
}
}
Expand All @@ -382,6 +481,7 @@ impl Receipt {
match self {
Self::ReturnData { digest, .. } => Some(digest),
Self::LogData { digest, .. } => Some(digest),
Self::MessageOut { digest, .. } => Some(digest),
_ => None,
}
}
Expand All @@ -390,6 +490,7 @@ impl Receipt {
match self {
Self::ReturnData { data, .. } => Some(data),
Self::LogData { data, .. } => Some(data),
Self::MessageOut { data, .. } => Some(data),
_ => None,
}
}
Expand Down Expand Up @@ -446,6 +547,34 @@ impl Receipt {
}
}

pub const fn message_id(&self) -> Option<&MessageId> {
match self {
Self::MessageOut { message_id, .. } => Some(message_id),
_ => None,
}
}

pub const fn sender(&self) -> Option<&Address> {
match self {
Self::MessageOut { sender, .. } => Some(sender),
_ => None,
}
}

pub const fn recipient(&self) -> Option<&Address> {
match self {
Self::MessageOut { recipient, .. } => Some(recipient),
_ => None,
}
}

pub const fn nonce(&self) -> Option<&Bytes32> {
match self {
Self::MessageOut { nonce, .. } => Some(nonce),
_ => None,
}
}

fn variant_len_without_data(variant: ReceiptRepr) -> usize {
ContractId::LEN // id
+ WORD_SIZE // pc
Expand Down Expand Up @@ -502,6 +631,16 @@ impl Receipt {
WORD_SIZE // status
+ WORD_SIZE // gas_used
}

ReceiptRepr::MessageOut => {
MessageId::LEN // message_id
+ Address::LEN // sender
+ Address::LEN // recipient
+ WORD_SIZE // amount
+ Bytes32::LEN // nonce
+ WORD_SIZE // len
+ Bytes32::LEN // digest
}
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions fuel-tx/src/receipt/receipt_repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub enum ReceiptRepr {
Transfer = 0x07,
TransferOut = 0x08,
ScriptResult = 0x09,
MessageOut = 0x0A,
}

impl From<&Receipt> for ReceiptRepr {
Expand All @@ -27,6 +28,7 @@ impl From<&Receipt> for ReceiptRepr {
Receipt::Transfer { .. } => Self::Transfer,
Receipt::TransferOut { .. } => Self::TransferOut,
Receipt::ScriptResult { .. } => Self::ScriptResult,
Receipt::MessageOut { .. } => Self::MessageOut,
}
}
}
Loading

0 comments on commit 0292d22

Please sign in to comment.