Skip to content

Commit

Permalink
Remove multi-tx handling from the VM
Browse files Browse the repository at this point in the history
  • Loading branch information
Dentosal committed Nov 29, 2021
1 parent 7a8ac84 commit b9a2cc4
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 59 deletions.
4 changes: 2 additions & 2 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ impl<S> Interpreter<S> {
}

impl<S: InterpreterStorageApply> Interpreter<&mut S> {
pub fn apply<I: IntoIterator<Item = Transaction>>(&mut self, txs: I) -> Result<Vec<Receipt>, TransactionError> {
S::apply(self, txs)
pub fn apply(&mut self, tx: Transaction) -> Result<Vec<Receipt>, TransactionError> {
S::apply(self, tx)
}
}

Expand Down
72 changes: 34 additions & 38 deletions src/memory_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,9 @@ impl InterpreterStorage for MemoryStorage {
}

impl InterpreterStorageApply for MemoryStorage {
fn apply<I: IntoIterator<Item = Transaction>>(
fn apply(
interpreter: &mut Interpreter<&mut MemoryStorage>,
txs: I,
tx: Transaction,
) -> Result<Vec<Receipt>, TransactionError> {
// A transaction that is considered valid will be reverted if the runtime
// returns an error.
Expand All @@ -210,47 +210,43 @@ impl InterpreterStorageApply for MemoryStorage {
//
// All the other variants of `InterpreterError` are supressed in this function
// and they will produce isolated `RVRT` operations.
let receipts = txs.into_iter().try_fold(vec![], |mut receipts, tx| {
match interpreter.transact(tx) {
Ok(state) => {
receipts.extend(state.receipts());

if !state.receipts().iter().any(|r| matches!(r, Receipt::Revert { .. })) {
interpreter.as_mut().commit();
} else {
interpreter.as_mut().revert();
}

Ok(receipts)
match interpreter.transact(tx) {
Ok(state) => {
let receipts = state.receipts().to_owned();

if !state.receipts().iter().any(|r| matches!(r, Receipt::Revert { .. })) {
interpreter.as_mut().commit();
} else {
interpreter.as_mut().revert();
}

Err(tx_error) => {
let conv = tx_error.map_error(|error| match error {
InterpreterError::ValidationError(e) => e.into(),
other => other,
});

match conv.error() {
InterpreterError::ValidationError(_)
| InterpreterError::OpcodeRepresentationUnimplemented(_)
| InterpreterError::OpcodeInvalid(_) => {
interpreter.as_mut().rollback();
}
_ => {
// TODO: VM is to return a `RVRT` receipt on runtime error.
// This way, the return of `transact` should be `Err` only
// if `InterpreterError::ValidationError` happens
interpreter.as_mut().revert();
}
}
interpreter.as_mut().persist();

Err(conv)
}
Ok(receipts)
}
})?;

interpreter.as_mut().persist();
Err(tx_error) => {
let conv = tx_error.map_error(|error| match error {
InterpreterError::ValidationError(e) => e.into(),
other => other,
});

match conv.error() {
InterpreterError::ValidationError(_)
| InterpreterError::OpcodeRepresentationUnimplemented(_)
| InterpreterError::OpcodeInvalid(_) => {
interpreter.as_mut().rollback();
}
_ => {
// TODO: VM is to return a `RVRT` receipt on runtime error.
// This way, the return of `transact` should be `Err` only
// if `InterpreterError::ValidationError` happens
interpreter.as_mut().revert();
}
}

Ok(receipts)
return Err(conv);
}
}
}
}
5 changes: 1 addition & 4 deletions src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,5 @@ where
}

pub trait InterpreterStorageApply {
fn apply<I: IntoIterator<Item = Transaction>>(
interpreter: &mut Interpreter<&mut Self>,
txs: I,
) -> Result<Vec<Receipt>, TransactionError>;
fn apply(interpreter: &mut Interpreter<&mut Self>, tx: Transaction) -> Result<Vec<Receipt>, TransactionError>;
}
8 changes: 4 additions & 4 deletions tests/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use fuel_vm::prelude::*;
use rand::rngs::StdRng;
use rand::{Rng, SeedableRng};

use std::{iter, mem};
use std::mem;

const WORD_SIZE: usize = mem::size_of::<Word>();

Expand Down Expand Up @@ -46,7 +46,7 @@ fn backtrace() {

Interpreter::with_storage(&mut storage)
.with_backtrace()
.apply(iter::once(tx_deploy))
.apply(tx_deploy)
.expect("Failed to deploy contract");

#[rustfmt::skip]
Expand Down Expand Up @@ -89,7 +89,7 @@ fn backtrace() {

Interpreter::with_storage(&mut storage)
.with_backtrace()
.apply(iter::once(tx_deploy))
.apply(tx_deploy)
.expect("Failed to deploy contract");

#[rustfmt::skip]
Expand Down Expand Up @@ -127,7 +127,7 @@ fn backtrace() {

let backtrace = Interpreter::with_storage(&mut storage)
.with_backtrace()
.apply(iter::once(tx_script))
.apply(tx_script)
.expect_err("Undefined opcode should err!")
.unwrap_backtrace();

Expand Down
16 changes: 10 additions & 6 deletions tests/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use fuel_vm::prelude::*;
use rand::rngs::StdRng;
use rand::{Rng, SeedableRng};

use std::{iter, mem};
use std::mem;

const WORD_SIZE: usize = mem::size_of::<Word>();

Expand Down Expand Up @@ -186,9 +186,13 @@ fn state_read_write() {
let state = storage.contract_state(&contract, &key);
assert_eq!(Bytes32::default(), state.into_owned());

let receipts = Interpreter::with_storage(&mut storage)
.apply(vec![tx_deploy, tx_add_word])
let receipts0 = Interpreter::with_storage(&mut storage)
.apply(tx_deploy)
.expect("Failed to transact");
let receipts1 = Interpreter::with_storage(&mut storage)
.apply(tx_add_word)
.expect("Failed to transact");
let receipts: Vec<_> = receipts0.into_iter().chain(receipts1).collect();
let state = storage.contract_state(&contract, &key);

// Assert the state of `key` is mutated to `val`
Expand Down Expand Up @@ -231,7 +235,7 @@ fn state_read_write() {

// Mutate the state
let receipts = Interpreter::with_storage(&mut storage)
.apply(iter::once(tx_unpack_xor))
.apply(tx_unpack_xor)
.expect("Failed to transact");

// Expect the arguments to be received correctly by the VM
Expand Down Expand Up @@ -307,7 +311,7 @@ fn load_external_contract_code() {
);

Interpreter::with_storage(&mut storage)
.apply(vec![tx_create_target])
.apply(tx_create_target)
.expect("deploy failed");

// Then deploy another contract that attempts to read the first one
Expand Down Expand Up @@ -374,7 +378,7 @@ fn load_external_contract_code() {
);

let receipts = Interpreter::with_storage(&mut storage)
.apply(vec![tx_deploy_loader])
.apply(tx_deploy_loader)
.expect("deploy failed");

if let Receipt::LogData { digest, .. } = receipts.get(0).expect("No receipt") {
Expand Down
6 changes: 3 additions & 3 deletions tests/flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ fn revert() {

// Deploy the contract into the blockchain
Interpreter::with_storage(&mut storage)
.apply(vec![tx])
.apply(tx)
.expect("Failed to transact");

let input = Input::contract(rng.gen(), rng.gen(), rng.gen(), contract);
Expand Down Expand Up @@ -414,7 +414,7 @@ fn revert() {
assert_eq!(Bytes32::default(), state.into_owned());

let receipts = Interpreter::with_storage(&mut storage)
.apply(vec![tx])
.apply(tx)
.expect("Failed to transact");
let state = storage.contract_state(&contract, &key);

Expand Down Expand Up @@ -460,7 +460,7 @@ fn revert() {
);

let receipts = Interpreter::with_storage(&mut storage)
.apply(vec![tx])
.apply(tx)
.expect("Failed to transact");
let state = storage.contract_state(&contract, &key);

Expand Down
3 changes: 1 addition & 2 deletions tests/profile_gas.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::iter;
use std::sync::{Arc, Mutex};

use fuel_vm::consts::*;
Expand Down Expand Up @@ -69,7 +68,7 @@ fn profile_gas() {

let result = Interpreter::with_storage(&mut storage)
.with_profiling(Box::new(output.clone()))
.apply(iter::once(tx_deploy));
.apply(tx_deploy);

if count == case_out_of_gas {
match result {
Expand Down

0 comments on commit b9a2cc4

Please sign in to comment.