Skip to content

Commit

Permalink
EVM + Weight v2 support (#1039)
Browse files Browse the repository at this point in the history
* wip `record_extarnal_cost`

* Add support for external cost recording from the EVM

* Add refund external cost support

* Separate dispatchables with weight limit

* introduce tbd EthereumWeigher

* Validate gas to weight conversion

* Add static opcode recording with temp costs

* Add optional `transaction_len` parameter to `GasWeightMapping`

* Account for pallet and call indexes

* Rollback `transaction_len` param, use MAX_POV_SIZE ratio instead

* wip tests

* Add `uncached_account_code_proof_size_accounting_works` test

* wip tests

* Temp remove static external cost accounting

* fix build

* Temp remove static external cost accounting 2

* warning cleanup

* fmt

* clippy

* taplo

* Add `evm-with-weight-limit` to ci

* Temp set evm fork + update Cargo.lock

* handle `code_hash`

* taplo

* fmt

* Handle `transact_with_weight_limit` as self contained

* fix ts tests

* suggestion

* remove precompile test

* some suggestions

* remove `transact_with_weight_limit`

* configurable `MaxPovSize`

* test pov size constants

* accessed storage overlayed cache

* `new_from_weight_limit` suggestion

* remove unnecessary check

* warnings cleanup

* set constant gas limit max pov size ratio

* check state version for suicide

* just completely remove suicide accounting

* - `code` must be able to oog
- refund based on effective used gas

* `is_empty` accounting

* fix build

* `SSTORE` must record account storage proof size

* suggestion: move weight_limit checks

* editorconfig

* fmt

* rename `transaction_len` to `proof_size_base_cost` in runner

* move `proof_size_base_cost` to validation primitive

* gas limit saturated conversion

* remove transaction proof size check outside validation

* pin evm

* pin evm+

* fix todos

* fix build

* scope of already recorded codes and storages must be per transaction

* pin evm + implement new `record_external_operation`

* fix runtime api versioning + legacy `ExecutionInfo` handling

* editorconfig

* cargo fmt

* clippy

* suggestion remove `evm-with-weight-limit` feature

* fmt

* update comment

* update tests for additional `AccountBasicRead` in the evm

* update evm pin
  • Loading branch information
tgmichel authored Jun 21, 2023
1 parent fba8457 commit 0c1680b
Show file tree
Hide file tree
Showing 24 changed files with 1,682 additions and 191 deletions.
16 changes: 6 additions & 10 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ bn = { package = "substrate-bn", version = "0.6", default-features = false }
environmental = { version = "1.1.4", default-features = false }
ethereum = { version = "0.14.0", default-features = false }
ethereum-types = { version = "0.14.1", default-features = false }
evm = { version = "0.39.0", default-features = false }
evm = { git = "https://github.com/rust-blockchain/evm", branch = "master", default-features = false }
hex-literal = { version = "0.3.4" }
impl-serde = { version = "0.4.0", default-features = false }
jsonrpsee = "0.16.2"
Expand Down
185 changes: 149 additions & 36 deletions client/rpc/src/eth/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use sp_runtime::{traits::Block as BlockT, DispatchError, SaturatedConversion};
use sp_state_machine::OverlayedChanges;
// Frontier
use fc_rpc_core::types::*;
use fp_evm::CallInfo;
use fp_evm::{ExecutionInfo, ExecutionInfoV2};
use fp_rpc::{EthereumRuntimeRPCApi, RuntimeStorageOverride};
use fp_storage::{EVM_ACCOUNT_CODES, PALLET_EVM};

Expand Down Expand Up @@ -210,7 +210,7 @@ where

error_on_execution_failure(&info.exit_reason, &info.value)?;
Ok(Bytes(info.value))
} else if api_version == 4 {
} else if api_version == 4 || api_version == 5 {
// Post-london + access list support
let encoded_params = Encode::encode(&(
&from.unwrap_or_default(),
Expand Down Expand Up @@ -247,23 +247,47 @@ where
recorder: &None,
};

let info = self
.client
.call_api_at(params)
.and_then(|r| {
Result::map_err(
<Result<CallInfo, DispatchError> as Decode>::decode(&mut &r[..]),
|error| sp_api::ApiError::FailedToDecodeReturnValue {
function: "EthereumRuntimeRPCApi_call",
error,
},
)
})
.map_err(|err| internal_err(format!("runtime error: {:?}", err)))?
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?;
let value = if api_version == 4 {
let info = self
.client
.call_api_at(params)
.and_then(|r| {
Result::map_err(
<Result<ExecutionInfo::<Vec<u8>>, DispatchError> as Decode>::decode(&mut &r[..]),
|error| sp_api::ApiError::FailedToDecodeReturnValue {
function: "EthereumRuntimeRPCApi_call",
error,
},
)
})
.map_err(|err| internal_err(format!("runtime error: {:?}", err)))?
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?;

error_on_execution_failure(&info.exit_reason, &info.value)?;
Ok(Bytes(info.value))
error_on_execution_failure(&info.exit_reason, &info.value)?;
info.value
} else if api_version == 5 {
let info = self
.client
.call_api_at(params)
.and_then(|r| {
Result::map_err(
<Result<ExecutionInfoV2::<Vec<u8>>, DispatchError> as Decode>::decode(&mut &r[..]),
|error| sp_api::ApiError::FailedToDecodeReturnValue {
function: "EthereumRuntimeRPCApi_call",
error,
},
)
})
.map_err(|err| internal_err(format!("runtime error: {:?}", err)))?
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?;

error_on_execution_failure(&info.exit_reason, &info.value)?;
info.value
} else {
unreachable!("invalid version");
};

Ok(Bytes(value))
} else {
Err(internal_err("failed to retrieve Runtime Api version"))
}
Expand Down Expand Up @@ -315,6 +339,36 @@ where
.map_err(|err| internal_err(format!("runtime error: {:?}", err)))?;
Ok(Bytes(code))
} else if api_version == 4 {
// Post-london + access list support
let access_list = access_list.unwrap_or_default();
#[allow(deprecated)]
let info = api.create_before_version_5(
substrate_hash,
from.unwrap_or_default(),
data,
value.unwrap_or_default(),
gas_limit,
max_fee_per_gas,
max_priority_fee_per_gas,
nonce,
false,
Some(
access_list
.into_iter()
.map(|item| (item.address, item.storage_keys))
.collect(),
),
)
.map_err(|err| internal_err(format!("runtime error: {:?}", err)))?
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?;

error_on_execution_failure(&info.exit_reason, &[])?;

let code = api
.account_code_at(substrate_hash, info.value)
.map_err(|err| internal_err(format!("runtime error: {:?}", err)))?;
Ok(Bytes(code))
} else if api_version == 5 {
// Post-london + access list support
let access_list = access_list.unwrap_or_default();
let info = api
Expand Down Expand Up @@ -515,10 +569,10 @@ where

let (exit_reason, data, used_gas) = match to {
Some(to) => {
let info = if api_version == 1 {
if api_version == 1 {
// Legacy pre-london
#[allow(deprecated)]
api.call_before_version_2(
let info = api.call_before_version_2(
substrate_hash,
from.unwrap_or_default(),
to,
Expand All @@ -530,11 +584,33 @@ where
estimate_mode,
)
.map_err(|err| internal_err(format!("runtime error: {:?}", err)))?
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?;

(info.exit_reason, info.value, info.used_gas)
} else if api_version < 4 {
// Post-london
#[allow(deprecated)]
api.call_before_version_4(
let info = api.call_before_version_4(
substrate_hash,
from.unwrap_or_default(),
to,
data,
value.unwrap_or_default(),
gas_limit,
max_fee_per_gas,
max_priority_fee_per_gas,
nonce,
estimate_mode,
)
.map_err(|err| internal_err(format!("runtime error: {:?}", err)))?
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?;

(info.exit_reason, info.value, info.used_gas)
} else if api_version == 4 {
// Post-london + access list support
let access_list = access_list.unwrap_or_default();
#[allow(deprecated)]
let info = api.call_before_version_5(
substrate_hash,
from.unwrap_or_default(),
to,
Expand All @@ -545,13 +621,21 @@ where
max_priority_fee_per_gas,
nonce,
estimate_mode,
Some(
access_list
.into_iter()
.map(|item| (item.address, item.storage_keys))
.collect(),
),
)
.map_err(|err| internal_err(format!("runtime error: {:?}", err)))?
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?;

(info.exit_reason, info.value, info.used_gas)
} else {
// Post-london + access list support
let access_list = access_list.unwrap_or_default();
api.call(
let info = api.call(
substrate_hash,
from.unwrap_or_default(),
to,
Expand All @@ -570,16 +654,16 @@ where
),
)
.map_err(|err| internal_err(format!("runtime error: {:?}", err)))?
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?
};
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?;

(info.exit_reason, info.value, info.used_gas)
(info.exit_reason, info.value, info.used_gas.effective)
}
}
None => {
let info = if api_version == 1 {
if api_version == 1 {
// Legacy pre-london
#[allow(deprecated)]
api.create_before_version_2(
let info = api.create_before_version_2(
substrate_hash,
from.unwrap_or_default(),
data,
Expand All @@ -590,11 +674,13 @@ where
estimate_mode,
)
.map_err(|err| internal_err(format!("runtime error: {:?}", err)))?
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?;

(info.exit_reason, Vec::new(), info.used_gas)
} else if api_version < 4 {
// Post-london
#[allow(deprecated)]
api.create_before_version_4(
let info = api.create_before_version_4(
substrate_hash,
from.unwrap_or_default(),
data,
Expand All @@ -606,11 +692,38 @@ where
estimate_mode,
)
.map_err(|err| internal_err(format!("runtime error: {:?}", err)))?
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?;

(info.exit_reason, Vec::new(), info.used_gas)
} else if api_version == 4 {
// Post-london + access list support
let access_list = access_list.unwrap_or_default();
#[allow(deprecated)]
let info = api.create_before_version_5(
substrate_hash,
from.unwrap_or_default(),
data,
value.unwrap_or_default(),
gas_limit,
max_fee_per_gas,
max_priority_fee_per_gas,
nonce,
estimate_mode,
Some(
access_list
.into_iter()
.map(|item| (item.address, item.storage_keys))
.collect(),
),
)
.map_err(|err| internal_err(format!("runtime error: {:?}", err)))?
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?;

(info.exit_reason, Vec::new(), info.used_gas)
} else {
// Post-london + access list support
let access_list = access_list.unwrap_or_default();
api.create(
let info = api.create(
substrate_hash,
from.unwrap_or_default(),
data,
Expand All @@ -628,10 +741,10 @@ where
),
)
.map_err(|err| internal_err(format!("runtime error: {:?}", err)))?
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?
};
.map_err(|err| internal_err(format!("execution fatal: {:?}", err)))?;

(info.exit_reason, Vec::new(), info.used_gas)
(info.exit_reason, Vec::new(), info.used_gas.effective)
}
}
};
Ok(ExecutableResult {
Expand Down
Loading

0 comments on commit 0c1680b

Please sign in to comment.