Skip to content

Commit

Permalink
Refactor l2witness/opt-storage-proof (#112)
Browse files Browse the repository at this point in the history
* rename GetStateData to GetLiveStateObject

* revert EvmTxTraces type

* rename GetLiveStateObject to GetLiveStateAccount

* fix typo

* some renamings

* format codes

* fix typo

* fix typos

* format codes

some reverts

some renamings

some renamings

format codes

* update comments

update comments

* update comments

update comments

update comments

* update comments

update comments

update comments

* rename

* rename

* update

* update comments
  • Loading branch information
0xmountaintop authored Jun 7, 2022
1 parent 12af4fa commit 52f22af
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 122 deletions.
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Auto detect text files and perform LF normalization
* text=auto
*.sol linguist-language=Solidity
*.go text eol=lf
*.go text eol=lf
18 changes: 9 additions & 9 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1193,17 +1193,17 @@ func (bc *BlockChain) writeKnownBlock(block *types.Block) error {
}

// WriteBlockWithState writes the block and all associated state to the database.
func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, evmTraces *types.EvmTxTraces, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, evmTraces []*types.ExecutionResult, storageTrace *types.StorageTrace, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
if !bc.chainmu.TryLock() {
return NonStatTy, errInsertionInterrupted
}
defer bc.chainmu.Unlock()
return bc.writeBlockWithState(block, receipts, logs, evmTraces, state, emitHeadEvent)
return bc.writeBlockWithState(block, receipts, logs, evmTraces, storageTrace, state, emitHeadEvent)
}

// writeBlockWithState writes the block and all associated state to the database,
// but is expects the chain mutex to be held.
func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, evmTraces *types.EvmTxTraces, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, evmTraces []*types.ExecutionResult, storageTrace *types.StorageTrace, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
if bc.insertStopped() {
return NonStatTy, errInsertionInterrupted
}
Expand Down Expand Up @@ -1327,7 +1327,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
// Fill blockResult content
var blockResult *types.BlockResult
if evmTraces != nil {
blockResult = bc.writeBlockResult(state, block, evmTraces)
blockResult = bc.writeBlockResult(state, block, evmTraces, storageTrace)
bc.blockResultCache.Add(block.Hash(), blockResult)
}

Expand All @@ -1351,10 +1351,10 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
}

