pallet-evm: refactor duplicate code in call/create/create2 (#4922)

* pallet-evm: refactor duplicate code in call/create/create2

* Bump runtime version
This commit is contained in:
Wei Tang
2020-02-13 21:21:19 +01:00
committed by GitHub
parent 0f122445f6
commit 78b5a06200
2 changed files with 101 additions and 142 deletions
+1 -1
View File
@@ -83,7 +83,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// implementation changes and behavior does not, then leave spec_version as // implementation changes and behavior does not, then leave spec_version as
// is and increment impl_version. // is and increment impl_version.
spec_version: 217, spec_version: 217,
impl_version: 0, impl_version: 1,
apis: RUNTIME_API_VERSIONS, apis: RUNTIME_API_VERSIONS,
}; };
+100 -141
View File
@@ -232,54 +232,22 @@ decl_module! {
nonce: Option<U256>, nonce: Option<U256>,
) -> DispatchResult { ) -> DispatchResult {
let sender = ensure_signed(origin)?; let sender = ensure_signed(origin)?;
ensure!(gas_price >= T::FeeCalculator::min_gas_price(), Error::<T>::GasPriceTooLow);
let source = T::ConvertAccountId::convert_account_id(&sender); let source = T::ConvertAccountId::convert_account_id(&sender);
let vicinity = Vicinity { Self::execute_evm(
gas_price,
origin: source,
};
let mut backend = Backend::<T>::new(&vicinity);
let mut executor = StackExecutor::new_with_precompile(
&backend,
gas_limit as usize,
&backend::GASOMETER_CONFIG,
T::Precompiles::execute,
);
let total_fee = gas_price.checked_mul(U256::from(gas_limit))
.ok_or(Error::<T>::FeeOverflow)?;
let total_payment = value.checked_add(total_fee).ok_or(Error::<T>::PaymentOverflow)?;
let source_account = Accounts::get(&source);
ensure!(source_account.balance >= total_payment, Error::<T>::BalanceLow);
executor.withdraw(source, total_fee).map_err(|_| Error::<T>::WithdrawFailed)?;
if let Some(nonce) = nonce {
ensure!(source_account.nonce == nonce, Error::<T>::InvalidNonce);
}
let reason = executor.transact_call(
source, source,
target,
value, value,
input, gas_limit,
gas_limit as usize, gas_price,
); nonce,
|executor| ((), executor.transact_call(
let ret = match reason { source,
ExitReason::Succeed(_) => Ok(()), target,
ExitReason::Error(_) => Err(Error::<T>::ExitReasonFailed), value,
ExitReason::Revert(_) => Err(Error::<T>::ExitReasonRevert), input,
ExitReason::Fatal(_) => Err(Error::<T>::ExitReasonFatal), gas_limit as usize,
}; )),
let actual_fee = executor.fee(gas_price); ).map_err(Into::into)
executor.deposit(source, total_fee.saturating_sub(actual_fee));
let (values, logs) = executor.deconstruct();
backend.apply(values, logs, true);
ret.map_err(Into::into)
} }
/// Issue an EVM create operation. This is similar to a contract creation transaction in /// Issue an EVM create operation. This is similar to a contract creation transaction in
@@ -294,60 +262,28 @@ decl_module! {
nonce: Option<U256>, nonce: Option<U256>,
) -> DispatchResult { ) -> DispatchResult {
let sender = ensure_signed(origin)?; let sender = ensure_signed(origin)?;
ensure!(gas_price >= T::FeeCalculator::min_gas_price(), Error::<T>::GasPriceTooLow);
let source = T::ConvertAccountId::convert_account_id(&sender); let source = T::ConvertAccountId::convert_account_id(&sender);
let vicinity = Vicinity { let create_address = Self::execute_evm(
gas_price,
origin: source,
};
let mut backend = Backend::<T>::new(&vicinity);
let mut executor = StackExecutor::new_with_precompile(
&backend,
gas_limit as usize,
&backend::GASOMETER_CONFIG,
T::Precompiles::execute,
);
let total_fee = gas_price.checked_mul(U256::from(gas_limit))
.ok_or(Error::<T>::FeeOverflow)?;
let total_payment = value.checked_add(total_fee).ok_or(Error::<T>::PaymentOverflow)?;
let source_account = Accounts::get(&source);
ensure!(source_account.balance >= total_payment, Error::<T>::BalanceLow);
executor.withdraw(source, total_fee).map_err(|_| Error::<T>::WithdrawFailed)?;
if let Some(nonce) = nonce {
ensure!(source_account.nonce == nonce, Error::<T>::InvalidNonce);
}
let create_address = executor.create_address(
evm::CreateScheme::Legacy { caller: source }
);
let reason = executor.transact_create(
source, source,
value, value,
init, gas_limit,
gas_limit as usize, gas_price,
); nonce,
|executor| {
let ret = match reason { (executor.create_address(
ExitReason::Succeed(_) => { evm::CreateScheme::Legacy { caller: source },
Module::<T>::deposit_event(Event::Created(create_address)); ), executor.transact_create(
Ok(()) source,
value,
init,
gas_limit as usize,
))
}, },
ExitReason::Error(_) => Err(Error::<T>::ExitReasonFailed), )?;
ExitReason::Revert(_) => Err(Error::<T>::ExitReasonRevert),
ExitReason::Fatal(_) => Err(Error::<T>::ExitReasonFatal),
};
let actual_fee = executor.fee(gas_price);
executor.deposit(source, total_fee.saturating_sub(actual_fee));
let (values, logs) = executor.deconstruct(); Module::<T>::deposit_event(Event::Created(create_address));
backend.apply(values, logs, true); Ok(())
ret.map_err(Into::into)
} }
/// Issue an EVM create2 operation. /// Issue an EVM create2 operation.
@@ -362,62 +298,30 @@ decl_module! {
nonce: Option<U256>, nonce: Option<U256>,
) -> DispatchResult { ) -> DispatchResult {
let sender = ensure_signed(origin)?; let sender = ensure_signed(origin)?;
ensure!(gas_price >= T::FeeCalculator::min_gas_price(), Error::<T>::GasPriceTooLow);
let source = T::ConvertAccountId::convert_account_id(&sender); let source = T::ConvertAccountId::convert_account_id(&sender);
let vicinity = Vicinity {
gas_price,
origin: source,
};
let mut backend = Backend::<T>::new(&vicinity);
let mut executor = StackExecutor::new_with_precompile(
&backend,
gas_limit as usize,
&backend::GASOMETER_CONFIG,
T::Precompiles::execute,
);
let total_fee = gas_price.checked_mul(U256::from(gas_limit))
.ok_or(Error::<T>::FeeOverflow)?;
let total_payment = value.checked_add(total_fee).ok_or(Error::<T>::PaymentOverflow)?;
let source_account = Accounts::get(&source);
ensure!(source_account.balance >= total_payment, Error::<T>::BalanceLow);
executor.withdraw(source, total_fee).map_err(|_| Error::<T>::WithdrawFailed)?;
if let Some(nonce) = nonce {
ensure!(source_account.nonce == nonce, Error::<T>::InvalidNonce);
}
let code_hash = H256::from_slice(Keccak256::digest(&init).as_slice()); let code_hash = H256::from_slice(Keccak256::digest(&init).as_slice());
let create_address = executor.create_address( let create_address = Self::execute_evm(
evm::CreateScheme::Create2 { caller: source, code_hash, salt }
);
let reason = executor.transact_create2(
source, source,
value, value,
init, gas_limit,
salt, gas_price,
gas_limit as usize, nonce,
); |executor| {
(executor.create_address(
let ret = match reason { evm::CreateScheme::Create2 { caller: source, code_hash, salt },
ExitReason::Succeed(_) => { ), executor.transact_create2(
Module::<T>::deposit_event(Event::Created(create_address)); source,
Ok(()) value,
init,
salt,
gas_limit as usize,
))
}, },
ExitReason::Error(_) => Err(Error::<T>::ExitReasonFailed), )?;
ExitReason::Revert(_) => Err(Error::<T>::ExitReasonRevert),
ExitReason::Fatal(_) => Err(Error::<T>::ExitReasonFatal),
};
let actual_fee = executor.fee(gas_price);
executor.deposit(source, total_fee.saturating_sub(actual_fee));
let (values, logs) = executor.deconstruct(); Module::<T>::deposit_event(Event::Created(create_address));
backend.apply(values, logs, true); Ok(())
ret.map_err(Into::into)
} }
} }
} }
@@ -454,4 +358,59 @@ impl<T: Trait> Module<T> {
AccountCodes::remove(address); AccountCodes::remove(address);
AccountStorages::remove_prefix(address); AccountStorages::remove_prefix(address);
} }
/// Execute an EVM operation.
fn execute_evm<F, R>(
source: H160,
value: U256,
gas_limit: u32,
gas_price: U256,
nonce: Option<U256>,
f: F,
) -> Result<R, Error<T>> where
F: FnOnce(&mut StackExecutor<Backend<T>>) -> (R, ExitReason),
{
ensure!(gas_price >= T::FeeCalculator::min_gas_price(), Error::<T>::GasPriceTooLow);
let vicinity = Vicinity {
gas_price,
origin: source,
};
let mut backend = Backend::<T>::new(&vicinity);
let mut executor = StackExecutor::new_with_precompile(
&backend,
gas_limit as usize,
&backend::GASOMETER_CONFIG,
T::Precompiles::execute,
);
let total_fee = gas_price.checked_mul(U256::from(gas_limit))
.ok_or(Error::<T>::FeeOverflow)?;
let total_payment = value.checked_add(total_fee).ok_or(Error::<T>::PaymentOverflow)?;
let source_account = Accounts::get(&source);
ensure!(source_account.balance >= total_payment, Error::<T>::BalanceLow);
executor.withdraw(source, total_fee).map_err(|_| Error::<T>::WithdrawFailed)?;
if let Some(nonce) = nonce {
ensure!(source_account.nonce == nonce, Error::<T>::InvalidNonce);
}
let (retv, reason) = f(&mut executor);
let ret = match reason {
ExitReason::Succeed(_) => Ok(retv),
ExitReason::Error(_) => Err(Error::<T>::ExitReasonFailed),
ExitReason::Revert(_) => Err(Error::<T>::ExitReasonRevert),
ExitReason::Fatal(_) => Err(Error::<T>::ExitReasonFatal),
};
let actual_fee = executor.fee(gas_price);
executor.deposit(source, total_fee.saturating_sub(actual_fee));
let (values, logs) = executor.deconstruct();
backend.apply(values, logs, true);
ret
}
} }