Skip to content
Open
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
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.

21 changes: 20 additions & 1 deletion crates/cfx_types/src/contract_address.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use super::{Address, H256, U256};
use super::{
Address, AddressSpaceUtil, AddressUtil, AddressWithSpace, Space, H256, U256,
};
use keccak_hash::keccak;
use rlp::RlpStream;

Expand Down Expand Up @@ -86,3 +88,20 @@ pub fn cal_contract_address(
};
return (address, code_hash);
}

pub fn cal_contract_address_with_space(
address_scheme: CreateContractAddressType, block_number: u64,
sender: &AddressWithSpace, nonce: &U256, code: &[u8],
) -> (AddressWithSpace, H256) {
let (mut address, code_hash) = cal_contract_address(
address_scheme,
block_number,
&sender.address,
nonce,
code,
);
if sender.space == Space::Native {
address.set_contract_type_bits();
}
(address.with_space(sender.space), code_hash)
}
6 changes: 5 additions & 1 deletion crates/cfx_types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,16 @@ mod utils;
pub use utils::*;

pub mod address_util;
pub use address_util::AddressUtil;

pub mod space_util;
pub use space_util::AddressSpaceUtil;

pub mod contract_address;
pub use contract_address::{cal_contract_address, CreateContractAddressType};
pub use contract_address::{
cal_contract_address, cal_contract_address_with_space,
CreateContractAddressType,
};

