Skip to content

Commit

Permalink
update with feat/zero branch zero.go file (#1109)
Browse files Browse the repository at this point in the history
Co-authored-by: Jerry <jerrycgh@gmail.com>
  • Loading branch information
temaniarpit27 and cffls authored Oct 7, 2024
1 parent 500812d commit dd237b6
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 65 deletions.
62 changes: 40 additions & 22 deletions core/state/intra_block_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ type IntraBlockState struct {
stateObjects map[libcommon.Address]*stateObject
stateObjectsDirty map[libcommon.Address]struct{}

seenStateObjects map[libcommon.Address]struct{} // State objects that have been seen at least once

nilAccounts map[libcommon.Address]struct{} // Remember non-existent account to avoid reading them again

// DB error.
Expand All @@ -86,18 +88,20 @@ type IntraBlockState struct {

// Journal of state modifications. This is the backbone of
// Snapshot and RevertToSnapshot.
journal *journal
validRevisions []revision
nextRevisionID int
trace bool
balanceInc map[libcommon.Address]*BalanceIncrease // Map of balance increases (without first reading the account)
journal *journal
validRevisions []revision
nextRevisionID int
trace bool
balanceInc map[libcommon.Address]*BalanceIncrease // Map of balance increases (without first reading the account)
disableBalanceInc bool // Disable balance increase tracking and eagerly read accounts
}

// Create a new state from a given trie
func New(stateReader StateReader) *IntraBlockState {
return &IntraBlockState{
stateReader: stateReader,
stateObjects: map[libcommon.Address]*stateObject{},
seenStateObjects: map[libcommon.Address]struct{}{},
stateObjectsDirty: map[libcommon.Address]struct{}{},
nilAccounts: map[libcommon.Address]struct{}{},
logs: map[libcommon.Hash][]*types.Log{},
Expand All @@ -112,6 +116,10 @@ func (sdb *IntraBlockState) SetTrace(trace bool) {
sdb.trace = trace
}

func (sdb *IntraBlockState) SetDisableBalanceInc(disable bool) {
sdb.disableBalanceInc = disable
}

// setErrorUnsafe sets error but should be called in medhods that already have locks
func (sdb *IntraBlockState) setErrorUnsafe(err error) {
if sdb.savedErr == nil {
Expand Down Expand Up @@ -306,24 +314,27 @@ func (sdb *IntraBlockState) AddBalance(addr libcommon.Address, amount *uint256.I
if sdb.trace {
fmt.Printf("AddBalance %x, %d\n", addr, amount)
}
// If this account has not been read, add to the balance increment map
_, needAccount := sdb.stateObjects[addr]
if !needAccount && addr == ripemd && amount.IsZero() {
needAccount = true
}
if !needAccount {
sdb.journal.append(balanceIncrease{
account: &addr,
increase: *amount,
})
bi, ok := sdb.balanceInc[addr]
if !ok {
bi = &BalanceIncrease{}
sdb.balanceInc[addr] = bi

if !sdb.disableBalanceInc {
// If this account has not been read, add to the balance increment map
_, needAccount := sdb.stateObjects[addr]
if !needAccount && addr == ripemd && amount.IsZero() {
needAccount = true
}
if !needAccount {
sdb.journal.append(balanceIncrease{
account: &addr,
increase: *amount,
})
bi, ok := sdb.balanceInc[addr]
if !ok {
bi = &BalanceIncrease{}
sdb.balanceInc[addr] = bi
}
bi.increase.Add(&bi.increase, amount)
bi.count++
return
}
bi.increase.Add(&bi.increase, amount)
bi.count++
return
}

stateObject := sdb.GetOrNewStateObject(addr)
Expand Down Expand Up @@ -414,6 +425,11 @@ func (sdb *IntraBlockState) HasLiveAccount(addr libcommon.Address) bool {
return false
}

func (sdb *IntraBlockState) SeenAccount(addr libcommon.Address) bool {
_, ok := sdb.seenStateObjects[addr]
return ok
}

func (sdb *IntraBlockState) HasLiveState(addr libcommon.Address, key *libcommon.Hash) bool {
if stateObject := sdb.stateObjects[addr]; stateObject != nil {
if _, ok := stateObject.originStorage[*key]; ok {
Expand Down Expand Up @@ -503,6 +519,7 @@ func (sdb *IntraBlockState) getStateObject(addr libcommon.Address) (stateObject
return nil
}
account, err := sdb.stateReader.ReadAccountData(addr)
sdb.seenStateObjects[addr] = struct{}{}
if err != nil {
sdb.setErrorUnsafe(err)
return nil
Expand All @@ -528,6 +545,7 @@ func (sdb *IntraBlockState) setStateObject(addr libcommon.Address, object *state
sdb.journal.append(balanceIncreaseTransfer{bi: bi})
}
sdb.stateObjects[addr] = object
sdb.seenStateObjects[addr] = struct{}{}
}

// Retrieve a state object or create a new state object if nil.
Expand Down
2 changes: 2 additions & 0 deletions core/vm/evmtypes/evmtypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ type IntraBlockState interface {
GetState(address common.Address, slot *common.Hash, outValue *uint256.Int)
SetState(common.Address, *common.Hash, uint256.Int)
HasLiveAccount(addr common.Address) bool
SeenAccount(addr common.Address) bool
HasLiveState(addr common.Address, key *common.Hash) bool

GetTransientState(addr common.Address, key common.Hash) uint256.Int
Expand Down Expand Up @@ -118,4 +119,5 @@ type IntraBlockState interface {
GetLogs(hash common.Hash) []*types.Log
GetBlockStateRoot(blockNum *uint256.Int) *uint256.Int
GetBlockNumber() *uint256.Int
SetDisableBalanceInc(disable bool)
}
7 changes: 7 additions & 0 deletions core/vm/instructions_zkevm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ func (ibs TestIntraBlockState) AddLog(log *types.Log) {
panic("implement me")
}

func (ibs TestIntraBlockState) SeenAccount(addr libcommon.Address) bool {
//TODO implement me
panic("implement me")
}

func (ibs TestIntraBlockState) GetLogs(hash libcommon.Hash) []*types.Log {
//TODO implement me
panic("implement me")
Expand Down Expand Up @@ -204,3 +209,5 @@ func (ibs TestIntraBlockState) Prepare(rules *chain.Rules, sender, coinbase comm
}

func (ibs TestIntraBlockState) Selfdestruct6780(common.Address) {}

func (ibs TestIntraBlockState) SetDisableBalanceInc(disable bool) {}
85 changes: 42 additions & 43 deletions eth/tracers/native/zero.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ func (t *zeroTracer) CaptureStart(env *vm.EVM, from libcommon.Address, to libcom
t.to = &to
t.env = env

t.env.IntraBlockState().SetDisableBalanceInc(true)

t.addAccountToTrace(from)
t.addAccountToTrace(to)
t.addAccountToTrace(env.Context.Coinbase)
Expand All @@ -62,6 +64,14 @@ func (t *zeroTracer) CaptureStart(env *vm.EVM, from libcommon.Address, to libcom
t.addOpCodeToAccount(to, vm.CALL)
}

for _, a := range t.ctx.Txn.GetAccessList() {
t.addAccountToTrace(a.Address)

for _, k := range a.StorageKeys {
t.addSLOADToAccount(a.Address, k)
}
}

// The recipient balance includes the value transferred.
toBal := new(big.Int).Sub(t.tx.Traces[to].Balance.ToBig(), value.ToBig())
t.tx.Traces[to].Balance = uint256.MustFromBig(toBal)
Expand Down Expand Up @@ -90,11 +100,6 @@ func (t *zeroTracer) CaptureTxStart(gasLimit uint64) {

// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
func (t *zeroTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
// Only continue if the error is nil or if the error is out of gas and the opcode is SSTORE, CALL, or SELFDESTRUCT
if !(err == nil || (err == vm.ErrOutOfGas && (op == vm.SSTORE || op == vm.CALL || op == vm.SELFDESTRUCT))) {
return
}

// Skip if tracing was interrupted
if t.interrupt.Load() {
return
Expand All @@ -112,42 +117,21 @@ func (t *zeroTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco
t.addSLOADToAccount(caller, slot)
case stackLen >= 1 && op == vm.SSTORE:
slot := libcommon.Hash(stackData[stackLen-1].Bytes32())

// If the SSTORE is out of gas and the slot is in live state, we will add the slot to account read
if err == vm.ErrOutOfGas {
if t.env.IntraBlockState().HasLiveState(caller, &slot) {
t.addAccountToTrace(caller)
t.addSLOADToAccount(caller, slot)
}
return
}
t.addAccountToTrace(caller)
t.addSSTOREToAccount(caller, slot, stackData[stackLen-2].Clone())
case stackLen >= 1 && (op == vm.EXTCODECOPY || op == vm.EXTCODEHASH || op == vm.EXTCODESIZE || op == vm.BALANCE || op == vm.SELFDESTRUCT):
addr := libcommon.Address(stackData[stackLen-1].Bytes20())

if err == vm.ErrOutOfGas && op == vm.SELFDESTRUCT {
if t.env.IntraBlockState().HasLiveAccount(addr) {
t.addAccountToTrace(addr)
}
return
}
t.addAccountToTrace(addr)
t.addOpCodeToAccount(addr, op)
case stackLen >= 5 && (op == vm.DELEGATECALL || op == vm.CALL || op == vm.STATICCALL || op == vm.CALLCODE):
addr := libcommon.Address(stackData[stackLen-2].Bytes20())

// If the call is out of gas, we will add account but not the opcode
if err == vm.ErrOutOfGas && op == vm.CALL {
if t.env.IntraBlockState().HasLiveAccount(addr) {
t.addAccountToTrace(addr)
}
return
}
t.addAccountToTrace(addr)
t.addOpCodeToAccount(addr, op)
case op == vm.CREATE:
nonce := t.env.IntraBlockState().GetNonce(caller)
nonce := uint64(0)
if t.env.IntraBlockState().HasLiveAccount(caller) {
nonce = t.env.IntraBlockState().GetNonce(caller)
}
addr := crypto.CreateAddress(caller, nonce)
t.addAccountToTrace(addr)
t.addOpCodeToAccount(addr, op)
Expand Down Expand Up @@ -195,7 +179,16 @@ func (t *zeroTracer) CaptureTxEnd(restGas uint64) {
t.tx.Meta.GasUsed = t.gasLimit - restGas
*t.ctx.CumulativeGasUsed += t.tx.Meta.GasUsed

toDelete := make([]libcommon.Address, 0)
for addr := range t.tx.Traces {
// Check again if the account was accessed through IntraBlockState
seenAccount := t.env.IntraBlockState().SeenAccount(addr)
// If an account was never accessed through IntraBlockState, it means that never there was an OpCode that read into it or checks whether it exists in the state trie, and therefore we don't need the trace of it.
if !seenAccount {
toDelete = append(toDelete, addr)
continue
}

trace := t.tx.Traces[addr]
hasLiveAccount := t.env.IntraBlockState().HasLiveAccount(addr)
newBalance := t.env.IntraBlockState().GetBalance(addr)
Expand All @@ -219,7 +212,9 @@ func (t *zeroTracer) CaptureTxEnd(restGas uint64) {
if len(trace.StorageReadMap) > 0 && hasLiveAccount {
trace.StorageRead = make([]libcommon.Hash, 0, len(trace.StorageReadMap))
for k := range trace.StorageReadMap {
trace.StorageRead = append(trace.StorageRead, k)
if t.env.IntraBlockState().HasLiveState(addr, &k) {
trace.StorageRead = append(trace.StorageRead, k)
}
}
} else {
trace.StorageRead = nil
Expand All @@ -238,8 +233,7 @@ func (t *zeroTracer) CaptureTxEnd(restGas uint64) {

if !bytes.Equal(codeHash[:], emptyCodeHash) && !bytes.Equal(codeHash[:], trace.CodeUsage.Read[:]) {
trace.CodeUsage.Read = nil
trace.CodeUsage.Write = make([]byte, len(code))
copy(trace.CodeUsage.Write, code)
trace.CodeUsage.Write = bytes.Clone(code)
} else if code != nil {
codeHashCopy := libcommon.BytesToHash(codeHash.Bytes())
trace.CodeUsage.Read = &codeHashCopy
Expand All @@ -254,8 +248,6 @@ func (t *zeroTracer) CaptureTxEnd(restGas uint64) {
// fmt.Printf("Address: %s, opcodes: %v\n", addr.String(), t.addrOpCodes[addr])
// }

// We don't need to provide the actual bytecode UNLESS the opcode is the following:
// DELEGATECALL, CALL, STATICCALL, CALLCODE, EXTCODECOPY, EXTCODEHASH, EXTCODESIZE
if trace.CodeUsage != nil && trace.CodeUsage.Read != nil {
if t.addrOpCodes[addr] != nil {
// We don't need to provide the actual bytecode UNLESS the opcode is the following:
Expand Down Expand Up @@ -283,6 +275,10 @@ func (t *zeroTracer) CaptureTxEnd(restGas uint64) {
}
}

for _, addr := range toDelete {
delete(t.tx.Traces, addr)
}

receipt := &types.Receipt{Type: t.ctx.Txn.Type(), CumulativeGasUsed: *t.ctx.CumulativeGasUsed}
receipt.Status = t.txStatus
receipt.TxHash = t.ctx.Txn.Hash()
Expand Down Expand Up @@ -316,7 +312,6 @@ func (t *zeroTracer) CaptureTxEnd(restGas uint64) {
return
}

t.tx.Meta.NewTxnTrieNode = txBuffer.Bytes()
t.tx.Meta.ByteCode = txBuffer.Bytes()
}

Expand Down Expand Up @@ -357,12 +352,19 @@ func (t *zeroTracer) addAccountToTrace(addr libcommon.Address) {
return
}

nonce := uint256.NewInt(t.env.IntraBlockState().GetNonce(addr))
codeHash := t.env.IntraBlockState().GetCodeHash(addr)
balance := uint256.NewInt(0)
nonce := uint256.NewInt(0)
codeHash := libcommon.Hash{}

if t.env.IntraBlockState().HasLiveAccount(addr) {
nonce = uint256.NewInt(t.env.IntraBlockState().GetNonce(addr))
balance = t.env.IntraBlockState().GetBalance(addr)
codeHash = t.env.IntraBlockState().GetCodeHash(addr)
}

t.tx.Traces[addr] = &types.TxnTrace{
Balance: t.env.IntraBlockState().GetBalance(addr).Clone(),
Nonce: nonce,
Balance: balance.Clone(),
Nonce: nonce.Clone(),
CodeUsage: &types.ContractCodeUsage{Read: &codeHash},
StorageWritten: make(map[libcommon.Hash]*uint256.Int),
StorageRead: make([]libcommon.Hash, 0),
Expand All @@ -371,10 +373,7 @@ func (t *zeroTracer) addAccountToTrace(addr libcommon.Address) {
}

func (t *zeroTracer) addSLOADToAccount(addr libcommon.Address, key libcommon.Hash) {
var value uint256.Int
t.env.IntraBlockState().GetState(addr, &key, &value)
t.tx.Traces[addr].StorageReadMap[key] = struct{}{}

t.addOpCodeToAccount(addr, vm.SLOAD)
}

Expand Down

0 comments on commit dd237b6

Please sign in to comment.