Skip to content

Commit

Permalink
plumb consensus params throughout the vm for configurable tx validati…
Browse files Browse the repository at this point in the history
…on (#130)
  • Loading branch information
Voxelot authored May 25, 2022
1 parent 4c5bc87 commit ffaf70c
Show file tree
Hide file tree
Showing 14 changed files with 73 additions and 48 deletions.
3 changes: 2 additions & 1 deletion src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::context::Context;
use crate::state::Debugger;
use std::collections::HashMap;

use fuel_tx::{Receipt, Transaction};
use fuel_tx::{ConsensusParameters, Receipt, Transaction};
use fuel_types::{AssetId, Word};

mod alu;
Expand Down Expand Up @@ -58,6 +58,7 @@ pub struct Interpreter<S> {
profiler: Profiler,
// track the offset for each unused balance in memory
unused_balance_index: HashMap<AssetId, usize>,
consensus_parameters: ConsensusParameters,
}

impl<S> Interpreter<S> {
Expand Down
7 changes: 4 additions & 3 deletions src/interpreter/constructors.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Exposed constructors API for the [`Interpreter`]
use fuel_tx::Transaction;
use fuel_tx::{ConsensusParameters, Transaction};

use super::Interpreter;
use crate::consts::*;
Expand All @@ -17,7 +17,7 @@ impl<S> Interpreter<S> {
/// If the provided storage implements
/// [`crate::storage::InterpreterStorage`], the returned interpreter
/// will provide full functionality.
pub fn with_storage(storage: S) -> Self {
pub fn with_storage(storage: S, params: ConsensusParameters) -> Self {
Self {
registers: [0; VM_REGISTER_COUNT],
memory: vec![0; VM_MAX_RAM as usize],
Expand All @@ -31,6 +31,7 @@ impl<S> Interpreter<S> {
#[cfg(feature = "profile-any")]
profiler: Profiler::default(),
unused_balance_index: Default::default(),
consensus_parameters: params,
}
}

Expand All @@ -47,7 +48,7 @@ where
S: Default,
{
fn default() -> Self {
Self::with_storage(Default::default())
Self::with_storage(Default::default(), Default::default())
}
}

Expand Down
22 changes: 14 additions & 8 deletions src/interpreter/executors/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::state::{ExecuteState, ProgramState, StateTransitionRef};
use crate::storage::InterpreterStorage;

use fuel_asm::PanicReason;
use fuel_tx::{Contract, Input, Output, Receipt, ScriptExecutionResult, Transaction};
use fuel_tx::{ConsensusParameters, Contract, Input, Output, Receipt, ScriptExecutionResult, Transaction};
use fuel_types::{bytes::SerializableVec, Word};

impl<S> Interpreter<S>
Expand All @@ -25,8 +25,8 @@ where
///
/// This is not a valid entrypoint for debug calls. It will only return a `bool`, and not the
/// VM state required to trace the execution steps.
pub fn check_predicates(tx: Transaction) -> bool {
let mut vm = Interpreter::with_storage(S::default());
pub fn check_predicates(tx: Transaction, params: ConsensusParameters) -> bool {
let mut vm = Interpreter::with_storage(S::default(), params);

if !tx.check_predicate_owners() {
return false;
Expand Down Expand Up @@ -63,7 +63,7 @@ where
fn init_predicate(&mut self, tx: Transaction) -> bool {
let block_height = 0;

self.init(true, block_height, tx).is_ok()
self.init(true, block_height, tx, self.consensus_parameters).is_ok()
}

fn input_to_predicate(tx: &Transaction, idx: usize) -> Option<MemoryRange> {
Expand Down Expand Up @@ -132,7 +132,7 @@ where
// Verify predicates
// https://github.com/FuelLabs/fuel-specs/blob/master/specs/protocol/tx_validity.md#predicate-verification
// TODO implement debug support
if !Interpreter::<()>::check_predicates(self.tx.clone()) {
if !Interpreter::<()>::check_predicates(self.tx.clone(), self.consensus_parameters) {
return Err(InterpreterError::PredicateFailure);
}

Expand Down Expand Up @@ -286,8 +286,12 @@ where
/// Allocate internally a new instance of [`Interpreter`] with the provided
/// storage, initialize it with the provided transaction and return the
/// result of th execution in form of [`StateTransition`]
pub fn transact_owned(storage: S, tx: Transaction) -> Result<StateTransition, InterpreterError> {
Interpreter::with_storage(storage)
pub fn transact_owned(
storage: S,
tx: Transaction,
params: ConsensusParameters,
) -> Result<StateTransition, InterpreterError> {
Interpreter::with_storage(storage, params)
.transact(tx)
.map(|st| st.into_owned())
}
Expand All @@ -297,7 +301,9 @@ where
/// of the interpreter and will avoid unnecessary copy with the data
/// that can be referenced from the interpreter instance itself.
pub fn transact(&mut self, tx: Transaction) -> Result<StateTransitionRef<'_>, InterpreterError> {
let state_result = self.init_with_storage(tx).and_then(|_| self.run());
let state_result = self
.init_with_storage(tx, self.consensus_parameters)
.and_then(|_| self.run());

#[cfg(feature = "profile-any")]
self.profiler.on_transaction(&state_result);
Expand Down
14 changes: 9 additions & 5 deletions src/interpreter/initialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@ use std::io;

impl<S> Interpreter<S> {
/// Initialize the VM with a given transaction
pub fn init(&mut self, predicate: bool, block_height: u32, mut tx: Transaction) -> Result<(), InterpreterError> {
let params = ConsensusParameters::default();

pub fn init(
&mut self,
predicate: bool,
block_height: u32,
mut tx: Transaction,
params: ConsensusParameters,
) -> Result<(), InterpreterError> {
tx.validate_without_signature(self.block_height() as Word, &params)?;
tx.precompute_metadata();

Expand Down Expand Up @@ -162,10 +166,10 @@ where
/// execution of contract opcodes.
///
/// For predicate verification, check [`Self::init`]
pub fn init_with_storage(&mut self, tx: Transaction) -> Result<(), InterpreterError> {
pub fn init_with_storage(&mut self, tx: Transaction, params: ConsensusParameters) -> Result<(), InterpreterError> {
let predicate = false;
let block_height = self.storage.block_height().map_err(InterpreterError::from_io)?;

self.init(predicate, block_height, tx)
self.init(predicate, block_height, tx, params)
}
}
6 changes: 4 additions & 2 deletions src/interpreter/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,8 @@ mod tests {
vec![vec![].into()],
);

vm.init_with_storage(tx).expect("Failed to init VM!");
vm.init_with_storage(tx, Default::default())
.expect("Failed to init VM!");

for (asset_id, amount) in balances {
assert!(vm.external_asset_id_balance_sub(&asset_id, amount + 1).is_err());
Expand Down Expand Up @@ -293,7 +294,8 @@ mod tests {
vec![Witness::default()],
);

vm.init_with_storage(tx).expect("Failed to init VM!");
vm.init_with_storage(tx, Default::default())
.expect("Failed to init VM!");

// increase variable output
vm.set_variable_output(0, asset_id_to_update, amount_to_set, owner)
Expand Down
9 changes: 6 additions & 3 deletions src/interpreter/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,8 @@ mod tests {
fn memcopy() {
let mut vm = Interpreter::with_memory_storage();

vm.init_with_storage(Transaction::default()).expect("Failed to init VM");
vm.init_with_storage(Transaction::default(), Default::default())
.expect("Failed to init VM");

let alloc = 1024;

Expand Down Expand Up @@ -505,7 +506,8 @@ mod tests {
assert_eq!(m, m_p);

let mut vm = Interpreter::with_memory_storage();
vm.init_with_storage(Transaction::default()).expect("Failed to init VM");
vm.init_with_storage(Transaction::default(), Default::default())
.expect("Failed to init VM");

let bytes = 1024;
vm.instruction(
Expand Down Expand Up @@ -536,7 +538,8 @@ mod tests {
fn stack_alloc_ownership() {
let mut vm = Interpreter::with_memory_storage();

vm.init_with_storage(Transaction::default()).expect("Failed to init VM");
vm.init_with_storage(Transaction::default(), Default::default())
.expect("Failed to init VM");

vm.instruction(Interpreter::instruction_script, Opcode::MOVE(0x10, REG_SP).into())
.unwrap();
Expand Down
8 changes: 4 additions & 4 deletions src/memory_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use crate::backtrace::Backtrace;
use crate::transactor::Transactor;

use fuel_tx::{Receipt, Transaction};
use fuel_tx::{ConsensusParameters, Receipt, Transaction};

mod storage;

Expand All @@ -29,9 +29,9 @@ impl<'a> AsMut<MemoryStorage> for MemoryClient<'a> {

impl<'a> MemoryClient<'a> {
/// Create a new instance of the memory client out of a provided storage.
pub fn new(storage: MemoryStorage) -> Self {
pub fn new(storage: MemoryStorage, params: ConsensusParameters) -> Self {
Self {
transactor: Transactor::new(storage),
transactor: Transactor::new(storage, params),
}
}

Expand Down Expand Up @@ -87,7 +87,7 @@ impl<'a> MemoryClient<'a> {

impl<'a> From<MemoryStorage> for MemoryClient<'a> {
fn from(s: MemoryStorage) -> Self {
Self::new(s)
Self::new(s, Default::default())
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/transactor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::interpreter::Interpreter;
use crate::state::StateTransitionRef;
use crate::storage::InterpreterStorage;

use fuel_tx::{Receipt, Transaction};
use fuel_tx::{ConsensusParameters, Receipt, Transaction};

use std::{mem, slice};

Expand All @@ -26,8 +26,8 @@ pub struct Transactor<'a, S> {

impl<'a, S> Transactor<'a, S> {
/// Transactor constructor
pub fn new(storage: S) -> Self {
Interpreter::with_storage(storage).into()
pub fn new(storage: S, params: ConsensusParameters) -> Self {
Interpreter::with_storage(storage, params).into()
}

/// State transition representation after the execution of a transaction.
Expand Down Expand Up @@ -185,6 +185,6 @@ where
S: Default,
{
fn default() -> Self {
Self::new(Default::default())
Self::new(Default::default(), Default::default())
}
}
2 changes: 1 addition & 1 deletion src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ pub mod test_helpers {
}

fn execute_tx(&mut self, tx: Transaction) -> StateTransition {
let mut client = MemoryClient::new(self.storage.clone());
let mut client = MemoryClient::new(self.storage.clone(), Default::default());
client.transact(tx);
let storage = client.as_ref().clone();
let txtor: Transactor<_> = client.into();
Expand Down
12 changes: 6 additions & 6 deletions tests/alu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ fn alu(registers_init: &[(RegisterId, Immediate18)], op: Opcode, reg: RegisterId
vec![],
);

let receipts = Transactor::new(storage)
let receipts = Transactor::new(storage, Default::default())
.transact(tx)
.receipts()
.expect("Failed to execute ALU script!")
Expand Down Expand Up @@ -65,7 +65,7 @@ fn alu_overflow(program: &[Opcode], reg: RegisterId, expected: u128, boolean: bo
vec![],
);

let receipts = Transactor::new(storage.clone())
let receipts = Transactor::new(storage.clone(), Default::default())
.transact(tx)
.receipts()
.expect("Failed to execute ALU script!")
Expand Down Expand Up @@ -101,7 +101,7 @@ fn alu_overflow(program: &[Opcode], reg: RegisterId, expected: u128, boolean: bo
vec![],
);

let receipts = Transactor::new(storage)
let receipts = Transactor::new(storage, Default::default())
.transact(tx)
.receipts()
.expect("Failed to execute ALU script!")
Expand Down Expand Up @@ -146,7 +146,7 @@ fn alu_err(registers_init: &[(RegisterId, Immediate18)], op: Opcode, reg: Regist
vec![],
);

let receipts = Transactor::new(storage.clone())
let receipts = Transactor::new(storage.clone(), Default::default())
.transact(tx)
.receipts()
.expect("Failed to execute ALU script!")
Expand Down Expand Up @@ -182,7 +182,7 @@ fn alu_err(registers_init: &[(RegisterId, Immediate18)], op: Opcode, reg: Regist
vec![],
);

let receipts = Transactor::new(storage)
let receipts = Transactor::new(storage, Default::default())
.transact(tx)
.receipts()
.expect("Failed to execute ALU script!")
Expand Down Expand Up @@ -219,7 +219,7 @@ fn alu_reserved(registers_init: &[(RegisterId, Immediate18)], op: Opcode) {
vec![],
vec![],
);
let receipts = Transactor::new(storage)
let receipts = Transactor::new(storage, Default::default())
.transact(tx)
.receipts()
.expect("Failed to execute ALU script!")
Expand Down
6 changes: 3 additions & 3 deletions tests/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ fn ecrecover() {
vec![],
);

let receipts = Transactor::new(storage)
let receipts = Transactor::new(storage, Default::default())
.transact(tx)
.receipts()
.expect("Failed to execute script!")
Expand Down Expand Up @@ -171,7 +171,7 @@ fn sha256() {
vec![],
);

let receipts = Transactor::new(storage)
let receipts = Transactor::new(storage, Default::default())
.transact(tx)
.receipts()
.expect("Failed to execute script!")
Expand Down Expand Up @@ -259,7 +259,7 @@ fn keccak256() {
vec![],
);

let receipts = Transactor::new(storage)
let receipts = Transactor::new(storage, Default::default())
.transact(tx)
.receipts()
.expect("Failed to execute script!")
Expand Down
12 changes: 8 additions & 4 deletions tests/flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ fn call() {
vec![program.clone()],
);

assert!(Transactor::new(&mut storage).transact(tx).is_success());
assert!(Transactor::new(&mut storage, Default::default())
.transact(tx)
.is_success());

let mut script_ops = vec![
Opcode::MOVI(0x10, 0x00),
Expand Down Expand Up @@ -185,7 +187,7 @@ fn call() {
_ => unreachable!(),
}

let receipts = Transactor::new(&mut storage)
let receipts = Transactor::new(&mut storage, Default::default())
.transact(tx)
.receipts()
.expect("Failed to execute script")
Expand Down Expand Up @@ -243,7 +245,9 @@ fn call_frame_code_offset() {
vec![program.clone().into()],
);

assert!(Transactor::new(&mut storage).transact(deploy).is_success());
assert!(Transactor::new(&mut storage, Default::default())
.transact(deploy)
.is_success());

let input = Input::contract(rng.gen(), rng.gen(), rng.gen(), id);
let output = Output::contract(0, rng.gen(), rng.gen());
Expand Down Expand Up @@ -282,7 +286,7 @@ fn call_frame_code_offset() {
vec![],
);

let mut vm = Interpreter::with_storage(storage);
let mut vm = Interpreter::with_storage(storage, Default::default());

vm.transact(script).expect("Failed to call deployed contract");

Expand Down
Loading

0 comments on commit ffaf70c

Please sign in to comment.