Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 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
11 changes: 10 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ jobs:
steps:
- name: Clone the repository
uses: actions/checkout@v2
- name: Cache Cargo artifacts
uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install the toolchain
uses: actions-rs/toolchain@v1
with:
Expand All @@ -19,6 +27,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
args: --verbose
args: --locked --verbose
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ aurora deploy-code 0x600060005560648060106000396000f360e060020a6000350480638ada0

### Examining EVM contract state

```console
$ aurora encode-address test.near
0xCBdA96B3F2B8eb962f97AE50C3852CA976740e2B
```

```sh
aurora get-nonce 0xCBdA96B3F2B8eb962f97AE50C3852CA976740e2B
aurora get-balance 0xCBdA96B3F2B8eb962f97AE50C3852CA976740e2B
Expand All @@ -127,6 +132,11 @@ aurora get-storage-at 0xFc481F4037887e10708552c0D7563Ec6858640d6 0

### Calling an EVM contract read-only

```console
$ aurora encode-address test.near
0xCBdA96B3F2B8eb962f97AE50C3852CA976740e2B
```

```sh
aurora view --sender 0xCBdA96B3F2B8eb962f97AE50C3852CA976740e2B 0xFc481F4037887e10708552c0D7563Ec6858640d6 0x8ada066e # getCounter()
aurora view --sender 0xCBdA96B3F2B8eb962f97AE50C3852CA976740e2B 0xFc481F4037887e10708552c0D7563Ec6858640d6 0xd09de08a # increment()
Expand Down
7 changes: 4 additions & 3 deletions src/benches/eth_deploy_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ use criterion::{BatchSize, BenchmarkId, Criterion, Throughput};
use secp256k1::SecretKey;

use crate::test_utils::{address_from_secret_key, create_eth_transaction, deploy_evm, SUBMIT};
use crate::types::Wei;

const INITIAL_BALANCE: u64 = 1000;
const INITIAL_BALANCE: Wei = Wei::new_u64(1000);
const INITIAL_NONCE: u64 = 0;
const TRANSFER_AMOUNT: u64 = 0;
const TRANSFER_AMOUNT: Wei = Wei::zero();

