Skip to content

Cancun support #205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
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
8 changes: 4 additions & 4 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 @@ -52,7 +52,7 @@ derive_more = "0.99"
environmental = { version = "1.1.4", default-features = false }
ethereum = { version = "0.15.0", default-features = false }
ethereum-types = { version = "0.14.1", default-features = false }
evm = { git = "https://github.com/moonbeam-foundation/evm", branch = "moonbeam-polkadot-v1.7.2", default-features = false }
evm = { git = "https://github.com/moonbeam-foundation/evm", branch = "v0.4.1-eip1153", default-features = false }
futures = "0.3.30"
hash-db = { version = "0.16.0", default-features = false }
hex = { version = "0.4.3", default-features = false, features = ["alloc"] }
Expand Down
4 changes: 2 additions & 2 deletions frame/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ pub mod pallet {

/// EVM config used in the module.
fn config() -> &'static EvmConfig {
&SHANGHAI_CONFIG
&CANCUN_CONFIG
}
}

Expand Down Expand Up @@ -792,7 +792,7 @@ impl<T: Config> GasWeightMapping for FixedGasWeightMapping<T> {
}
}

static SHANGHAI_CONFIG: EvmConfig = EvmConfig::shanghai();
static CANCUN_CONFIG: EvmConfig = EvmConfig::cancun();

