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

fix for unit tests: do not call NewAccessWitness in NewEVMTxContext #49

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
12 changes: 8 additions & 4 deletions consensus/ethash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -661,14 +661,18 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header
r.Sub(r, header.Number)
r.Mul(r, blockReward)
r.Div(r, big8)
uncleCoinbase := utils.GetTreeKeyBalance(uncle.Coinbase.Bytes())
state.Witness().TouchAddress(uncleCoinbase, state.GetBalance(uncle.Coinbase).Bytes())
if state.Witness() != nil {
uncleCoinbase := utils.GetTreeKeyBalance(uncle.Coinbase.Bytes())
state.Witness().TouchAddress(uncleCoinbase, state.GetBalance(uncle.Coinbase).Bytes())
}
state.AddBalance(uncle.Coinbase, r)

r.Div(blockReward, big32)
reward.Add(reward, r)
}
coinbase := utils.GetTreeKeyBalance(header.Coinbase.Bytes())
state.Witness().TouchAddress(coinbase, state.GetBalance(header.Coinbase).Bytes())
if config.IsCancun(header.Number) {
coinbase := utils.GetTreeKeyBalance(header.Coinbase.Bytes())
state.Witness().TouchAddress(coinbase, state.GetBalance(header.Coinbase).Bytes())
}
state.AddBalance(header.Coinbase, reward)
}
1 change: 0 additions & 1 deletion core/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ func NewEVMTxContext(msg Message) vm.TxContext {
return vm.TxContext{
Origin: msg.From(),
GasPrice: new(big.Int).Set(msg.GasPrice()),
Accesses: types.NewAccessWitness(),
}
}

