Skip to content

Commit

Permalink
Feat(standalone): Conversion from standalone's TransactionKind to Nor…
Browse files Browse the repository at this point in the history
…malizedEthTransaction (#586)
  • Loading branch information
birchmd authored Aug 19, 2022
1 parent 34c838f commit ec7de27
Show file tree
Hide file tree
Showing 5 changed files with 304 additions and 35 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions engine-standalone-storage/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ aurora-engine = { path = "../engine", default-features = false, features = ["std
aurora-engine-types = { path = "../engine-types", default-features = false, features = ["std"] }
aurora-engine-sdk = { path = "../engine-sdk", default-features = false, features = ["std"] }
aurora-engine-transactions = { path = "../engine-transactions", default-features = false, features = ["std"] }
aurora-engine-precompiles = { path = "../engine-precompiles", default-features = false, features = ["std"] }
borsh = { version = "0.9.3" }
evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.36.0-aurora", default-features = false }
hex = "0.4.3"
rocksdb = { version = "0.18.0", default-features = false }
postgres = "0.19.2"
serde = "1.0.130"
Expand Down
255 changes: 253 additions & 2 deletions engine-standalone-storage/src/sync/types.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
use crate::Storage;
use aurora_engine::parameters;
use aurora_engine::xcc::AddressVersionUpdateArgs;
use aurora_engine_transactions::EthTransactionKind;
use aurora_engine_transactions::{EthTransactionKind, NormalizedEthTransaction};
use aurora_engine_types::account_id::AccountId;
use aurora_engine_types::{types, H256};
use aurora_engine_types::types::Address;
use aurora_engine_types::{
types::{self, Wei},
H256, U256,
};
use borsh::{BorshDeserialize, BorshSerialize};
use std::borrow::Cow;

Expand Down Expand Up @@ -119,6 +124,252 @@ pub enum TransactionKind {
Unknown,
}

impl TransactionKind {
pub fn eth_repr(
self,
engine_account: &AccountId,
caller: &AccountId,
block_height: u64,
transaction_position: u16,
storage: &Storage,
) -> NormalizedEthTransaction {
match self {
// In the case the submit arg fails to normalize, there is no EVM execution
Self::Submit(eth_tx_kind) => eth_tx_kind
.try_into()
.unwrap_or_else(|_| Self::no_evm_execution("submit")),
Self::Call(call_args) => {
let from = Self::get_implicit_address(caller);
let nonce =
Self::get_implicit_nonce(&from, block_height, transaction_position, storage);
let (to, data, value) = match call_args {
parameters::CallArgs::V1(args) => (args.contract, args.input, Wei::zero()),
parameters::CallArgs::V2(args) => (
args.contract,
args.input,
Wei::new(U256::from_big_endian(&args.value)),
),
};
NormalizedEthTransaction {
address: from,
chain_id: None,
nonce,
gas_limit: U256::from(u64::MAX),
max_priority_fee_per_gas: U256::zero(),
max_fee_per_gas: U256::zero(),
to: Some(to),
value,
data,
access_list: Vec::new(),
}
}
Self::Deploy(data) => {
let from = Self::get_implicit_address(caller);
let nonce =
Self::get_implicit_nonce(&from, block_height, transaction_position, storage);
NormalizedEthTransaction {
address: from,
chain_id: None,
nonce,
gas_limit: U256::from(u64::MAX),
max_priority_fee_per_gas: U256::zero(),
max_fee_per_gas: U256::zero(),
to: None,
value: Wei::zero(),
data,
access_list: Vec::new(),
}
}
Self::DeployErc20(_) => {
let from = Self::get_implicit_address(caller);
let nonce =
Self::get_implicit_nonce(&from, block_height, transaction_position, storage);
let data = aurora_engine::engine::setup_deploy_erc20_input(engine_account);
NormalizedEthTransaction {
address: from,
chain_id: None,
nonce,
gas_limit: U256::from(u64::MAX),
max_priority_fee_per_gas: U256::zero(),
max_fee_per_gas: U256::zero(),
to: None,
value: Wei::zero(),
data,
access_list: Vec::new(),
}
}
Self::FtOnTransfer(args) => {
if engine_account == caller {
let recipient = aurora_engine::deposit_event::FtTransferMessageData::parse_on_transfer_message(&args.msg).map(|data| data.recipient).unwrap_or_default();
let value = Wei::new(U256::from(args.amount.as_u128()));
// This transaction mints new ETH, so we'll say it comes from the zero address.
NormalizedEthTransaction {
address: types::Address::default(),
chain_id: None,
nonce: U256::zero(),
gas_limit: U256::from(u64::MAX),
max_priority_fee_per_gas: U256::zero(),
max_fee_per_gas: U256::zero(),
to: Some(recipient),
value,
data: Vec::new(),
access_list: Vec::new(),
}
} else {
let from = Self::get_implicit_address(engine_account);
let nonce = Self::get_implicit_nonce(
&from,
block_height,
transaction_position,
storage,
);
let to = storage
.with_engine_access(block_height, transaction_position, &[], |io| {
aurora_engine::engine::get_erc20_from_nep141(&io, caller)
})
.result
.ok()
.and_then(|bytes| types::Address::try_from_slice(&bytes).ok())
.unwrap_or_default();
let erc20_recipient = hex::decode(&args.msg.as_bytes()[0..40])
.ok()
.and_then(|bytes| types::Address::try_from_slice(&bytes).ok())
.unwrap_or_default();
let data = aurora_engine::engine::setup_receive_erc20_tokens_input(
&args,
&erc20_recipient,
);
NormalizedEthTransaction {
address: from,
chain_id: None,
nonce,
gas_limit: U256::from(u64::MAX),
max_priority_fee_per_gas: U256::zero(),
max_fee_per_gas: U256::zero(),
to: Some(to),
value: Wei::zero(),
data,
access_list: Vec::new(),
}
}
}
Self::RefundOnError(maybe_args) => {
match maybe_args {
Some(args) => match args.erc20_address {
Some(erc20_address) => {
// ERC-20 refund
let from = Self::get_implicit_address(engine_account);
let nonce = Self::get_implicit_nonce(
&from,
block_height,
transaction_position,
storage,
);
let to = erc20_address;
let data = aurora_engine::engine::setup_refund_on_error_input(
U256::from_big_endian(&args.amount),
args.recipient_address,
);
NormalizedEthTransaction {
address: from,
chain_id: None,
nonce,
gas_limit: U256::from(u64::MAX),
max_priority_fee_per_gas: U256::zero(),
max_fee_per_gas: U256::zero(),
to: Some(to),
value: Wei::zero(),
data,
access_list: Vec::new(),
}
}
None => {
// ETH refund
let value = Wei::new(U256::from_big_endian(&args.amount));
let from = aurora_engine_precompiles::native::exit_to_near::ADDRESS;
let nonce = Self::get_implicit_nonce(
&from,
block_height,
transaction_position,
storage,
);
NormalizedEthTransaction {
address: from,
chain_id: None,
nonce,
gas_limit: U256::from(u64::MAX),
max_priority_fee_per_gas: U256::zero(),
max_fee_per_gas: U256::zero(),
to: Some(args.recipient_address),
value,
data: Vec::new(),
access_list: Vec::new(),
}
}
},
None => Self::no_evm_execution("refund_on_error"),
}
}
Self::Deposit(_) => Self::no_evm_execution("deposit"),
Self::FtTransferCall(_) => Self::no_evm_execution("ft_transfer_call"),
Self::FinishDeposit(_) => Self::no_evm_execution("finish_deposit"),
Self::ResolveTransfer(_, _) => Self::no_evm_execution("resolve_transfer"),
Self::FtTransfer(_) => Self::no_evm_execution("ft_transfer"),
TransactionKind::Withdraw(_) => Self::no_evm_execution("withdraw"),
TransactionKind::StorageDeposit(_) => Self::no_evm_execution("storage_deposit"),
TransactionKind::StorageUnregister(_) => Self::no_evm_execution("storage_unregister"),
TransactionKind::StorageWithdraw(_) => Self::no_evm_execution("storage_withdraw"),
TransactionKind::SetPausedFlags(_) => Self::no_evm_execution("set_paused_flags"),
TransactionKind::RegisterRelayer(_) => Self::no_evm_execution("register_relayer"),
TransactionKind::SetConnectorData(_) => Self::no_evm_execution("set_connector_data"),
TransactionKind::NewConnector(_) => Self::no_evm_execution("new_connector"),
TransactionKind::NewEngine(_) => Self::no_evm_execution("new_engine"),
TransactionKind::FactoryUpdate(_) => Self::no_evm_execution("factory_update"),
TransactionKind::FactoryUpdateAddressVersion(_) => {
Self::no_evm_execution("factory_update_address_version")
}
TransactionKind::FactorySetWNearAddress(_) => {
Self::no_evm_execution("factory_set_wnear_address")
}
TransactionKind::Unknown => Self::no_evm_execution("unknown"),
}
}

/// There are many cases where a receipt on NEAR can change the Aurora contract state, but no EVM execution actually occurs.
/// In these cases we have a sentinel Ethereum transaction from the zero address to itself with input equal to the method name.
fn no_evm_execution(method_name: &str) -> NormalizedEthTransaction {
NormalizedEthTransaction {
address: Address::from_array([0; 20]),
chain_id: None,
nonce: U256::zero(),
gas_limit: U256::zero(),
max_priority_fee_per_gas: U256::zero(),
max_fee_per_gas: U256::zero(),
to: Some(Address::from_array([0; 20])),
value: Wei::zero(),
data: method_name.as_bytes().to_vec(),
access_list: Vec::new(),
}
}

fn get_implicit_address(caller: &AccountId) -> types::Address {
aurora_engine_sdk::types::near_account_to_evm_address(caller.as_bytes())
}

fn get_implicit_nonce(
from: &types::Address,
block_height: u64,
transaction_position: u16,
storage: &Storage,
) -> U256 {
storage
.with_engine_access(block_height, transaction_position, &[], |io| {
aurora_engine::engine::get_nonce(&io, from)
})
.result
}
}

/// This data type represents `TransactionMessage` above in the way consistent with how it is
/// stored on disk (in the DB). This type implements borsh (de)serialization. The purpose of
/// having a private struct for borsh, which is separate from the main `TransactionMessage`
Expand Down
2 changes: 1 addition & 1 deletion engine-types/src/types/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl Address {
Ok(Self::new(H160::from_slice(raw_addr)))
}

pub fn from_array(array: [u8; 20]) -> Self {
pub const fn from_array(array: [u8; 20]) -> Self {
Self(H160(array))
}

Expand Down
Loading

0 comments on commit ec7de27

Please sign in to comment.