Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat(standalone): thread-safety and serde #496

Merged
merged 3 commits into from
Apr 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 2 additions & 33 deletions engine-standalone-storage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub mod diff;
pub mod engine_state;
pub mod error;
pub mod json_snapshot;
mod promise;
pub mod promise;
pub mod relayer_db;
/// Functions for receiving new blocks and transactions to keep the storage up to date.
pub mod sync;
Expand All @@ -38,20 +38,12 @@ pub enum StoragePrefix {

pub struct Storage {
db: DB,
engine_transaction: RefCell<Diff>,
engine_output: Cell<Vec<u8>>,
}

impl Storage {
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, rocksdb::Error> {
let db = DB::open_default(path)?;
let engine_transaction = RefCell::new(Diff::default());
let engine_output = Cell::new(Vec::new());
Ok(Self {
db,
engine_transaction,
engine_output,
})
Ok(Self { db })
}

pub fn get_latest_block(&self) -> Result<(H256, u64), error::Error> {
Expand Down Expand Up @@ -343,29 +335,6 @@ impl Storage {
Ok(result)
}

/// Get an object which represents the state of the engine at the given block hash,
/// after transactions up to (not including) the given transaction index.
/// The `input` is the bytes that would be present in the NEAR runtime (normally
/// not needed for standalone engine).
pub fn access_engine_storage_at_position<'db, 'input: 'db>(
&'db mut self,
block_height: u64,
transaction_position: u16,
input: &'input [u8],
) -> engine_state::EngineStateAccess<'db, 'db, 'db> {
self.engine_transaction.borrow_mut().clear();
self.engine_output.set(Vec::new());

engine_state::EngineStateAccess::new(
input,
block_height,
transaction_position,
&self.engine_transaction,
&self.engine_output,
&self.db,
)
}

/// Same as `access_engine_storage_at_position`, but does not modify `self`, hence the immutable
/// borrow instead of the mutable one. The use case for this function is to execute a transaction
/// with the engine, but not to make any immediate changes to storage; only return the diff and outcome.
Expand Down
57 changes: 30 additions & 27 deletions engine-standalone-storage/src/relayer_db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,18 @@ where
env.block_timestamp = block_metadata.timestamp;
env.random_seed = block_metadata.random_seed;

let io = storage.access_engine_storage_at_position(block_height, transaction_position, &[]);

let maybe_result = engine::submit(
io,
&env,
&transaction_bytes,
engine_state.clone(),
env.current_account_id(),
relayer_address,
&mut handler,
);
match maybe_result {
let result = storage.with_engine_access(block_height, transaction_position, &[], |io| {
engine::submit(
io,
&env,
&transaction_bytes,
engine_state.clone(),
env.current_account_id(),
relayer_address,
&mut handler,
)
});
match result.result {
// Engine errors would always turn into panics on the NEAR side, so we do not need to persist
// any diff. Therefore, even if the error was expected, we still continue to the next transaction.
Err(e) => {
Expand Down Expand Up @@ -140,7 +140,7 @@ where
}
}

let diff = io.get_transaction_diff();
let diff = result.diff;
let tx_msg = crate::TransactionMessage {
block_hash,
near_receipt_id: near_tx_hash,
Expand Down Expand Up @@ -227,20 +227,23 @@ mod test {
storage
.set_block_data(block_hash, block_height, block_metadata)
.unwrap();
let mut io = storage.access_engine_storage_at_position(block_height, 0, &[]);
engine::set_state(&mut io, engine_state.clone());
connector::EthConnectorContract::create_contract(
io,
engine_state.owner_id.clone(),
parameters::InitCallArgs {
prover_account: engine_state.bridge_prover_id.clone(),
eth_custodian_address: "6bfad42cfc4efc96f529d786d643ff4a8b89fa52".to_string(),
metadata: Default::default(),
},
)
.ok()
.unwrap();
let diff = io.get_transaction_diff();
let result = storage.with_engine_access(block_height, 0, &[], |io| {
let mut local_io = io.clone();
engine::set_state(&mut local_io, engine_state.clone());
connector::EthConnectorContract::create_contract(
io,
engine_state.owner_id.clone(),
parameters::InitCallArgs {
prover_account: engine_state.bridge_prover_id.clone(),
eth_custodian_address: "6bfad42cfc4efc96f529d786d643ff4a8b89fa52"
.to_string(),
metadata: Default::default(),
},
)
});

result.result.ok().unwrap();
let diff = result.diff;
storage
.set_transaction_included(
H256::zero(),
Expand Down
18 changes: 10 additions & 8 deletions engine-standalone-storage/src/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,17 @@ pub fn consume_message(
let block_hash = transaction_message.block_hash;
let block_height = storage.get_block_height_by_hash(block_hash)?;
let block_metadata = storage.get_block_metadata(block_hash)?;
let io =
storage.access_engine_storage_at_position(block_height, transaction_position, &[]);

let (tx_hash, diff, result) = execute_transaction(
transaction_message.as_ref(),
block_height,
&block_metadata,
io,
)?;
let (tx_hash, diff, result) = storage
.with_engine_access(block_height, transaction_position, &[], |io| {
execute_transaction(
transaction_message.as_ref(),
block_height,
&block_metadata,
io,
)
})
.result?;
match &result {
Some(TransactionExecutionResult::Submit(Err(_))) => (), // do not persist if Engine encounters an error
_ => storage.set_transaction_included(tx_hash, &transaction_message, &diff)?,
Expand Down
27 changes: 15 additions & 12 deletions engine-tests/src/test_utils/standalone/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,24 +239,27 @@ impl StandaloneRunner {
}

pub fn get_balance(&mut self, address: &Address) -> Wei {
let io = self
.storage
.access_engine_storage_at_position(self.env.block_height + 1, 0, &[]);
engine::get_balance(&io, address)
self.storage
.with_engine_access(self.env.block_height + 1, 0, &[], |io| {
engine::get_balance(&io, address)
})
.result
}

pub fn get_nonce(&mut self, address: &Address) -> U256 {
let io = self
.storage
.access_engine_storage_at_position(self.env.block_height + 1, 0, &[]);
engine::get_nonce(&io, address)
self.storage
.with_engine_access(self.env.block_height + 1, 0, &[], |io| {
engine::get_nonce(&io, address)
})
.result
}

pub fn get_code(&mut self, address: &Address) -> Vec<u8> {
let io = self
.storage
.access_engine_storage_at_position(self.env.block_height + 1, 0, &[]);
engine::get_code(&io, address)
self.storage
.with_engine_access(self.env.block_height + 1, 0, &[], |io| {
engine::get_code(&io, address)
})
.result
}

pub fn close(self) {
Expand Down
21 changes: 4 additions & 17 deletions engine-tests/src/tests/standalone/storage.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use aurora_engine::engine;
use aurora_engine_sdk::env::Timestamp;
use aurora_engine_types::types::{Address, Wei};
use aurora_engine_types::{H256, U256};
Expand Down Expand Up @@ -148,23 +147,11 @@ fn test_consume_transaction() {
let result = runner.submit_transaction(&signer.secret_key, tx).unwrap();
assert!(result.status.is_ok());

// Look at the engine state for the following block
let engine_io =
runner
.storage
.access_engine_storage_at_position(runner.env.block_height + 1, 0, &[]);

// Confirm the balances and nonces match the expected values (note the transfer has been applied)
assert_eq!(
engine::get_balance(&engine_io, &address),
balance - transfer_amount
);
assert_eq!(
engine::get_balance(&engine_io, &dest_address),
transfer_amount
);
assert_eq!(engine::get_nonce(&engine_io, &address), U256::one());
assert_eq!(engine::get_nonce(&engine_io, &dest_address), U256::zero());
assert_eq!(runner.get_balance(&address), balance - transfer_amount);
assert_eq!(runner.get_balance(&dest_address), transfer_amount);
assert_eq!(runner.get_nonce(&address), U256::one());
assert_eq!(runner.get_nonce(&dest_address), U256::zero());

runner.close();
}
Expand Down
9 changes: 6 additions & 3 deletions engine-tests/src/tests/standalone/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,13 @@ fn test_consume_deploy_erc20_message() {
)
.unwrap();

let io = runner
let erc20_address = runner
.storage
.access_engine_storage_at_position(runner.env.block_height + 1, 0, &[]);
let erc20_address = aurora_engine::engine::get_erc20_from_nep141(&io, &token).unwrap();
.with_engine_access(runner.env.block_height + 1, 0, &[], |io| {
aurora_engine::engine::get_erc20_from_nep141(&io, &token)
})
.result
.unwrap();

runner.env.block_height += 1;
runner.env.signer_account_id = "some_account.near".parse().unwrap();
Expand Down
7 changes: 7 additions & 0 deletions engine-transactions/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,20 @@ impl NormalizedEthTransaction {
}

#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub enum ParseTransactionError {
UnknownTransactionType,
// Per the EIP-2718 spec 0xff is a reserved value
ReservedSentinel,
#[cfg_attr(feature = "serde", serde(serialize_with = "decoder_err_to_str"))]
RlpDecodeError(DecoderError),
}

#[cfg(feature = "serde")]
fn decoder_err_to_str<S: serde::Serializer>(err: &DecoderError, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_str(&format!("{:?}", err))
}

impl ParseTransactionError {
pub fn as_str(&self) -> &'static str {
match self {
Expand Down
2 changes: 1 addition & 1 deletion engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ mainnet = ["contract", "log"]
testnet = ["contract", "log"]
mainnet-test = ["meta-call"]
testnet-test = ["meta-call"]
impl-serde = ["aurora-engine-types/impl-serde", "serde", "aurora-engine-transactions/impl-serde"]
impl-serde = ["aurora-engine-types/impl-serde", "serde", "aurora-engine-transactions/impl-serde", "evm-core/with-serde"]
4 changes: 4 additions & 0 deletions engine/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ macro_rules! assert_or_finish {
}

#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct EngineError {
pub kind: EngineErrorKind,
pub gas_used: u64,
Expand All @@ -84,6 +85,7 @@ impl AsRef<[u8]> for EngineError {

/// Errors with the EVM engine.
#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub enum EngineErrorKind {
/// Normal EVM errors.
EvmError(ExitError),
Expand Down Expand Up @@ -182,6 +184,7 @@ impl ExitIntoResult for ExitReason {
}

#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BalanceOverflow;

impl AsRef<[u8]> for BalanceOverflow {
Expand All @@ -192,6 +195,7 @@ impl AsRef<[u8]> for BalanceOverflow {

/// Errors resulting from trying to pay for gas
#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum GasPaymentError {
/// Overflow adding ETH to an account balance (should never happen)
BalanceOverflow(BalanceOverflow),
Expand Down
2 changes: 2 additions & 0 deletions engine/src/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ impl From<Log> for ResultLog {

/// The status of a transaction.
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TransactionStatus {
Succeed(Vec<u8>),
Revert(Vec<u8>),
Expand Down Expand Up @@ -109,6 +110,7 @@ impl AsRef<[u8]> for TransactionStatus {
/// Borsh-encoded parameters for the `call`, `call_with_args`, `deploy_code`,
/// and `deploy_with_input` methods.
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SubmitResult {
version: u8,
pub status: TransactionStatus,
Expand Down