Skip to content

Commit

Permalink
Record witness access in EXTCODEHASH (#370)
Browse files Browse the repository at this point in the history
* instructions: add access witness recording for EXTCODEHASH

* add test for EXTCODEHASH witness recording

* add test for access witness EXTCODEHASH

Signed-off-by: Ignacio Hagopian <[email protected]>

* do not touch version

Signed-off-by: Ignacio Hagopian <[email protected]>

---------

Signed-off-by: Ignacio Hagopian <[email protected]>
  • Loading branch information
jsign authored and gballet committed May 8, 2024
1 parent ead2dfb commit a9d9098
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 0 deletions.
133 changes: 133 additions & 0 deletions core/state_processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie/utils"

//"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
Expand Down Expand Up @@ -794,3 +795,135 @@ func TestProcessVerkleContractWithEmptyCode(t *testing.T) {
}
}
}

func TestProcessVerklExtCodeHashOpcode(t *testing.T) {
var (
config = &params.ChainConfig{
ChainID: big.NewInt(69421),
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
Ethash: new(params.EthashConfig),
ShanghaiTime: u64(0),
PragueTime: u64(0),
TerminalTotalDifficulty: common.Big0,
TerminalTotalDifficultyPassed: true,
ProofInBlocks: true,
}
signer = types.LatestSigner(config)
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
bcdb = rawdb.NewMemoryDatabase() // Database for the blockchain
gendb = rawdb.NewMemoryDatabase() // Database for the block-generation code, they must be separate as they are path-based.
coinbase = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7")
account1 = common.HexToAddress("0x687704DB07e902e9A8B3754031D168D46E3D586e")
account2 = common.HexToAddress("0x6177843db3138ae69679A54b95cf345ED759450d")
gspec = &Genesis{
Config: config,
Alloc: GenesisAlloc{
coinbase: GenesisAccount{
Balance: big.NewInt(1000000000000000000), // 1 ether
Nonce: 0,
},
account1: GenesisAccount{
Balance: big.NewInt(1000000000000000000), // 1 ether
Nonce: 0,
},
account2: GenesisAccount{
Balance: big.NewInt(1000000000000000000), // 1 ether
Nonce: 3,
},
},
}
)
// Verkle trees use the snapshot, which must be enabled before the
// data is saved into the tree+database.
genesis := gspec.MustCommit(bcdb)

// Commit the genesis block to the block-generation database as it
// is now independent of the blockchain database.
gspec.MustCommit(gendb)

dummyContract := []byte{
0x60, 2, // PUSH1 2
0x60, 12, // PUSH1 12
0x60, 0x00, // PUSH1 0
0x39, // CODECOPY

0x60, 2, // PUSH1 2
0x60, 0x00, // PUSH1 0
0xF3, // RETURN

// Contract that auto-calls EXTCODEHASH
0x60, 42, // PUSH1 42
}
dummyContractAddr := common.HexToAddress("3a220f351252089d385b29beca14e27f204c296a")
extCodeHashContract := []byte{
0x60, 22, // PUSH1 22
0x60, 12, // PUSH1 12
0x60, 0x00, // PUSH1 0
0x39, // CODECOPY

0x60, 22, // PUSH1 22
0x60, 0x00, // PUSH1 0
0xF3, // RETURN

// Contract that auto-calls EXTCODEHASH
0x73, // PUSH20
0x3a, 0x22, 0x0f, 0x35, 0x12, 0x52, 0x08, 0x9d, 0x38, 0x5b, 0x29, 0xbe, 0xca, 0x14, 0xe2, 0x7f, 0x20, 0x4c, 0x29, 0x6a,
0x3F, // EXTCODEHASH
}
extCodeHashContractAddr := common.HexToAddress("db7d6ab1f17c6b31909ae466702703daef9269cf")
_, _, _, statediff := GenerateVerkleChain(gspec.Config, genesis, beacon.New(ethash.NewFaker()), gendb, 2, func(i int, gen *BlockGen) {
gen.SetPoS()

if i == 0 {
// Create dummy contract.
tx, _ := types.SignTx(types.NewContractCreation(0, big.NewInt(0), 100_000, big.NewInt(875000000), dummyContract), signer, testKey)
gen.AddTx(tx)

// Create contract with EXTCODEHASH opcode.
tx, _ = types.SignTx(types.NewContractCreation(1, big.NewInt(0), 100_000, big.NewInt(875000000), extCodeHashContract), signer, testKey)
gen.AddTx(tx)
} else {
tx, _ := types.SignTx(types.NewTransaction(2, extCodeHashContractAddr, big.NewInt(0), 100_000, big.NewInt(875000000), nil), signer, testKey)
gen.AddTx(tx)
}

})

contractKeccakTreeKey := utils.GetTreeKeyCodeKeccak(dummyContractAddr[:])

var stateDiffIdx = -1
for i, stemStateDiff := range statediff[1] {
if bytes.Equal(stemStateDiff.Stem[:], contractKeccakTreeKey[:31]) {
stateDiffIdx = i
break
}
}
if stateDiffIdx == -1 {
t.Fatalf("no state diff found for stem")
}

codeHashStateDiff := statediff[1][stateDiffIdx].SuffixDiffs[0]
if codeHashStateDiff.Suffix != utils.CodeKeccakLeafKey {
t.Fatalf("code hash invalid suffix")
}
if codeHashStateDiff.CurrentValue == nil {
t.Fatalf("codeHash.CurrentValue must not be empty")
}
expCodeHash := crypto.Keccak256Hash(dummyContract[12:])
if *codeHashStateDiff.CurrentValue != expCodeHash {
t.Fatalf("codeHash.CurrentValue unexpected code hash")
}
if codeHashStateDiff.NewValue != nil {
t.Fatalf("codeHash.NewValue must be nil")
}
}
7 changes: 7 additions & 0 deletions core/vm/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,13 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
slot := scope.Stack.peek()
address := common.Address(slot.Bytes20())
if interpreter.evm.chainRules.IsPrague {
statelessGas := interpreter.evm.Accesses.TouchAddressOnReadAndComputeGas(slot.Bytes(), uint256.Int{}, trieUtils.CodeKeccakLeafKey)
if !scope.Contract.UseGas(statelessGas) {
scope.Contract.Gas = 0
return nil, ErrOutOfGas
}
}
if interpreter.evm.StateDB.Empty(address) {
slot.Clear()
} else {
Expand Down

0 comments on commit a9d9098

Please sign in to comment.