Expand Down
18 changes: 11 additions & 7 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,14 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
journal: newJournal(),
accessList: newAccessList(),
hasher: crypto.NewKeccakState(),
witness: types.NewAccessWitness(),
}
if sdb.snaps == nil && tr.IsVerkle() {
sdb.snaps, err = snapshot.New(db.TrieDB().DiskDB(), db.TrieDB(), 1, root, false, true, false, true)
if err != nil {
return nil, err
if tr.IsVerkle() {
sdb.witness = types.NewAccessWitness()
if sdb.snaps == nil {
sdb.snaps, err = snapshot.New(db.TrieDB().DiskDB(), db.TrieDB(), 1, root, false, true, false, true)
if err != nil {
return nil, err
}
}
}
if sdb.snaps != nil {
Expand Down Expand Up @@ -182,7 +184,7 @@ func (s *StateDB) StartPrefetcher(namespace string) {
s.prefetcher.close()
s.prefetcher = nil
}
if s.snap != nil {
if s.snap != nil && !s.trie.IsVerkle() {
s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace)
}
}
Expand Down Expand Up @@ -713,7 +715,9 @@ func (s *StateDB) Copy() *StateDB {
preimages: make(map[common.Hash][]byte, len(s.preimages)),
journal: newJournal(),
hasher: crypto.NewKeccakState(),
witness: s.witness.Copy(),
}
if s.witness != nil {
state.witness = s.witness.Copy()
}
// Copy the dirty states, logs, and preimages
for addr := range s.journal.dirties {
Expand Down
7 changes: 6 additions & 1 deletion core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
// Create a new context to be used in the EVM environment.
txContext := NewEVMTxContext(msg)
if config.IsCancun(blockNumber) {
txContext.Accesses = types.NewAccessWitness()
}
evm.Reset(txContext, statedb)

// Apply the transaction to the current state (included in the env).
Expand Down Expand Up @@ -128,7 +131,9 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
}

statedb.Witness().Merge(txContext.Accesses)
if txContext.Accesses != nil {
statedb.Witness().Merge(txContext.Accesses)
}

// Set the receipt logs and create the bloom filter.
receipt.Logs = statedb.GetLogs(tx.Hash(), blockHash)
Expand Down
22 changes: 12 additions & 10 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ type EVM struct {
// NewEVM returns a new EVM. The returned EVM is not thread safe and should
// only ever be used *once*.
func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM {
if txCtx.Accesses == nil {
if txCtx.Accesses == nil && chainConfig.IsCancun(blockCtx.BlockNumber) {
txCtx.Accesses = types.NewAccessWitness()
}
evm := &EVM{
Expand Down Expand Up @@ -232,16 +232,18 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
if len(code) == 0 {
ret, err = nil, nil // gas is unchanged
} else {
// Touch the account data
var data [32]byte
evm.Accesses.TouchAddress(utils.GetTreeKeyVersion(addr.Bytes()), data[:])
binary.BigEndian.PutUint64(data[:], evm.StateDB.GetNonce(addr))
evm.Accesses.TouchAddress(utils.GetTreeKeyNonce(addr[:]), data[:])
evm.Accesses.TouchAddress(utils.GetTreeKeyBalance(addr[:]), evm.StateDB.GetBalance(addr).Bytes())
binary.BigEndian.PutUint64(data[:], uint64(len(code)))
evm.Accesses.TouchAddress(utils.GetTreeKeyCodeSize(addr[:]), data[:])
evm.Accesses.TouchAddress(utils.GetTreeKeyCodeKeccak(addr[:]), evm.StateDB.GetCodeHash(addr).Bytes())
if evm.Accesses != nil {
// Touch the account data
var data [32]byte
evm.Accesses.TouchAddress(utils.GetTreeKeyVersion(addr.Bytes()), data[:])
binary.BigEndian.PutUint64(data[:], evm.StateDB.GetNonce(addr))
evm.Accesses.TouchAddress(utils.GetTreeKeyNonce(addr[:]), data[:])
evm.Accesses.TouchAddress(utils.GetTreeKeyBalance(addr[:]), evm.StateDB.GetBalance(addr).Bytes())
binary.BigEndian.PutUint64(data[:], uint64(len(code)))
evm.Accesses.TouchAddress(utils.GetTreeKeyCodeSize(addr[:]), data[:])
evm.Accesses.TouchAddress(utils.GetTreeKeyCodeKeccak(addr[:]), evm.StateDB.GetCodeHash(addr).Bytes())

}
addrCopy := addr
// If the account has no code, we can abort here
// The depth-check is already done, and precompiles handled above
Expand Down
105 changes: 53 additions & 52 deletions core/vm/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,12 +372,9 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
if overflow {
uint64CodeEnd = 0xffffffffffffffff
}
if interpreter.evm.accesses != nil {
copyCodeFromAccesses(scope.Contract.Address(), uint64CodeOffset, uint64CodeEnd, memOffset.Uint64(), interpreter, scope)
} else {
codeCopy := getData(scope.Contract.Code, uint64CodeOffset, length.Uint64())
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)

codeCopy := getData(scope.Contract.Code, uint64CodeOffset, length.Uint64())
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
if interpreter.evm.TxContext.Accesses != nil {
touchEachChunks(uint64CodeOffset, uint64CodeEnd, codeCopy, scope.Contract, interpreter.evm)
}

Expand Down Expand Up @@ -444,12 +441,10 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
uint64CodeEnd = 0xffffffffffffffff
}
addr := common.Address(a.Bytes20())
if interpreter.evm.accesses != nil {
copyCodeFromAccesses(addr, uint64CodeOffset, uint64CodeEnd, memOffset.Uint64(), interpreter, scope)
} else {
codeCopy := getData(interpreter.evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64())
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
codeCopy := getData(interpreter.evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64())
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)

if interpreter.evm.chainConfig.IsCancun(interpreter.evm.Context.BlockNumber) {
touchEachChunks(uint64CodeOffset, uint64CodeEnd, codeCopy, scope.Contract, interpreter.evm)
}

Expand Down Expand Up @@ -579,10 +574,12 @@ func opSload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
hash := common.Hash(loc.Bytes32())
val := interpreter.evm.StateDB.GetState(scope.Contract.Address(), hash)
loc.SetBytes(val.Bytes())
// Get the initial value as it might not be present

index := trieUtils.GetTreeKeyStorageSlot(scope.Contract.Address().Bytes(), loc)
interpreter.evm.TxContext.Accesses.TouchAddress(index, val.Bytes())
if interpreter.evm.TxContext.Accesses != nil {
// Get the initial value as it might not be present
index := trieUtils.GetTreeKeyStorageSlot(scope.Contract.Address().Bytes(), loc)
interpreter.evm.TxContext.Accesses.TouchAddress(index, val.Bytes())
}
return nil, nil
}

Expand Down Expand Up @@ -910,21 +907,23 @@ func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
// touch next chunk if PUSH1 is at the boundary. if so, *pc has
// advanced past this boundary.
if *pc%31 == 0 {
// touch push data by adding the last byte of the pushdata
var value [32]byte
chunk := *pc / 31
count := uint64(0)
// Look for the first code byte (i.e. no pushdata)
for ; count < 31 && !scope.Contract.IsCode(chunk*31+count); count++ {
if interpreter.evm.TxContext.Accesses != nil {
// touch push data by adding the last byte of the pushdata
var value [32]byte
chunk := *pc / 31
count := uint64(0)
// Look for the first code byte (i.e. no pushdata)
for ; count < 31 && !scope.Contract.IsCode(chunk*31+count); count++ {
}
value[0] = byte(count)
endMin := (chunk + 1) * 31
if endMin > uint64(len(scope.Contract.Code)) {
endMin = uint64(len(scope.Contract.Code))
}
copy(value[1:], scope.Contract.Code[chunk*31:endMin])
index := trieUtils.GetTreeKeyCodeChunk(scope.Contract.Address().Bytes(), uint256.NewInt(chunk))
interpreter.evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil)
}
value[0] = byte(count)
endMin := (chunk + 1) * 31
if endMin > uint64(len(scope.Contract.Code)) {
endMin = uint64(len(scope.Contract.Code))
}
copy(value[1:], scope.Contract.Code[chunk*31:endMin])
index := trieUtils.GetTreeKeyCodeChunk(scope.Contract.Address().Bytes(), uint256.NewInt(chunk))
interpreter.evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil)
}
} else {
scope.Stack.push(integer.Clear())
Expand All @@ -951,37 +950,39 @@ func makePush(size uint64, pushByteSize int) executionFunc {
scope.Stack.push(integer.SetBytes(common.RightPadBytes(
scope.Contract.Code[startMin:endMin], pushByteSize)))

// touch push data by adding the last byte of the pushdata
var value [32]byte
chunk := uint64(endMin-1) / 31
count := uint64(0)
// Look for the first code byte (i.e. no pushdata)
for ; count < 31 && !scope.Contract.IsCode(chunk*31+count); count++ {
}
value[0] = byte(count)
copy(value[1:], scope.Contract.Code[chunk*31:endMin])
index := trieUtils.GetTreeKeyCodeChunk(scope.Contract.Address().Bytes(), uint256.NewInt(chunk))
interpreter.evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil)

// in the case of PUSH32, the end data might be two chunks away,
// so also get the middle chunk. There is a boundary condition
// check (endMin > 2) in the case the code is a single PUSH32
// insctruction, whose immediate are just 0s.
if pushByteSize == 32 && endMin > 2 {
chunk = uint64(endMin-2) / 31
count = uint64(0)
if interpreter.evm.TxContext.Accesses != nil {
// touch push data by adding the last byte of the pushdata
var value [32]byte
chunk := uint64(endMin-1) / 31
count := uint64(0)
// Look for the first code byte (i.e. no pushdata)
for ; count < 31 && !scope.Contract.IsCode(chunk*31+count); count++ {
}
value[0] = byte(count)
end := (chunk + 1) * 31
if end > uint64(len(scope.Contract.Code)) {
end = uint64(len(scope.Contract.Code))
}
copy(value[1:], scope.Contract.Code[chunk*31:end])
copy(value[1:], scope.Contract.Code[chunk*31:endMin])
index := trieUtils.GetTreeKeyCodeChunk(scope.Contract.Address().Bytes(), uint256.NewInt(chunk))
interpreter.evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil)

// in the case of PUSH32, the end data might be two chunks away,
// so also get the middle chunk. There is a boundary condition
// check (endMin > 2) in the case the code is a single PUSH32
// insctruction, whose immediate are just 0s.
if pushByteSize == 32 && endMin > 2 {
chunk = uint64(endMin-2) / 31
count = uint64(0)
// Look for the first code byte (i.e. no pushdata)
for ; count < 31 && !scope.Contract.IsCode(chunk*31+count); count++ {
}
value[0] = byte(count)
end := (chunk + 1) * 31
if end > uint64(len(scope.Contract.Code)) {
end = uint64(len(scope.Contract.Code))
}
copy(value[1:], scope.Contract.Code[chunk*31:end])
index := trieUtils.GetTreeKeyCodeChunk(scope.Contract.Address().Bytes(), uint256.NewInt(chunk))
interpreter.evm.TxContext.Accesses.TouchAddressAndChargeGas(index, nil)

}
}

*pc += size
Expand Down
5 changes: 1 addition & 4 deletions miner/worker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,10 +259,7 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool) {
if _, err := chain.InsertChain([]*types.Block{block}); err != nil {
t.Fatalf("failed to insert new mined block %d: %v", block.NumberU64(), err)
}
// TODO(gballet) the timeout had to be increased from 3s to 7s with verkle
// trees, presumably because calculating an address is orders of magnitude
// slower with perdersen_hash not using the multi-exponentiation.
case <-time.After(5 * time.Second): // Worker needs 1s to include new changes.
case <-time.After(3 * time.Second): // Worker needs 1s to include new changes.
t.Fatalf("timeout")
}
}
Expand Down