Skip to content
This repository has been archived by the owner on Mar 13, 2023. It is now read-only.

Update dvm #363

Closed
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
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions bin/node-template/node/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ where
client.clone(),
pool.clone(),
TransactionConverter,
network.clone(),
is_authority,
)));
io.extend_with(EthPubSubApiServer::to_delegate(EthPubSubApi::new(
Expand Down
45 changes: 4 additions & 41 deletions bin/node-template/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1515,15 +1515,15 @@ impl_runtime_apis! {

impl dvm_rpc_primitives::EthereumRuntimeRPCApi<Block> for Runtime {
fn chain_id() -> u64 {
ChainId::get()
<Runtime as pallet_evm::Trait>::ChainId::get()
}

fn account_basic(address: H160) -> EVMAccount {
<Runtime as pallet_evm::Trait>::AccountBasicMapping::account_basic(&address)
}

fn gas_price() -> U256 {
FixedGasPrice::min_gas_price()
<Runtime as pallet_evm::Trait>::FeeCalculator::min_gas_price()
}

fn account_code_at(address: H160) -> Vec<u8> {
Expand All @@ -1548,45 +1548,8 @@ impl_runtime_apis! {
gas_price: Option<U256>,
nonce: Option<U256>,
action: dvm_ethereum::TransactionAction,
) -> Result<(Vec<u8>, U256), sp_runtime::DispatchError> {
// --- substrate ---
use sp_runtime::traits::UniqueSaturatedInto;

// ensure that the gas_limit fits within a u32; otherwise the wrong value will be passed
let gas_limit_considered: u32 = gas_limit.unique_saturated_into();
let gas_limit_considered_256: U256 = gas_limit_considered.into();
if gas_limit_considered_256 != gas_limit {
frame_support::debug::warn!("WARNING: An invalid gas_limit amount was submitted.
Make sure your gas_limit fits within a 32-bit integer
(gas_limit: {:?})", gas_limit);
}
match action {
dvm_ethereum::TransactionAction::Call(to) =>
EVM::execute_call(
from,
to,
data,
value,
gas_limit_considered,
gas_price.unwrap_or(U256::from(0)),
nonce,
false,
)
.map(|(_, ret, gas, _)| (ret, gas))
.map_err(|err| err.into()),
dvm_ethereum::TransactionAction::Create =>
EVM::execute_create(
from,
data,
value,
gas_limit_considered,
gas_price.unwrap_or(U256::from(0)),
nonce,
false,
)
.map(|(_, _, gas, _)| (vec![], gas))
.map_err(|err| err.into()),
}
) -> Result<(Vec<u8>, U256), (sp_runtime::DispatchError, Vec<u8>)> {
<dvm_ethereum::Module<Runtime>>::call(from, data, value, gas_limit.low_u32(), gas_price.unwrap_or_default(), nonce, action)
}

fn current_transaction_statuses() -> Option<Vec<TransactionStatus>> {
Expand Down
225 changes: 138 additions & 87 deletions frame/dvm/ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ mod mock;
pub mod account_basic;
pub mod precompiles;

#[derive(Eq, PartialEq, Clone, sp_runtime::RuntimeDebug)]
pub enum ReturnValue {
Bytes(Vec<u8>),
Hash(H160),
}

/// A type alias for the balance type from this pallet's point of view.
pub type BalanceOf<T> = <T as darwinia_balances::Trait>::Balance;
type RingInstance = darwinia_balances::Instance0;
Expand Down Expand Up @@ -364,79 +370,49 @@ impl<T: Trait> Module<T> {
}

/// Execute an Ethereum transaction, ignoring transaction signatures.
pub fn execute(source: H160, transaction: ethereum::Transaction) -> DispatchResult {
pub fn execute(from: H160, transaction: ethereum::Transaction) -> DispatchResult {
let transaction_hash =
H256::from_slice(Keccak256::digest(&rlp::encode(&transaction)).as_slice());
let transaction_index = Pending::get().len() as u32;
let (exit_reason, returned_value, gas_used, logs) = Self::execute_evm(
from,
transaction.input.clone(),
transaction.value,
transaction.gas_limit.low_u32(),
transaction.gas_price,
Some(transaction.nonce),
transaction.action,
true,
)?;

Self::handle_exit_reason(exit_reason)?;

let to = match transaction.action {
TransactionAction::Create => None,
TransactionAction::Call(to) => Some(to),
};

let (status, gas_used) = match transaction.action {
ethereum::TransactionAction::Call(target) => {
let (_, _, gas_used, logs) =
Self::handle_exec(pallet_evm::Module::<T>::execute_call(
source,
target,
transaction.input.clone(),
transaction.value,
transaction.gas_limit.low_u32(),
transaction.gas_price,
Some(transaction.nonce),
true,
)?)?;

(
TransactionStatus {
transaction_hash,
transaction_index,
from: source,
to: Some(target),
contract_address: None,
logs: {
logs.into_iter()
.map(|log| Log {
address: log.address,
topics: log.topics,
data: log.data,
})
.collect()
},
logs_bloom: Bloom::default(), // TODO: feed in bloom.
},
gas_used,
)
}
ethereum::TransactionAction::Create => {
let (_, contract_address, gas_used, logs) =
Self::handle_exec(pallet_evm::Module::<T>::execute_create(
source,
transaction.input.clone(),
transaction.value,
transaction.gas_limit.low_u32(),
transaction.gas_price,
Some(transaction.nonce),
true,
)?)?;
let contract_address = match returned_value {
ReturnValue::Bytes(_) => None,
ReturnValue::Hash(addr) => Some(addr),
};

(
TransactionStatus {
transaction_hash,
transaction_index,
from: source,
to: None,
contract_address: Some(contract_address),
logs: {
logs.into_iter()
.map(|log| Log {
address: log.address,
topics: log.topics,
data: log.data,
})
.collect()
},
logs_bloom: Bloom::default(), // TODO: feed in bloom.
},
gas_used,
)
}
let status = TransactionStatus {
transaction_hash,
transaction_index,
from,
to,
contract_address,
logs: {
logs.into_iter()
.map(|log| Log {
address: log.address,
topics: log.topics,
data: log.data,
})
.collect()
},
logs_bloom: Bloom::default(), // TODO: feed in bloom.
};

let receipt = ethereum::Receipt {
Expand All @@ -451,11 +427,86 @@ impl<T: Trait> Module<T> {
Ok(())
}

fn handle_exec<R>(
res: (ExitReason, R, U256, Vec<pallet_evm::Log>),
) -> Result<(ExitReason, R, U256, Vec<pallet_evm::Log>), Error<T>> {
match res.0 {
ExitReason::Succeed(_s) => Ok(res),
/// Execute an EVM call or create
pub fn call(
source: H160,
data: Vec<u8>,
value: U256,
gas_limit: u32,
gas_price: U256,
nonce: Option<U256>,
action: TransactionAction,
) -> Result<(Vec<u8>, U256), (sp_runtime::DispatchError, Vec<u8>)> {
let (exit_reason, returned_value, gas_used, _) = Self::execute_evm(
source, data, value, gas_limit, gas_price, nonce, action, false,
)
.map_err(|err| (err.into(), Vec::new()))?;

let returned_value = match returned_value.clone() {
ReturnValue::Bytes(data) => data,
ReturnValue::Hash(_) => Vec::new(),
};

Self::handle_exit_reason(exit_reason)
.map_err(|err| (err.into(), returned_value.clone()))?;

Ok((returned_value, gas_used))
}
}

impl<T: Trait> Module<T> {
fn execute_evm(
source: H160,
data: Vec<u8>,
value: U256,
gas_limit: u32,
gas_price: U256,
nonce: Option<U256>,
action: TransactionAction,
apply_state: bool,
) -> Result<(ExitReason, ReturnValue, U256, Vec<pallet_evm::Log>), pallet_evm::Error<T>> {
match action {
TransactionAction::Call(target) => pallet_evm::Module::<T>::execute_call(
source,
target,
data,
value,
gas_limit,
gas_price,
nonce,
apply_state,
)
.map(|(exit_reason, returned_value, gas_used, logs)| {
(
exit_reason,
ReturnValue::Bytes(returned_value),
gas_used,
logs,
)
}),
TransactionAction::Create => pallet_evm::Module::<T>::execute_create(
source,
data,
value,
gas_limit,
gas_price,
nonce,
apply_state,
)
.map(|(exit_reason, returned_value, gas_used, logs)| {
(
exit_reason,
ReturnValue::Hash(returned_value),
gas_used,
logs,
)
}),
}
}

fn handle_exit_reason(exit_reason: ExitReason) -> Result<(), Error<T>> {
match exit_reason {
ExitReason::Succeed(_s) => Ok(()),
ExitReason::Error(e) => Err(Self::parse_exit_error(e)),
ExitReason::Revert(e) => match e {
ExitRevert::Reverted => Err(Error::<T>::Reverted),
Expand All @@ -471,20 +522,20 @@ impl<T: Trait> Module<T> {

fn parse_exit_error(exit_error: ExitError) -> Error<T> {
match exit_error {
ExitError::StackUnderflow => return Error::<T>::StackUnderflow,
ExitError::StackOverflow => return Error::<T>::StackOverflow,
ExitError::InvalidJump => return Error::<T>::InvalidJump,
ExitError::InvalidRange => return Error::<T>::InvalidRange,
ExitError::DesignatedInvalid => return Error::<T>::DesignatedInvalid,
ExitError::CallTooDeep => return Error::<T>::CallTooDeep,
ExitError::CreateCollision => return Error::<T>::CreateCollision,
ExitError::CreateContractLimit => return Error::<T>::CreateContractLimit,
ExitError::OutOfOffset => return Error::<T>::OutOfOffset,
ExitError::OutOfGas => return Error::<T>::OutOfGas,
ExitError::OutOfFund => return Error::<T>::OutOfFund,
ExitError::PCUnderflow => return Error::<T>::PCUnderflow,
ExitError::CreateEmpty => return Error::<T>::CreateEmpty,
ExitError::Other(_s) => return Error::<T>::ExitErrorOther,
ExitError::StackUnderflow => Error::<T>::StackUnderflow,
ExitError::StackOverflow => Error::<T>::StackOverflow,
ExitError::InvalidJump => Error::<T>::InvalidJump,
ExitError::InvalidRange => Error::<T>::InvalidRange,
ExitError::DesignatedInvalid => Error::<T>::DesignatedInvalid,
ExitError::CallTooDeep => Error::<T>::CallTooDeep,
ExitError::CreateCollision => Error::<T>::CreateCollision,
ExitError::CreateContractLimit => Error::<T>::CreateContractLimit,
ExitError::OutOfOffset => Error::<T>::OutOfOffset,
ExitError::OutOfGas => Error::<T>::OutOfGas,
ExitError::OutOfFund => Error::<T>::OutOfFund,
ExitError::PCUnderflow => Error::<T>::PCUnderflow,
ExitError::CreateEmpty => Error::<T>::CreateEmpty,
ExitError::Other(_s) => Error::<T>::ExitErrorOther,
}
}
}
Loading