Skip to content

Commit

Permalink
Merge branch 'feat/erc20-gas-token' into chore/aleksuss/charge_gas_optim
Browse files Browse the repository at this point in the history
  • Loading branch information
aleksuss authored Feb 3, 2023
2 parents 4021045 + df11f14 commit b30b5db
Show file tree
Hide file tree
Showing 27 changed files with 860 additions and 1,017 deletions.
6 changes: 3 additions & 3 deletions engine-standalone-storage/src/relayer_db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ pub mod error {
pub enum Error {
Storage(crate::Error),
Postgres(postgres::Error),
EngineState(state::error::EngineStateError),
EngineState(state::EngineStateError),
Engine(engine::EngineError),
}

Expand All @@ -181,8 +181,8 @@ pub mod error {
}
}

impl From<state::error::EngineStateError> for Error {
fn from(e: state::error::EngineStateError) -> Self {
impl From<state::EngineStateError> for Error {
fn from(e: state::EngineStateError) -> Self {
Self::EngineState(e)
}
}
Expand Down
8 changes: 4 additions & 4 deletions engine-standalone-storage/src/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ fn non_submit_execute<'db>(
}

TransactionKind::RefundOnError(maybe_args) => {
let result: Result<Option<TransactionExecutionResult>, state::error::EngineStateError> =
let result: Result<Option<TransactionExecutionResult>, state::EngineStateError> =
maybe_args
.clone()
.map(|args| {
Expand Down Expand Up @@ -438,7 +438,7 @@ pub mod error {

#[derive(Debug)]
pub enum Error {
EngineState(state::error::EngineStateError),
EngineState(state::EngineStateError),
Engine(engine::EngineError),
DeployErc20(engine::DeployErc20Error),
FtOnTransfer(connector::error::FtTransferCallError),
Expand All @@ -452,8 +452,8 @@ pub mod error {
ConnectorStorage(connector::error::StorageReadError),
}

impl From<state::error::EngineStateError> for Error {
fn from(e: state::error::EngineStateError) -> Self {
impl From<state::EngineStateError> for Error {
fn from(e: state::EngineStateError) -> Self {
Self::EngineState(e)
}
}
Expand Down
23 changes: 9 additions & 14 deletions engine-test-doubles/src/io.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use aurora_engine_sdk::io::{StorageIntermediate, IO};
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::RwLock;

pub struct Value(Vec<u8>);

Expand All @@ -27,37 +27,32 @@ pub struct Storage {

/// In-memory implementation of [IO].
#[derive(Debug, Clone, Copy)]
pub struct StoragePointer<'a>(pub &'a RwLock<Storage>);
pub struct StoragePointer<'a>(pub &'a RefCell<Storage>);

impl<'a> IO for StoragePointer<'a> {
type StorageValue = Value;

fn read_input(&self) -> Self::StorageValue {
Value(self.0.read().unwrap().input.clone())
Value(self.0.borrow().input.clone())
}

fn return_output(&mut self, value: &[u8]) {
let mut storage = self.0.write().unwrap();
let mut storage = self.0.borrow_mut();
storage.output = value.to_vec();
}

fn read_storage(&self, key: &[u8]) -> Option<Self::StorageValue> {
self.0
.read()
.unwrap()
.kv_store
.get(key)
.map(|v| Value(v.clone()))
self.0.borrow().kv_store.get(key).map(|v| Value(v.clone()))
}

fn storage_has_key(&self, key: &[u8]) -> bool {
self.0.read().unwrap().kv_store.contains_key(key)
self.0.borrow().kv_store.contains_key(key)
}

fn write_storage(&mut self, key: &[u8], value: &[u8]) -> Option<Self::StorageValue> {
let key = key.to_vec();
let value = value.to_vec();
let mut storage = self.0.write().unwrap();
let mut storage = self.0.borrow_mut();
storage.kv_store.insert(key, value).map(Value)
}

Expand All @@ -67,12 +62,12 @@ impl<'a> IO for StoragePointer<'a> {
value: Self::StorageValue,
) -> Option<Self::StorageValue> {
let key = key.to_vec();
let mut storage = self.0.write().unwrap();
let mut storage = self.0.borrow_mut();
storage.kv_store.insert(key, value.0).map(Value)
}

fn remove_storage(&mut self, key: &[u8]) -> Option<Self::StorageValue> {
let mut storage = self.0.write().unwrap();
let mut storage = self.0.borrow_mut();
storage.kv_store.remove(key).map(Value)
}
}
4 changes: 2 additions & 2 deletions engine-tests/src/tests/standalone/sanity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use aurora_engine_test_doubles::io::{Storage, StoragePointer};
use aurora_engine_test_doubles::promise::PromiseTracker;
use aurora_engine_types::types::{Address, EthGas, Wei};
use aurora_engine_types::{account_id::AccountId, H160, H256, U256};
use std::sync::RwLock;
use std::cell::RefCell;

#[test]
fn test_deploy_code() {
Expand All @@ -22,7 +22,7 @@ fn test_deploy_code() {
default_gas_token: Default::default(),
};
let origin = Address::new(H160([0u8; 20]));
let storage = RwLock::new(Storage::default());
let storage = RefCell::new(Storage::default());
let io = StoragePointer(&storage);
let env = aurora_engine_sdk::env::Fixed {
signer_account_id: owner_id.clone(),
Expand Down
5 changes: 5 additions & 0 deletions engine-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,9 @@ rand = "0.8.5"
[features]
default = ["std"]
std = ["borsh/std", "hex/std", "primitive-types/std"]
# `primitive-types/std` is excluded because its `std` implementation includes a transitive
# dependency on `getrandom` which uses OS call to obtain entropy. Such calls are not
# available in Wasm, therefore we cannot use the `std` implementation of `primitive-types`
# in other Rust contracts.
contracts-std = ["borsh/std", "hex/std"]
impl-serde = ["primitive-types/impl-serde", "serde"]
7 changes: 5 additions & 2 deletions engine-types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc_error_handler))]
#![cfg_attr(not(any(feature = "std", feature = "contracts-std")), no_std)]
#![cfg_attr(
not(any(feature = "std", feature = "contracts-std")),
feature(alloc_error_handler)
)]
#![cfg_attr(feature = "log", feature(panic_info_message))]
#![deny(clippy::as_conversions)]

Expand Down
227 changes: 227 additions & 0 deletions engine-types/src/parameters/engine.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
use crate::{
account_id::AccountId,
types::{Address, RawH256, RawU256, WeiU256},
Vec,
};
use borsh::{BorshDeserialize, BorshSerialize};

#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ResultLog {
pub address: Address,
pub topics: Vec<RawU256>,
pub data: Vec<u8>,
}

/// The status of a transaction.
#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TransactionStatus {
Succeed(Vec<u8>),
Revert(Vec<u8>),
OutOfGas,
OutOfFund,
OutOfOffset,
CallTooDeep,
}

impl TransactionStatus {
pub fn is_ok(&self) -> bool {
matches!(*self, TransactionStatus::Succeed(_))
}

pub fn is_revert(&self) -> bool {
matches!(*self, TransactionStatus::Revert(_))
}

pub fn is_fail(&self) -> bool {
*self == TransactionStatus::OutOfGas
|| *self == TransactionStatus::OutOfFund
|| *self == TransactionStatus::OutOfOffset
|| *self == TransactionStatus::CallTooDeep
}
}

impl AsRef<[u8]> for TransactionStatus {
fn as_ref(&self) -> &[u8] {
match self {
Self::Succeed(_) => b"SUCCESS",
Self::Revert(_) => errors::ERR_REVERT,
Self::OutOfFund => errors::ERR_OUT_OF_FUNDS,
Self::OutOfGas => errors::ERR_OUT_OF_GAS,
Self::OutOfOffset => errors::ERR_OUT_OF_OFFSET,
Self::CallTooDeep => errors::ERR_CALL_TOO_DEEP,
}
}
}

/// 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(serde::Serialize, serde::Deserialize))]
pub struct SubmitResult {
version: u8,
pub status: TransactionStatus,
pub gas_used: u64,
pub logs: Vec<ResultLog>,
}

impl SubmitResult {
/// Must be incremented when making breaking changes to the SubmitResult ABI.
/// The current value of 7 is chosen because previously a `TransactionStatus` object
/// was first in the serialization, which is an enum with less than 7 variants.
/// Therefore, no previous `SubmitResult` would have began with a leading 7 byte,
/// and this can be used to distinguish the new ABI (with version byte) from the old.
const VERSION: u8 = 7;

pub fn new(status: TransactionStatus, gas_used: u64, logs: Vec<ResultLog>) -> Self {
Self {
version: Self::VERSION,
status,
gas_used,
logs,
}
}
}

/// Borsh-encoded parameters for the engine `call` function.
#[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq, Clone)]
pub struct FunctionCallArgsV2 {
pub contract: Address,
/// Wei compatible Borsh-encoded value field to attach an ETH balance to the transaction
pub value: WeiU256,
pub input: Vec<u8>,
}

/// Legacy Borsh-encoded parameters for the engine `call` function, to provide backward type compatibility
#[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq, Clone)]
pub struct FunctionCallArgsV1 {
pub contract: Address,
pub input: Vec<u8>,
}

/// Deserialized values from bytes to current or legacy Borsh-encoded parameters
/// for passing to the engine `call` function, and to provide backward type compatibility
#[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq, Clone)]
pub enum CallArgs {
V2(FunctionCallArgsV2),
V1(FunctionCallArgsV1),
}

impl CallArgs {
pub fn deserialize(bytes: &[u8]) -> Option<Self> {
// For handling new input format (wrapped into call args enum) - for data structures with new arguments,
// made for flexibility and extensibility.
if let Ok(value) = Self::try_from_slice(bytes) {
Some(value)
// Fallback, for handling old input format,
// i.e. input, formed as a raw (not wrapped into call args enum) data structure with legacy arguments,
// made for backward compatibility.
} else if let Ok(value) = FunctionCallArgsV1::try_from_slice(bytes) {
Some(Self::V1(value))
// Dealing with unrecognized input should be handled and result as an exception in a call site.
} else {
None
}
}
}

/// Borsh-encoded parameters for the `view` function.
#[derive(BorshSerialize, BorshDeserialize, Debug, Eq, PartialEq)]
pub struct ViewCallArgs {
pub sender: Address,
pub address: Address,
pub amount: RawU256,
pub input: Vec<u8>,
}

/// Borsh-encoded parameters for `deploy_erc20_token` function.
#[derive(BorshSerialize, BorshDeserialize, Debug, Eq, PartialEq, Clone)]
pub struct DeployErc20TokenArgs {
pub nep141: AccountId,
}

/// Borsh-encoded parameters for `get_erc20_from_nep141` function.
pub type GetErc20FromNep141CallArgs = DeployErc20TokenArgs;

/// Borsh-encoded parameters for the `get_storage_at` function.
#[derive(BorshSerialize, BorshDeserialize)]
pub struct GetStorageAtArgs {
pub address: Address,
pub key: RawH256,
}

pub mod errors {
pub const ERR_REVERT: &[u8; 10] = b"ERR_REVERT";
pub const ERR_OUT_OF_FUNDS: &[u8; 16] = b"ERR_OUT_OF_FUNDS";
pub const ERR_CALL_TOO_DEEP: &[u8; 17] = b"ERR_CALL_TOO_DEEP";
pub const ERR_OUT_OF_OFFSET: &[u8; 17] = b"ERR_OUT_OF_OFFSET";
pub const ERR_OUT_OF_GAS: &[u8; 14] = b"ERR_OUT_OF_GAS";
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_view_call_fail() {
let bytes = [0; 71];
let _ = ViewCallArgs::try_from_slice(&bytes).unwrap_err();
}

#[test]
fn test_roundtrip_view_call() {
let x = ViewCallArgs {
sender: Address::from_array([1; 20]),
address: Address::from_array([2; 20]),
amount: [3; 32],
input: vec![1, 2, 3],
};
let bytes = x.try_to_vec().unwrap();
let res = ViewCallArgs::try_from_slice(&bytes).unwrap();
assert_eq!(x, res);
}

#[test]
fn test_call_args_deserialize() {
let new_input = FunctionCallArgsV2 {
contract: Address::from_array([0u8; 20]),
value: WeiU256::default(),
input: Vec::new(),
};
let legacy_input = FunctionCallArgsV1 {
contract: Address::from_array([0u8; 20]),
input: Vec::new(),
};

// Parsing bytes in a new input format - data structures (wrapped into call args enum) with new arguments,
// made for flexibility and extensibility.

// Using new input format (wrapped into call args enum) and data structure with new argument (`value` field).
let input_bytes = CallArgs::V2(new_input.clone()).try_to_vec().unwrap();
let parsed_data = CallArgs::deserialize(&input_bytes);
assert_eq!(parsed_data, Some(CallArgs::V2(new_input.clone())));

// Using new input format (wrapped into call args enum) and old data structure with legacy arguments,
// this is allowed for compatibility reason.
let input_bytes = CallArgs::V1(legacy_input.clone()).try_to_vec().unwrap();
let parsed_data = CallArgs::deserialize(&input_bytes);
assert_eq!(parsed_data, Some(CallArgs::V1(legacy_input.clone())));

// Parsing bytes in an old input format - raw data structure (not wrapped into call args enum) with legacy arguments,
// made for backward compatibility.

// Using old input format (not wrapped into call args enum) - raw data structure with legacy arguments.
let input_bytes = legacy_input.try_to_vec().unwrap();
let parsed_data = CallArgs::deserialize(&input_bytes);
assert_eq!(parsed_data, Some(CallArgs::V1(legacy_input)));

// Using old input format (not wrapped into call args enum) - raw data structure with new argument (`value` field).
// Data structures with new arguments allowed only in new input format for future extensibility reason.
// Raw data structure (old input format) allowed only with legacy arguments for backward compatibility reason.
// Unrecognized input should be handled and result as an exception in a call site.
let input_bytes = new_input.try_to_vec().unwrap();
let parsed_data = CallArgs::deserialize(&input_bytes);
assert_eq!(parsed_data, None);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use crate::*;
use borsh::maybestd::io;
use borsh::{BorshDeserialize, BorshSerialize};

pub mod engine;

#[must_use]
#[derive(Debug, BorshSerialize, BorshDeserialize)]
pub enum PromiseArgs {
Expand Down
Loading

0 comments on commit b30b5db

Please sign in to comment.