// Fill blockResult content
func (bc *BlockChain) writeBlockResult(state *state.StateDB, block *types.Block, evmTraces *types.EvmTxTraces) *types.BlockResult {
func (bc *BlockChain) writeBlockResult(state *state.StateDB, block *types.Block, evmTraces []*types.ExecutionResult, storageTrace *types.StorageTrace) *types.BlockResult {
blockResult := &types.BlockResult{
ExecutionResults: evmTraces.TxResults,
StorageTrace: evmTraces.Storage,
ExecutionResults: evmTraces,
StorageTrace: storageTrace,
}
coinbase := types.AccountWrapper{
Address: block.Coinbase(),
Expand Down Expand Up @@ -1692,8 +1692,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er

// Write the block to the chain and get the status.
substart = time.Now()
// EvmTraces is nil is safe because l2geth's p2p server is stoped and the code will not execute there.
status, err := bc.writeBlockWithState(block, receipts, logs, nil, statedb, false)
// EvmTraces & StorageTrace being nil is safe because l2geth's p2p server is stoped and the code will not execute there.
status, err := bc.writeBlockWithState(block, receipts, logs, nil, nil, statedb, false)
atomic.StoreUint32(&followupInterrupt, 1)
if err != nil {
return it.index, err
Expand Down
2 changes: 1 addition & 1 deletion core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ func (s *StateDB) GetProofByHash(addrHash common.Hash) ([][]byte, error) {
return proof, err
}

func (s *StateDB) GetStateData(addr common.Address) *types.StateAccount {
func (s *StateDB) GetLiveStateAccount(addr common.Address) *types.StateAccount {
obj, ok := s.stateObjects[addr]
if !ok {
return nil
Expand Down
42 changes: 18 additions & 24 deletions core/types/l2trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,33 +41,26 @@ type StorageTrace struct {
StorageProofs map[string]map[string][]hexutil.Bytes `json:"storageProofs,omitempty"`
}

// EvmTxTraces groups trace data from each executation of tx and left
// some field to be finished from blockResult
type EvmTxTraces struct {
TxResults []*ExecutionResult
Storage *StorageTrace
}

// ExecutionResult groups all structured logs emitted by the EVM
// while replaying a transaction in debug mode as well as transaction
// execution status, the amount of gas used and the return value
type ExecutionResult struct {
Gas uint64 `json:"gas"`
Failed bool `json:"failed"`
ReturnValue string `json:"returnValue,omitempty"`
// Sender's account proof (before Tx)..
// Sender's account state (before Tx)
From *AccountWrapper `json:"from,omitempty"`
// Receiver's account proof.
// Receiver's account state (before Tx)
To *AccountWrapper `json:"to,omitempty"`
// AccountCreated record the account in case tx is create
// (for creating inside contracts we handle CREATE op)
// AccountCreated record the account if the tx is "create"
// (for creating inside a contract, we just handle CREATE op)
AccountCreated *AccountWrapper `json:"accountCreated,omitempty"`

// Record all accounts' state which would be affected AFTER tx executed
// currently they are just sender and to account
// currently they are just `from` and `to` account
AccountsAfter []*AccountWrapper `json:"accountAfter"`

// It's exist only when tx is a contract call.
// `CodeHash` only exists when tx is a contract call.
CodeHash *common.Hash `json:"codeHash,omitempty"`
// If it is a contract call, the contract code is returned.
ByteCode string `json:"byteCode,omitempty"`
Expand Down Expand Up @@ -107,21 +100,22 @@ func NewStructLogResBasic(pc uint64, op string, gas, gasCost uint64, depth int,
}

type ExtraData struct {
// Indicate the call success or not for CALL/CREATE op
// Indicate the call succeeds or not for CALL/CREATE op
CallFailed bool `json:"callFailed,omitempty"`
// CALL | CALLCODE | DELEGATECALL | STATICCALL: [tx.to address’s code, stack.nth_last(1) address’s code]
CodeList [][]byte `json:"codeList,omitempty"`
// SSTORE | SLOAD: [storageProof]
// SELFDESTRUCT: [contract address’s accountProof, stack.nth_last(0) address’s accountProof]
// SELFBALANCE: [contract address’s accountProof]
// BALANCE | EXTCODEHASH: [stack.nth_last(0) address’s accountProof]
// CREATE | CREATE2: [created contract address’s accountProof (before constructed),
// created contract address's data (after constructed)]
// CALL | CALLCODE: [caller contract address’s accountProof, stack.nth_last(1) (i.e. called) address’s accountProof
// called contract address's data (value updated, before called)]
// STATICCALL: [stack.nth_last(1) (i.e. called) address’s accountProof
// called contract address's data (before called)]
ProofList []*AccountWrapper `json:"proofList,omitempty"`
// SELFDESTRUCT: [contract address’s account, stack.nth_last(0) address’s account]
// SELFBALANCE: [contract address’s account]
// BALANCE | EXTCODEHASH: [stack.nth_last(0) address’s account]
// CREATE | CREATE2: [created contract address’s account (before constructed),
// created contract address's account (after constructed)]
// CALL | CALLCODE: [caller contract address’s account,
// stack.nth_last(1) (i.e. callee) address’s account,
// callee contract address's account (value updated, before called)]
// STATICCALL: [stack.nth_last(1) (i.e. callee) address’s account,
// callee contract address's account (before called)]
StateList []*AccountWrapper `json:"proofList,omitempty"`
}

type AccountWrapper struct {
Expand Down
2 changes: 1 addition & 1 deletion core/vm/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ type StateDB interface {
SetState(common.Address, common.Hash, common.Hash)

GetRootHash() common.Hash
GetStateData(addr common.Address) *types.StateAccount
GetLiveStateAccount(addr common.Address) *types.StateAccount
GetProof(addr common.Address) ([][]byte, error)
GetProofByHash(addrHash common.Hash) ([][]byte, error)
GetStorageProof(a common.Address, key common.Hash) ([][]byte, error)
Expand Down
48 changes: 24 additions & 24 deletions core/vm/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ type StructLogger struct {
cfg LogConfig
env *EVM

states map[common.Address]struct{}
statesAffected map[common.Address]struct{}
storage map[common.Address]Storage
createdAccount *types.AccountWrapper

Expand All @@ -178,8 +178,8 @@ type StructLogger struct {
// NewStructLogger returns a new logger
func NewStructLogger(cfg *LogConfig) *StructLogger {
logger := &StructLogger{
storage: make(map[common.Address]Storage),
states: make(map[common.Address]struct{}),
storage: make(map[common.Address]Storage),
statesAffected: make(map[common.Address]struct{}),
}
if cfg != nil {
logger.cfg = *cfg
Expand All @@ -190,7 +190,7 @@ func NewStructLogger(cfg *LogConfig) *StructLogger {
// Reset clears the data held by the logger.
func (l *StructLogger) Reset() {
l.storage = make(map[common.Address]Storage)
l.states = make(map[common.Address]struct{})
l.statesAffected = make(map[common.Address]struct{})
l.output = make([]byte, 0)
l.logs = l.logs[:0]
l.callStackLogInd = nil
Expand All @@ -199,21 +199,21 @@ func (l *StructLogger) Reset() {
}

// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Address, isCreate bool, input []byte, gas uint64, value *big.Int) {
l.env = env

if create {
//Notice codeHash is set AFTER CreateTx has exited, so heree codeHash is still empty
if isCreate {
// notice codeHash is set AFTER CreateTx has exited, so here codeHash is still empty
l.createdAccount = &types.AccountWrapper{
//Nonce is 1 after EIP158, so we query it from stateDb
Address: to,
// nonce is 1 after EIP158, so we query it from stateDb
Nonce: env.StateDB.GetNonce(to),
Balance: (*hexutil.Big)(value),
Address: to,
}
}

l.states[from] = struct{}{}
l.states[to] = struct{}{}
l.statesAffected[from] = struct{}{}
l.statesAffected[to] = struct{}{}
}

// CaptureState logs a new structured log message and pushes it out to the environment
Expand Down Expand Up @@ -263,7 +263,7 @@ func (l *StructLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scop
l.storage[contractAddress][storageKey] = storageValue
structlog.Storage = l.storage[contractAddress].Copy()

if err := traceStorageProof(l, scope, structlog.getOrInitExtraData()); err != nil {
if err := traceStorage(l, scope, structlog.getOrInitExtraData()); err != nil {
log.Error("Failed to trace data", "opcode", op.String(), "err", err)
}
}
Expand Down Expand Up @@ -305,20 +305,20 @@ func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration
}

func (l *StructLogger) CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
//the last logged op should be CALL/CREATE
// the last logged op should be CALL/STATICCALL/CALLCODE/CREATE/CREATE2
lastLogPos := len(l.logs) - 1
log.Debug("mark call stack", "pos", lastLogPos, "op", l.logs[lastLogPos].Op)
l.callStackLogInd = append(l.callStackLogInd, lastLogPos)
//sanity check
// sanity check
if len(l.callStackLogInd) != l.env.depth {
panic("unexpected evm depth in capture enter")
}
l.states[to] = struct{}{}
l.statesAffected[to] = struct{}{}
theLog := l.logs[lastLogPos]
// handling additional updating for CREATE only
// handling additional updating for CALL/STATICCALL/CALLCODE/CREATE/CREATE2 only
// append extraData part for the log, capture the account status (the nonce / balance has been updated in capture enter)
wrappedStatus, _ := getWrappedForAddr(l, to)
theLog.ExtraData.ProofList = append(theLog.ExtraData.ProofList, wrappedStatus)
wrappedStatus, _ := getWrappedAccountForAddr(l, to)
theLog.ExtraData.StateList = append(theLog.ExtraData.StateList, wrappedStatus)
}

// in CaptureExit phase, a CREATE has its target address's code being set and queryable
Expand All @@ -331,7 +331,7 @@ func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {
theLogPos := l.callStackLogInd[stackH-1]
l.callStackLogInd = l.callStackLogInd[:stackH-1]
theLog := l.logs[theLogPos]
//update "forecast" data
// update "forecast" data
if err != nil {
theLog.ExtraData.CallFailed = true
}
Expand All @@ -340,14 +340,14 @@ func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {
switch theLog.Op {
case CREATE, CREATE2:
// append extraData part for the log whose op is CREATE(2), capture the account status (the codehash would be updated in capture exit)
dataLen := len(theLog.ExtraData.ProofList)
dataLen := len(theLog.ExtraData.StateList)
if dataLen == 0 {
panic("unexpected data capture for target op")
}

lastAccData := theLog.ExtraData.ProofList[dataLen-1]
wrappedStatus, _ := getWrappedForAddr(l, lastAccData.Address)
theLog.ExtraData.ProofList = append(theLog.ExtraData.ProofList, wrappedStatus)
lastAccData := theLog.ExtraData.StateList[dataLen-1]
wrappedStatus, _ := getWrappedAccountForAddr(l, lastAccData.Address)
theLog.ExtraData.StateList = append(theLog.ExtraData.StateList, wrappedStatus)
default:
//do nothing for other op code
return
Expand All @@ -357,7 +357,7 @@ func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {

// UpdatedAccounts is used to collect all "touched" accounts
func (l *StructLogger) UpdatedAccounts() map[common.Address]struct{} {
return l.states
return l.statesAffected
}

// UpdatedStorages is used to collect all "touched" storage slots
Expand Down
Loading

0 comments on commit 52f22af

Please sign in to comment.