pub(crate) fn eth_deploy_code_benchmark(c: &mut Criterion) {
let mut runner = deploy_evm();
let mut rng = rand::thread_rng();
let source_account = SecretKey::random(&mut rng);
runner.create_address(
address_from_secret_key(&source_account),
INITIAL_BALANCE.into(),
INITIAL_BALANCE,
INITIAL_NONCE.into(),
);
let inputs: Vec<_> = [1, 4, 8, 12, 16]
Expand Down
2 changes: 1 addition & 1 deletion src/benches/eth_erc20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub(crate) fn eth_erc20_benchmark(c: &mut Criterion) {
let source_account = SecretKey::random(&mut rng);
runner.create_address(
address_from_secret_key(&source_account),
INITIAL_BALANCE.into(),
crate::types::Wei::new_u64(INITIAL_BALANCE),
INITIAL_NONCE.into(),
);
let calling_account_id = "some-account.near".to_string();
Expand Down
5 changes: 3 additions & 2 deletions src/benches/eth_standard_precompiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ use secp256k1::SecretKey;

use crate::test_utils::standard_precompiles::{PrecompilesConstructor, PrecompilesContract};
use crate::test_utils::{address_from_secret_key, deploy_evm, sign_transaction, SUBMIT};
use crate::types::Wei;

const INITIAL_BALANCE: u64 = 1000;
const INITIAL_BALANCE: Wei = Wei::new_u64(1000);
const INITIAL_NONCE: u64 = 0;

pub(crate) fn eth_standard_precompiles_benchmark(c: &mut Criterion) {
Expand All @@ -14,7 +15,7 @@ pub(crate) fn eth_standard_precompiles_benchmark(c: &mut Criterion) {
let source_account = SecretKey::random(&mut rng);
runner.create_address(
address_from_secret_key(&source_account),
INITIAL_BALANCE.into(),
INITIAL_BALANCE,
INITIAL_NONCE.into(),
);
let calling_account_id = "some-account.near".to_string();
Expand Down
9 changes: 5 additions & 4 deletions src/benches/eth_transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,25 @@ use criterion::{BatchSize, Criterion};
use secp256k1::SecretKey;

use crate::test_utils::{address_from_secret_key, create_eth_transaction, deploy_evm, SUBMIT};
use crate::types::Wei;

const INITIAL_BALANCE: u64 = 1000;
const INITIAL_BALANCE: Wei = Wei::new_u64(1000);
const INITIAL_NONCE: u64 = 0;
const TRANSFER_AMOUNT: u64 = 123;
const TRANSFER_AMOUNT: Wei = Wei::new_u64(123);

pub(crate) fn eth_transfer_benchmark(c: &mut Criterion) {
let mut runner = deploy_evm();
let mut rng = rand::thread_rng();
let source_account = SecretKey::random(&mut rng);
runner.create_address(
address_from_secret_key(&source_account),
INITIAL_BALANCE.into(),
INITIAL_BALANCE,
INITIAL_NONCE.into(),
);
let dest_account = address_from_secret_key(&SecretKey::random(&mut rng));
let transaction = create_eth_transaction(
Some(dest_account),
TRANSFER_AMOUNT.into(),
TRANSFER_AMOUNT,
vec![],
Some(runner.chain_id),
&source_account,
Expand Down
74 changes: 49 additions & 25 deletions src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::precompiles;
use crate::prelude::{Address, TryInto, Vec, H256, U256};
use crate::sdk;
use crate::storage::{address_to_key, bytes_to_key, storage_to_key, KeyPrefix, KeyPrefixU8};
use crate::types::{u256_to_arr, AccountId};
use crate::types::{u256_to_arr, AccountId, Wei};

/// Errors with the EVM engine.
#[derive(Debug, Clone, Eq, PartialEq)]
Expand Down Expand Up @@ -94,6 +94,22 @@ impl ExitIntoResult for ExitReason {
}
}

//TODO: check as I added `Debug` trait there. Perhaps this wasn't added earlier intentionally.
Comment thread
sept-en marked this conversation as resolved.
Outdated
#[derive(Debug)]
pub enum EngineStateError {
NotFound,
DeserializationFailed,
}

impl AsRef<[u8]> for EngineStateError {
fn as_ref(&self) -> &[u8] {
match self {
Self::NotFound => b"ERR_STATE_NOT_FOUND",
Self::DeserializationFailed => b"ERR_STATE_CORRUPTED",
}
}
}

/// Engine internal state, mostly configuration.
/// Should not contain anything large or enumerable.
#[derive(BorshSerialize, BorshDeserialize, Default)]
Expand Down Expand Up @@ -136,8 +152,8 @@ const CONFIG: &Config = &Config::istanbul();
const STATE_KEY: &[u8; 5] = b"STATE";

impl Engine {
pub fn new(origin: Address) -> Self {
Self::new_with_state(Engine::get_state(), origin)
pub fn new(origin: Address) -> Result<Self, EngineStateError> {
Engine::get_state().map(|state| Self::new_with_state(state, origin))
}

pub fn new_with_state(state: EngineState, origin: Address) -> Self {
Expand All @@ -153,10 +169,11 @@ impl Engine {
}

/// Fails if state is not found.
pub fn get_state() -> EngineState {
pub fn get_state() -> Result<EngineState, EngineStateError> {
match sdk::read_storage(&bytes_to_key(KeyPrefix::Config, STATE_KEY)) {
None => Default::default(),
Some(bytes) => EngineState::try_from_slice(&bytes).expect("ERR_DESER"),
None => Err(EngineStateError::NotFound),
Some(bytes) => EngineState::try_from_slice(&bytes)
.map_err(|_| EngineStateError::DeserializationFailed),
}
}

Expand All @@ -173,8 +190,7 @@ impl Engine {
}

pub fn get_code_size(address: &Address) -> usize {
// TODO: Seems this can be optimized to only read the register length.
Engine::get_code(&address).len()
sdk::read_storage_len(&address_to_key(KeyPrefix::Code, address)).unwrap_or(0)
}

pub fn set_nonce(address: &Address, nonce: &U256) {
Expand Down Expand Up @@ -207,24 +223,25 @@ impl Engine {
.unwrap_or_else(U256::zero)
}

pub fn set_balance(address: &Address, balance: &U256) {
pub fn set_balance(address: &Address, balance: &Wei) {
sdk::write_storage(
&address_to_key(KeyPrefix::Balance, address),
&u256_to_arr(balance),
&balance.to_bytes(),
);
}

pub fn remove_balance(address: &Address) {
let balance = Self::get_balance(address);
// Apply changes for eth-conenctor
EthConnectorContract::get_instance().internal_remove_eth(address, &balance);
EthConnectorContract::get_instance().internal_remove_eth(address, &balance.raw());
sdk::remove_storage(&address_to_key(KeyPrefix::Balance, address))
}

pub fn get_balance(address: &Address) -> U256 {
sdk::read_storage(&address_to_key(KeyPrefix::Balance, address))
pub fn get_balance(address: &Address) -> Wei {
let raw = sdk::read_storage(&address_to_key(KeyPrefix::Balance, address))
.map(|value| U256::from_big_endian(&value))
.unwrap_or_else(U256::zero)
.unwrap_or_else(U256::zero);
Wei::new(raw)
}

pub fn remove_storage(address: &Address, key: &H256) {
Expand All @@ -245,7 +262,7 @@ impl Engine {
let balance = Self::get_balance(address);
let nonce = Self::get_nonce(address);
let code_len = Self::get_code_size(address);
balance == U256::zero() && nonce == U256::zero() && code_len == 0
balance.is_zero() && nonce.is_zero() && code_len == 0
}

/// Removes all storage for the given address.
Expand Down Expand Up @@ -277,20 +294,20 @@ impl Engine {

pub fn deploy_code_with_input(&mut self, input: Vec<u8>) -> EngineResult<SubmitResult> {
let origin = self.origin();
let value = U256::zero();
let value = Wei::zero();
self.deploy_code(origin, value, input)
}

pub fn deploy_code(
&mut self,
origin: Address,
value: U256,
value: Wei,
input: Vec<u8>,
) -> EngineResult<SubmitResult> {
let mut executor = self.make_executor();
let address = executor.create_address(CreateScheme::Legacy { caller: origin });
let (status, result) = (
executor.transact_create(origin, value, input, u64::MAX),
executor.transact_create(origin, value.raw(), input, u64::MAX),
address,
);
let is_succeed = status.is_succeed();
Expand All @@ -310,19 +327,21 @@ impl Engine {
pub fn call_with_args(&mut self, args: FunctionCallArgs) -> EngineResult<SubmitResult> {
let origin = self.origin();
let contract = Address(args.contract);
let value = U256::zero();
let value = Wei::zero();
self.call(origin, contract, value, args.input)
}

pub fn call(
&mut self,
origin: Address,
contract: Address,
value: U256,
value: Wei,
input: Vec<u8>,
) -> EngineResult<SubmitResult> {
let mut executor = self.make_executor();
let (status, result) = executor.transact_call(origin, contract, value, input, u64::MAX);
let (status, result) =
executor.transact_call(origin, contract, value.raw(), input, u64::MAX);

let used_gas = executor.used_gas();
let (values, logs) = executor.into_state().deconstruct();
let is_succeed = status.is_succeed();
Expand Down Expand Up @@ -354,18 +373,19 @@ impl Engine {
let origin = Address::from_slice(&args.sender);
let contract = Address::from_slice(&args.address);
let value = U256::from_big_endian(&args.amount);
self.view(origin, contract, value, args.input)
self.view(origin, contract, Wei::new(value), args.input)
}

pub fn view(
&self,
origin: Address,
contract: Address,
value: U256,
value: Wei,
input: Vec<u8>,
) -> EngineResult<Vec<u8>> {
let mut executor = self.make_executor();
let (status, result) = executor.transact_call(origin, contract, value, input, u64::MAX);
let (status, result) =
executor.transact_call(origin, contract, value.raw(), input, u64::MAX);
status.into_result()?;
Ok(result)
}
Expand Down Expand Up @@ -484,7 +504,7 @@ impl evm::backend::Backend for Engine {
fn basic(&self, address: Address) -> Basic {
Basic {
nonce: Engine::get_nonce(&address),
balance: Engine::get_balance(&address),
balance: Engine::get_balance(&address).raw(),
}
}

Expand Down Expand Up @@ -523,9 +543,13 @@ impl ApplyBackend for Engine {
reset_storage,
} => {
Engine::set_nonce(&address, &basic.nonce);

//TODO: check this part
// Apply changes for eth-connector
EthConnectorContract::get_instance()
.internal_set_eth_balance(&address, &basic.balance);
Engine::set_balance(&address, &Wei::new(basic.balance));
Comment thread
sept-en marked this conversation as resolved.
Outdated

if let Some(code) = code {
Engine::set_code(&address, &code)
}
Expand Down
21 changes: 17 additions & 4 deletions src/fungible_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ impl FungibleToken {

/// Balance of ETH tokens
pub fn internal_unwrap_balance_of_eth(&self, address: EthAddress) -> Balance {
engine::Engine::get_balance(&prelude::Address(address)).as_u128()
engine::Engine::get_balance(&prelude::Address(address))
.raw()
.as_u128()
}

/// Internal deposit NEAR - NEP-141
Expand All @@ -63,7 +65,10 @@ impl FungibleToken {
pub fn internal_deposit_eth(&mut self, address: EthAddress, amount: Balance) {
let balance = self.internal_unwrap_balance_of_eth(address);
if let Some(new_balance) = balance.checked_add(amount) {
engine::Engine::set_balance(&prelude::Address(address), &U256::from(new_balance));
engine::Engine::set_balance(
&prelude::Address(address),
&Wei::new(U256::from(new_balance)),
);
self.total_supply_eth = self
.total_supply_eth
.checked_add(amount)
Expand Down Expand Up @@ -114,7 +119,10 @@ impl FungibleToken {
pub fn internal_withdraw_eth(&mut self, address: EthAddress, amount: Balance) {
let balance = self.internal_unwrap_balance_of_eth(address);
if let Some(new_balance) = balance.checked_sub(amount) {
engine::Engine::set_balance(&prelude::Address(address), &U256::from(new_balance));
engine::Engine::set_balance(
&prelude::Address(address),
&Wei::new(U256::from(new_balance)),
);
self.total_supply_eth = self
.total_supply_eth
.checked_sub(amount)
Expand Down Expand Up @@ -426,7 +434,9 @@ impl FungibleToken {
pub fn accounts_insert(&self, account_id: &str, amount: Balance) {
if !self.accounts_contains_key(account_id) {
let key = Self::get_statistic_key();
//TODO: verify `read_u64` unwrapping
Comment thread
artob marked this conversation as resolved.
Outdated
let accounts_counter = sdk::read_u64(&key)
.unwrap_or(Ok(0))
.unwrap_or(0)
.checked_add(1)
.expect("ERR_ACCOUNTS_COUNTER_OVERFLOW");
Expand All @@ -438,7 +448,10 @@ impl FungibleToken {
/// Get accounts counter for statistics
/// It represents total unique accounts.
pub fn get_accounts_counter(&self) -> u64 {
sdk::read_u64(&Self::get_statistic_key()).unwrap_or(0)
//TODO: verify `read_u64` unwrapping
sdk::read_u64(&Self::get_statistic_key())
.unwrap_or(Ok(0))
.unwrap_or(0)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks really strange.

}

fn accounts_contains_key(&self, account_id: &str) -> bool {
Expand Down
Loading