Skip to content
Merged
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
27 changes: 27 additions & 0 deletions contracts/cancun_opcodes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package contracts

import (
_ "embed"

contractutils "github.com/cosmos/evm/contracts/utils"
evmtypes "github.com/cosmos/evm/x/vm/types"
)

var (
// CancunOpcodesJSON are the compiled bytes of the CancunOpcodesContract
//
//go:embed solidity/CancunOpcodes.json
CancunOpcodesJSON []byte

// CancunOpcodesContract is the compiled cancun opcodes contract
CancunOpcodesContract evmtypes.CompiledContract
)

func init() {
var err error
if CancunOpcodesContract, err = contractutils.ConvertHardhatBytesToCompiledContract(
CancunOpcodesJSON,
); err != nil {
panic(err)
}
}
5 changes: 4 additions & 1 deletion contracts/hardhat.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ module.exports = {
solidity: {
compilers: [
{
version: "0.8.20",
version: "0.8.25",
settings: {
evmVersion: "cancun",
}
},
// This version is required to compile the werc9 contract.
{
Expand Down
81 changes: 81 additions & 0 deletions contracts/solidity/CancunOpcodes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "CancunOpcodes",
"sourceName": "solidity/CancunOpcodes.sol",
"abi": [
{
"inputs": [],
"name": "testBlobBaseFee",
"outputs": [
{
"internalType": "uint256",
"name": "fee",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "testBlobHash",
"outputs": [
{
"internalType": "bytes32",
"name": "hash",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint8",
"name": "value",
"type": "uint8"
}
],
"name": "testSimpleMCopy",
"outputs": [
{
"internalType": "bytes32",
"name": "copied",
"type": "bytes32"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "testTstoreTload",
"outputs": [
{
"internalType": "uint256",
"name": "loadedValue",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x6080604052348015600e575f80fd5b506102918061001c5f395ff3fe608060405234801561000f575f80fd5b506004361061004a575f3560e01c806307f641e71461004e578063109a972b1461007e5780636a037df3146100ae578063f48357f1146100de575b5f80fd5b61006860048036038101906100639190610176565b6100fc565b60405161007591906101b9565b60405180910390f35b61009860048036038101906100939190610208565b610106565b6040516100a591906101b9565b60405180910390f35b6100c860048036038101906100c39190610176565b610129565b6040516100d59190610242565b60405180910390f35b6100e6610138565b6040516100f39190610242565b60405180910390f35b5f81499050919050565b5f60405182815360408101604052602081602083015e6020810151915050919050565b5f8160425d60425c9050919050565b5f4a905090565b5f80fd5b5f819050919050565b61015581610143565b811461015f575f80fd5b50565b5f813590506101708161014c565b92915050565b5f6020828403121561018b5761018a61013f565b5b5f61019884828501610162565b91505092915050565b5f819050919050565b6101b3816101a1565b82525050565b5f6020820190506101cc5f8301846101aa565b92915050565b5f60ff82169050919050565b6101e7816101d2565b81146101f1575f80fd5b50565b5f81359050610202816101de565b92915050565b5f6020828403121561021d5761021c61013f565b5b5f61022a848285016101f4565b91505092915050565b61023c81610143565b82525050565b5f6020820190506102555f830184610233565b9291505056fea2646970667358221220557c6520cf75983003b61b499d2c575700eeca53ee5de7ae1760ea2a9795b39964736f6c63430008190033",
"deployedBytecode": "0x608060405234801561000f575f80fd5b506004361061004a575f3560e01c806307f641e71461004e578063109a972b1461007e5780636a037df3146100ae578063f48357f1146100de575b5f80fd5b61006860048036038101906100639190610176565b6100fc565b60405161007591906101b9565b60405180910390f35b61009860048036038101906100939190610208565b610106565b6040516100a591906101b9565b60405180910390f35b6100c860048036038101906100c39190610176565b610129565b6040516100d59190610242565b60405180910390f35b6100e6610138565b6040516100f39190610242565b60405180910390f35b5f81499050919050565b5f60405182815360408101604052602081602083015e6020810151915050919050565b5f8160425d60425c9050919050565b5f4a905090565b5f80fd5b5f819050919050565b61015581610143565b811461015f575f80fd5b50565b5f813590506101708161014c565b92915050565b5f6020828403121561018b5761018a61013f565b5b5f61019884828501610162565b91505092915050565b5f819050919050565b6101b3816101a1565b82525050565b5f6020820190506101cc5f8301846101aa565b92915050565b5f60ff82169050919050565b6101e7816101d2565b81146101f1575f80fd5b50565b5f81359050610202816101de565b92915050565b5f6020828403121561021d5761021c61013f565b5b5f61022a848285016101f4565b91505092915050565b61023c81610143565b82525050565b5f6020820190506102555f830184610233565b9291505056fea2646970667358221220557c6520cf75983003b61b499d2c575700eeca53ee5de7ae1760ea2a9795b39964736f6c63430008190033",
"linkReferences": {},
"deployedLinkReferences": {}
}
45 changes: 45 additions & 0 deletions contracts/solidity/CancunOpcodes.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: LGPL-3.0-only

pragma solidity ^0.8.25;

contract CancunOpcodes {
/// @notice TSTORE + TLOAD using fixed slot (0x42)
/// @param value The value to store in transient storage
/// @return loadedValue Value loaded from transient slot 0x42
function testTstoreTload(uint256 value) external returns (uint256 loadedValue) {
assembly {
tstore(0x42, value)
loadedValue := tload(0x42)
}
}

/// @notice Store 1-byte value in memory, copy it via MCOPY, then load and return
/// @param value The 1-byte value to test
/// @return copied 32-byte memory word after MCOPY
function testSimpleMCopy(uint8 value) external pure returns (bytes32 copied) {
assembly {
let dst := mload(0x40)
mstore8(dst, value) // Store exactly 1 byte at dst position
mstore(0x40, add(dst, 0x40))
mcopy(add(dst, 0x20), dst, 0x20) // Use 32 byte offset to read 32 bytes after mcopy
copied := mload(add(dst, 0x20))
}
}

/// @notice Returns the current blob base fee
/// @return fee Blob base fee (expected 0 on most networks)
function testBlobBaseFee() external view returns (uint256 fee) {
assembly {
fee := blobbasefee()
}
}

/// @notice Returns the blob hash for a given index
/// @param index Blob index to query
/// @return hash 32-byte blob commitment hash
function testBlobHash(uint256 index) external view returns (bytes32 hash) {
assembly {
hash := blobhash(index)
}
}
}
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -257,15 +257,14 @@ replace (
cosmossdk.io/store => github.com/b-harvest/cosmos-sdk/store v0.0.0-20250324051345-ddad0e6f75cb
github.com/cometbft/cometbft => github.com/b-harvest/cometbft v0.0.0-20250324035653-78e589510249
github.com/cosmos/cosmos-sdk => github.com/b-harvest/cosmos-sdk v0.0.0-20250324051359-31fe6618dc61
github.com/ethereum/go-ethereum => github.com/b-harvest/go-ethereum v0.0.0-20250416151150-60099d9e9cdd
)

replace (
// need this replace when importing cosmos/rosetta pkg
cosmossdk.io/core => cosmossdk.io/core v0.11.0
// use cosmos fork of keyring
github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0
// use Evmos geth fork
github.com/ethereum/go-ethereum => github.com/evmos/go-ethereum v1.10.26-evmos-rc4
// Security Advisory https://github.com/advisories/GHSA-h395-qcrw-5vmq
github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.9.1
// replace broken goleveldb
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,8 @@ github.com/b-harvest/cosmos-sdk v0.0.0-20250324051359-31fe6618dc61 h1:vxFQZq9hto
github.com/b-harvest/cosmos-sdk v0.0.0-20250324051359-31fe6618dc61/go.mod h1:dWbaOXueH9KzRlHBkluKFp9t0tZwahej3mT1wj8vQq4=
github.com/b-harvest/cosmos-sdk/store v0.0.0-20250324051345-ddad0e6f75cb h1:E5IaRS16dPYT/rwdm/k+5Ytq8t3rTVOAR7yrFPpv7VU=
github.com/b-harvest/cosmos-sdk/store v0.0.0-20250324051345-ddad0e6f75cb/go.mod h1:8DwVTz83/2PSI366FERGbWSH7hL6sB7HbYp8bqksNwM=
github.com/b-harvest/go-ethereum v0.0.0-20250416151150-60099d9e9cdd h1:NUeDjcZ6EhFuxBvn8BDcn2l7BB6e37dfaMievdszE/M=
github.com/b-harvest/go-ethereum v0.0.0-20250416151150-60099d9e9cdd/go.mod h1:/6CsT5Ceen2WPLI/oCA3xMcZ5sWMF/D46SjM/ayY0Oo=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
Expand Down Expand Up @@ -484,8 +486,6 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evmos/go-ethereum v1.10.26-evmos-rc4 h1:vwDVMScuB2KSu8ze5oWUuxm6v3bMUp6dL3PWvJNJY+I=
github.com/evmos/go-ethereum v1.10.26-evmos-rc4/go.mod h1:/6CsT5Ceen2WPLI/oCA3xMcZ5sWMF/D46SjM/ayY0Oo=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
Expand Down
105 changes: 105 additions & 0 deletions x/vm/core/vm/eips.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"strconv"
"strings"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
)
Expand All @@ -34,6 +35,12 @@ var activators = map[string]func(*JumpTable){
"ethereum_2200": enable2200,
"ethereum_1884": enable1884,
"ethereum_1344": enable1344,

// v1.13.14
"ethereum_1153": enable1153,
"ethereum_5656": enable5656,
"ethereum_4844": enable4844,
"ethereum_7516": enable7516,
}

// EnableEIP enables the given EIP on the config.
Expand Down Expand Up @@ -215,3 +222,101 @@ func opPush0(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
scope.Stack.Push(new(uint256.Int))
return nil, nil
}

// enable1153 applies EIP-1153 "Transient Storage"
// - Adds TLOAD that reads from transient storage
// - Adds TSTORE that writes to transient storage
func enable1153(jt *JumpTable) {
jt[TLOAD] = &operation{
execute: opTload,
constantGas: params.WarmStorageReadCostEIP2929,
minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
}

jt[TSTORE] = &operation{
execute: opTstore,
constantGas: params.WarmStorageReadCostEIP2929,
minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
}
}

// opTload implements TLOAD opcode
func opTload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
loc := scope.Stack.Peek()
hash := common.Hash(loc.Bytes32())
val := interpreter.evm.StateDB.GetTransientState(scope.Contract.Address(), hash)
loc.SetBytes(val.Bytes())
return nil, nil
}

// opTstore implements TSTORE opcode
func opTstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly {
return nil, ErrWriteProtection
}
loc := scope.Stack.Pop()
val := scope.Stack.Pop()
interpreter.evm.StateDB.SetTransientState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32())
return nil, nil
}

// enable5656 enables EIP-5656 (MCOPY opcode)
// https://eips.ethereum.org/EIPS/eip-5656
func enable5656(jt *JumpTable) {
jt[MCOPY] = &operation{
execute: opMcopy,
constantGas: GasFastestStep,
dynamicGas: gasMcopy,
minStack: minStack(3, 0),
maxStack: maxStack(3, 0),
memorySize: memoryMcopy,
}
}

// opMcopy implements the MCOPY opcode (https://eips.ethereum.org/EIPS/eip-5656)
func opMcopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
var (
dst = scope.Stack.Pop()
src = scope.Stack.Pop()
length = scope.Stack.Pop()
)
// These values are checked for overflow during memory expansion calculation
// (the memorySize function on the opcode).
scope.Memory.Copy(dst.Uint64(), src.Uint64(), length.Uint64())
return nil, nil
}

// enable4844 applies EIP-4844 (BLOBHASH opcode)
func enable4844(jt *JumpTable) {
jt[BLOBHASH] = &operation{
execute: opBlobHash,
constantGas: GasFastestStep,
minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
}
}

// opBlobHash implements the BLOBHASH opcode
func opBlobHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
index := scope.Stack.Peek()
index.Clear()
return nil, nil
}

// enable7516 applies EIP-7516 (BLOBBASEFEE opcode)
func enable7516(jt *JumpTable) {
jt[BLOBBASEFEE] = &operation{
execute: opBlobBaseFee,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
}
}

// opBlobBaseFee implements BLOBBASEFEE opcode
func opBlobBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.Push(uint256.NewInt(0))
return nil, nil
}
2 changes: 2 additions & 0 deletions x/vm/core/vm/gas_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
// as argument:
// CALLDATACOPY (stack position 2)
// CODECOPY (stack position 2)
// MCOPY (stack position 2)
// EXTCODECOPY (stack position 3)
// RETURNDATACOPY (stack position 2)
func memoryCopierGas(stackpos int) gasFunc {
Expand Down Expand Up @@ -89,6 +90,7 @@ func memoryCopierGas(stackpos int) gasFunc {
var (
gasCallDataCopy = memoryCopierGas(2)
gasCodeCopy = memoryCopierGas(2)
gasMcopy = memoryCopierGas(2)
gasExtCodeCopy = memoryCopierGas(3)
gasReturnDataCopy = memoryCopierGas(2)
)
Expand Down
3 changes: 3 additions & 0 deletions x/vm/core/vm/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ type StateDB interface {
GetState(common.Address, common.Hash) common.Hash
SetState(common.Address, common.Hash, common.Hash)

GetTransientState(addr common.Address, key common.Hash) common.Hash
SetTransientState(addr common.Address, key, value common.Hash)

Suicide(common.Address) bool
HasSuicided(common.Address) bool

Expand Down
11 changes: 11 additions & 0 deletions x/vm/core/vm/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,14 @@ func (m *Memory) Data() []byte {
func (m *Memory) GasCost(newMemSize uint64) (uint64, error) {
return memoryGasCost(m, newMemSize)
}

// Copy copies data from the src position slice into the dst position.
// The source and destination may overlap.
// OBS: This operation assumes that any necessary memory expansion has already been performed,
// and this method may panic otherwise.
func (m *Memory) Copy(dst, src, len uint64) {
if len == 0 {
return
}
copy(m.store[dst:], m.store[src:src+len])
}
8 changes: 8 additions & 0 deletions x/vm/core/vm/memory_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ func memoryMStore(stack *Stack) (uint64, bool) {
return calcMemSize64WithUint(stack.Back(0), 32)
}

func memoryMcopy(stack *Stack) (uint64, bool) {
mStart := stack.Back(0) // stack[0]: dest
if stack.Back(1).Gt(mStart) {
mStart = stack.Back(1) // stack[1]: source
}
return calcMemSize64(mStart, stack.Back(2)) // stack[2]: length
}

func memoryCreate(stack *Stack) (uint64, bool) {
return calcMemSize64(stack.Back(1), stack.Back(2))
}
Expand Down
Loading
Loading