/// The KECCAK hash of an empty bloom filter (0x00 * 256)
pub const KECCAK_EMPTY_BLOOM: H256 = H256([
Expand Down
9 changes: 9 additions & 0 deletions crates/cfx_types/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,12 @@ pub fn u256_to_h256_be(value: U256) -> H256 {
pub fn h256_to_u256_be(value: H256) -> U256 {
U256::from_big_endian(value.as_bytes())
}

/// Creates an Ethereum address from an EVM word's upper 20 bytes
pub fn u256_to_address_be(value: U256) -> Address {
let mut buf = [0u8; 32];
value.to_big_endian(&mut buf);
let mut addr_bytes: [u8; 20] = [0u8; 20];
addr_bytes.copy_from_slice(&buf[12..]);
Address::from(addr_bytes)
}
15 changes: 7 additions & 8 deletions crates/cfxcore/core/src/genesis_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ use cfx_parameters::{
use cfx_statedb::StateDb;
use cfx_storage::{StorageManager, StorageManagerTrait};
use cfx_types::{
address_util::AddressUtil, Address, AddressSpaceUtil, AddressWithSpace,
Space, H256, U256,
address_util::AddressUtil, cal_contract_address_with_space, Address,
AddressSpaceUtil, AddressWithSpace, CreateContractAddressType, Space, H256,
U256,
};
use diem_crypto::{
bls::BLSPrivateKey, ec_vrf::EcVrfPublicKey, PrivateKey, ValidCryptoMaterial,
Expand All @@ -41,13 +42,11 @@ use secret_store::SecretStore;

use crate::verification::{compute_receipts_root, compute_transaction_root};
use cfx_executor::{
executive::{
contract_address, ExecutionOutcome, ExecutiveContext, TransactOptions,
},
executive::{ExecutionOutcome, ExecutiveContext, TransactOptions},
machine::Machine,
state::State,
};
use cfx_vm_types::{CreateContractAddress, Env};
use cfx_vm_types::Env;
use diem_types::account_address::AccountAddress;
use primitives::transaction::native_transaction::NativeTransaction;

Expand Down Expand Up @@ -323,8 +322,8 @@ pub fn genesis_block(
machine.clone(),
);

let (contract_address, _) = contract_address(
CreateContractAddress::FromSenderNonceAndCodeHash,
let (contract_address, _) = cal_contract_address_with_space(
CreateContractAddressType::FromSenderNonceAndCodeHash,
0,
&genesis_account_address,
&(i - 1).into(),
Expand Down
1 change: 1 addition & 0 deletions crates/client/src/rpc/impls/cfx/cfx_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1468,6 +1468,7 @@ impl RpcImpl {
has_gas_price: request.has_gas_price(),
has_nonce: request.nonce.is_some(),
has_storage_limit: request.storage_limit.is_some(),
collect_access_list: false,
};

let epoch_height = consensus_graph
Expand Down
12 changes: 6 additions & 6 deletions crates/client/src/rpc/types/cfx/receipt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
use crate::rpc::types::{Log, RpcAddress};
use cfx_addr::Network;
use cfx_types::{
address_util::AddressUtil, Bloom, Space, SpaceMap, H256, U256, U64,
address_util::AddressUtil, cal_contract_address, Bloom,
CreateContractAddressType, Space, SpaceMap, H256, U256, U64,
};
use cfx_util_macros::bail;
use cfx_vm_types::{contract_address, CreateContractAddress};
use primitives::{
receipt::{
Receipt as PrimitiveReceipt, StorageChange as PrimitiveStorageChange,
Expand Down Expand Up @@ -120,8 +120,8 @@ impl Receipt {
if Action::Create == unsigned.action()
&& outcome_status == TransactionStatus::Success
{
let (mut created_address, _) = contract_address(
CreateContractAddress::FromSenderNonceAndCodeHash,
let (mut created_address, _) = cal_contract_address(
CreateContractAddressType::FromSenderNonceAndCodeHash,
block_number.into(),
&transaction.sender,
unsigned.nonce(),
Expand All @@ -142,8 +142,8 @@ impl Receipt {
if Action::Create == unsigned.action()
&& outcome_status == TransactionStatus::Success
{
let (created_address, _) = contract_address(
CreateContractAddress::FromSenderNonce,
let (created_address, _) = cal_contract_address(
CreateContractAddressType::FromSenderNonce,
0,
&transaction.sender,
unsigned.nonce(),
Expand Down
1 change: 1 addition & 0 deletions crates/execution/execute-helper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ cfx-statedb = { workspace = true }
cfx-vm-tracer-derive = { workspace = true }
cfx-types = { workspace = true }
cfx-vm-types = { workspace = true }
cfx-vm-interpreter = { workspace = true }
cfx-executor = { workspace = true }
log = { workspace = true }
primitives = { workspace = true }
Expand Down
90 changes: 83 additions & 7 deletions crates/execution/execute-helper/src/estimation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,21 @@ use cfx_executor::{
use solidity_abi::string_revert_reason_decode;

use super::observer::{
exec_tracer::ErrorUnwind, gasman::GasLimitEstimation, Observer,
access_list::AccessListKey, exec_tracer::ErrorUnwind,
gasman::GasLimitEstimationKey, Observer,
};
use cfx_parameters::{consensus::ONE_CFX_IN_DRIP, staking::*};
use cfx_statedb::Result as DbResult;
use cfx_types::{
address_util::AddressUtil, Address, AddressSpaceUtil, Space, U256,
};
use cfx_vm_types::{self as vm, Env, Spec};
use primitives::{transaction::Action, SignedTransaction, Transaction};
use primitives::{
transaction::Action, AccessList, SignedTransaction, Transaction,
};
use std::{
cmp::{max, min},
collections::HashSet,
fmt::Display,
ops::{Mul, Shl},
};
Expand All @@ -33,6 +37,7 @@ enum SponsoredType {
pub struct EstimateExt {
pub estimated_gas_limit: U256,
pub estimated_storage_limit: u64,
pub access_list: AccessList, // default empty
}

pub struct EstimationContext<'a> {
Expand Down Expand Up @@ -140,6 +145,12 @@ impl<'a> EstimationContext<'a> {

self.process_estimate_request(&mut tx, &request)?;

let access_list = if request.collect_access_list {
self.collect_access_list(tx.clone(), request)?
} else {
AccessList::new()
};

let (executed, overwrite_storage_limit) = match self
.two_pass_estimation(&tx, request)?
{
Expand All @@ -156,6 +167,7 @@ impl<'a> EstimationContext<'a> {
executed, &tx,
),
estimated_storage_limit: storage_limit(executed),
access_list,
}
}
ExecutionOutcome::Finished(_) => unreachable!(),
Expand All @@ -169,9 +181,62 @@ impl<'a> EstimationContext<'a> {
executed,
overwrite_storage_limit,
&request,
access_list,
)
}

pub fn collect_access_list(
&mut self, tx: SignedTransaction, request: EstimateRequest,
) -> DbResult<AccessList> {
// prepare the excludes: add from, to, precompiles, 7702 authorities to
// excludes
let mut excludes = HashSet::new();
excludes.insert(tx.sender().address);
let to = match tx.transaction.action() {
Action::Call(to) => to,
Action::Create => {
tx.cal_created_address().expect("should success").address
}
};
excludes.insert(to);

if let Some(auth_list) = tx.authorization_list() {
excludes
.extend(auth_list.iter().filter_map(|auth| auth.authority()));
}

let builtins = match tx.space() {
Space::Native => &self.machine.builtins(),
Space::Ethereum => &self.machine.builtins_evm(),
};
excludes.extend(builtins.iter().map(|(addr, _)| *addr));

let access_list = tx
.access_list()
.map(|val| val.to_vec())
.unwrap_or(AccessList::new());

// execute the transaction to collect access list
let res = self.as_executive().transact(
&tx,
request.access_list_options(access_list, excludes),
)?;
let executed = match res {
ExecutionOutcome::Finished(executed) => executed,
ExecutionOutcome::ExecutionErrorBumpNonce(_exec_err, executed) => {
executed
}
ExecutionOutcome::NotExecutedDrop(_)
| ExecutionOutcome::NotExecutedToReconsiderPacking(_) => {
return Ok(AccessList::new());
}
};
let access_list = executed.ext_result.get::<AccessListKey>().expect(
"AccessListKey should be set by AccessListInspector observer",
);
Ok(access_list.to_vec())
}

fn check_cip130(
&self, tx: &SignedTransaction, request: &EstimateRequest,
) -> Option<(ExecutionOutcome, EstimateExt)> {
Expand All @@ -195,12 +260,11 @@ impl<'a> EstimationContext<'a> {
// storage limit paid by the sponsor are different values. So
// this function will
//
// 1. First Pass: Assuming the sponsor pays for storage collateral,
// check if the transaction will fail for
// NotEnoughBalanceForStorage.
// 1. First Pass: Assuming the sender pays for storage collateral,
// check if the transaction will finished
//
// 2. Second Pass: If it does, executes the transaction again assuming
// the user pays for the storage collateral. The resultant
// the sponsor pays for the storage collateral. The resultant
// storage limit must be larger than the maximum storage limit
// can be afford by the sponsor, to guarantee the user pays for
// the storage limit.
Expand Down Expand Up @@ -294,13 +358,15 @@ impl<'a> EstimationContext<'a> {
fn enact_executed_by_estimation_request(
&self, tx: SignedTransaction, mut executed: Executed,
overwrite_storage_limit: Option<u64>, request: &EstimateRequest,
access_list: AccessList,
) -> DbResult<(ExecutionOutcome, EstimateExt)> {
let estimated_storage_limit =
overwrite_storage_limit.unwrap_or(storage_limit(&executed));
let estimated_gas_limit = estimated_gas_limit(&executed, &tx);
let estimation = EstimateExt {
estimated_storage_limit,
estimated_gas_limit,
access_list,
};

let gas_sponsored_contract_if_eligible_sender = self
Expand Down Expand Up @@ -412,7 +478,7 @@ fn estimated_gas_limit(executed: &Executed, tx: &SignedTransaction) -> U256 {
.map(|&x| if x == 0 { 10 } else { 40 })
.sum::<u64>();
let estimated =
executed.ext_result.get::<GasLimitEstimation>().unwrap() * 7 / 6
executed.ext_result.get::<GasLimitEstimationKey>().unwrap() * 7 / 6
+ executed.base_gas;
U256::max(
eip7623_gas_limit.into(),
Expand Down Expand Up @@ -464,6 +530,7 @@ pub struct EstimateRequest {
pub has_gas_price: bool,
pub has_nonce: bool,
pub has_storage_limit: bool,
pub collect_access_list: bool,
}

impl EstimateRequest {
Expand Down Expand Up @@ -498,4 +565,13 @@ impl EstimateRequest {
settings: self.transact_settings(ChargeCollateral::EstimateSponsor),
}
}

pub fn access_list_options(
self, access_list: AccessList, excludes: HashSet<Address>,
) -> TransactOptions<Observer> {
TransactOptions {
observer: Observer::access_list_inspector(access_list, excludes),
settings: self.transact_settings(ChargeCollateral::EstimateSender),
}
}
}
Loading
Loading