impl<T: Config> Pallet<T> {
/// Check whether an account is empty.
Expand Down
13 changes: 13 additions & 0 deletions frame/evm/src/runner/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,7 @@ pub struct SubstrateStackState<'vicinity, 'config, T> {
vicinity: &'vicinity Vicinity,
substate: SubstrateStackSubstate<'config>,
original_storage: BTreeMap<(H160, H256), H256>,
transient_storage: BTreeMap<(H160, H256), H256>,
recorded: Recorded,
weight_info: Option<WeightInfo>,
storage_meter: Option<StorageMeter>,
Expand All @@ -750,6 +751,7 @@ impl<'vicinity, 'config, T: Config> SubstrateStackState<'vicinity, 'config, T> {
},
_marker: PhantomData,
original_storage: BTreeMap::new(),
transient_storage: BTreeMap::new(),
recorded: Default::default(),
weight_info,
storage_meter,
Expand Down Expand Up @@ -844,6 +846,13 @@ where
<AccountStorages<T>>::get(address, index)
}

fn transient_storage(&self, address: H160, index: H256) -> H256 {
self.transient_storage
.get(&(address, index))
.copied()
.unwrap_or_default()
}

fn original_storage(&self, address: H160, index: H256) -> Option<H256> {
Some(
self.original_storage
Expand Down Expand Up @@ -930,6 +939,10 @@ where
}
}

fn set_transient_storage(&mut self, address: H160, key: H256, value: H256) {
self.transient_storage.insert((address, key), value);
}

fn reset_storage(&mut self, address: H160) {
#[allow(deprecated)]
let _ = <AccountStorages<T>>::remove_prefix(address, None);
Expand Down
2 changes: 1 addition & 1 deletion precompiles/src/testing/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ impl PrecompileHandle for MockHandle {
if self
.record_cost(crate::evm::costs::call_cost(
context.apparent_value,
&evm::Config::london(),
&evm::Config::cancun(),
))
.is_err()
{
Expand Down
4 changes: 2 additions & 2 deletions primitives/evm/src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ mod tests {
UnknownError,
}

static SHANGHAI_CONFIG: evm::Config = evm::Config::shanghai();
static CANCUN_CONFIG: evm::Config = evm::Config::cancun();

impl From<TransactionValidationError> for TestError {
fn from(e: TransactionValidationError) -> Self {
Expand Down Expand Up @@ -345,7 +345,7 @@ mod tests {
} = input;
CheckEvmTransaction::<TestError>::new(
CheckEvmTransactionConfig {
evm_config: &SHANGHAI_CONFIG,
evm_config: &CANCUN_CONFIG,
block_gas_limit: blockchain_gas_limit,
base_fee: blockchain_base_fee,
chain_id: blockchain_chain_id,
Expand Down
57 changes: 57 additions & 0 deletions ts-tests/contracts/eip1153.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract ReentrancyProtected {
// A constant key for the reentrancy guard stored in Transient Storage.
// This acts as a unique identifier for the reentrancy lock.
bytes32 constant REENTRANCY_GUARD = keccak256("REENTRANCY_GUARD");

// Modifier to prevent reentrant calls.
// It checks if the reentrancy guard is set (indicating an ongoing execution)
// and sets the guard before proceeding with the function execution.
// After the function executes, it resets the guard to allow future calls.
modifier nonReentrant() {
// Ensure the guard is not set (i.e., no ongoing execution).
require(tload(REENTRANCY_GUARD) == 0, "Reentrant call detected.");

// Set the guard to block reentrant calls.
tstore(REENTRANCY_GUARD, 1);

_; // Execute the function body.

// Reset the guard after execution to allow future calls.
tstore(REENTRANCY_GUARD, 0);
}

// Uses inline assembly to access the Transient Storage's tstore operation.
function tstore(bytes32 location, uint value) private {
assembly {
tstore(location, value)
}
}

// Uses inline assembly to access the Transient Storage's tload operation.
// Returns the value stored at the given location.
function tload(bytes32 location) private returns (uint value) {
assembly {
value := tload(location)
}
}

function nonReentrantMethod() public nonReentrant() {
(bool success, bytes memory result) = msg.sender.call("");
if (!success) {
assembly {
revert(add(32, result), mload(result))
}
}
}

function test() external {
this.nonReentrantMethod();
}

receive() external payable {
this.nonReentrantMethod();
}
}
54 changes: 54 additions & 0 deletions ts-tests/tests/test-eip1153.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { expect, use as chaiUse } from "chai";
import chaiAsPromised from "chai-as-promised";
import { AbiItem } from "web3-utils";

import ReentrancyProtected from "../build/contracts/ReentrancyProtected.json";
import { GENESIS_ACCOUNT, GENESIS_ACCOUNT_PRIVATE_KEY } from "./config";
import { createAndFinalizeBlock, customRequest, describeWithFrontier } from "./util";

chaiUse(chaiAsPromised);

describeWithFrontier("Frontier RPC (EIP-1153)", (context) => {
const TEST_CONTRACT_BYTECODE = ReentrancyProtected.bytecode;
const TEST_CONTRACT_ABI = ReentrancyProtected.abi as AbiItem[];
let contract_address: string = null;

// Those test are ordered. In general this should be avoided, but due to the time it takes
// to spin up a frontier node, it saves a lot of time.

before("create the contract", async function () {
this.timeout(15000);
const tx = await context.web3.eth.accounts.signTransaction(
{
from: GENESIS_ACCOUNT,
data: TEST_CONTRACT_BYTECODE,
value: "0x00",
gasPrice: "0x3B9ACA00",
gas: "0x100000",
},
GENESIS_ACCOUNT_PRIVATE_KEY
);
await customRequest(context.web3, "eth_sendRawTransaction", [tx.rawTransaction]);
await createAndFinalizeBlock(context.web3);

const receipt = await context.web3.eth.getTransactionReceipt(tx.transactionHash);
contract_address = receipt.contractAddress;
});

it("should detect reentrant call and revert", async function () {
const contract = new context.web3.eth.Contract(TEST_CONTRACT_ABI, contract_address, {
from: GENESIS_ACCOUNT,
gasPrice: "0x3B9ACA00"
});

try {
await contract.methods.test().call();
} catch (error) {
return expect(error.message).to.be.eq(
"Returned error: VM Exception while processing transaction: revert Reentrant call detected."
);
}

expect.fail("Expected the contract call to fail");
});
});
2 changes: 1 addition & 1 deletion ts-tests/truffle-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ module.exports = {
// Configure your compilers
compilers: {
solc: {
version: "0.8.2", // Fetch exact version from solc-bin (default: truffle's version)
version: "0.8.25", // Fetch exact version from solc-bin (default: truffle's version)
docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
// settings: { // See the solidity docs for advice about optimization and evmVersion
// optimizer: {
Expand Down