Skip to content

Commit

Permalink
fix(trace): update proofList struct (ethereum#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
0xmountaintop authored Mar 19, 2022
1 parent 9fb413d commit 13ea5c2
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 45 deletions.
15 changes: 11 additions & 4 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1348,18 +1348,25 @@ func (bc *BlockChain) writeBlockResult(state *state.StateDB, block *types.Block,
blockResult.BlockTrace = types.NewTraceBlock(bc.chainConfig, block)
for i, tx := range block.Transactions() {
evmTrace := blockResult.ExecutionResults[i]
// Get the sender's address.

// Get sender's address.
from, _ := types.Sender(types.MakeSigner(bc.chainConfig, block.Number()), tx)
// Get account's proof.
evmTrace.Sender = &types.AccountProofWrapper{
Address: from,
Nonce: state.GetNonce(from),
Balance: state.GetBalance(from),
}
// Get sender's account proof.
proof, err := state.GetProof(from)
if err != nil {
log.Error("Failed to get proof", "blockNumber", block.NumberU64(), "address", from.String(), "err", err)
} else {
evmTrace.Proof = make([]string, len(proof))
evmTrace.Sender.Proof = make([]string, len(proof))
for i := range proof {
evmTrace.Proof[i] = hexutil.Encode(proof[i])
evmTrace.Sender.Proof[i] = hexutil.Encode(proof[i])
}
}

// Contract is called
if len(tx.Data()) != 0 && tx.To() != nil {
evmTrace.ByteCode = hexutil.Encode(state.GetCode(*tx.To()))
Expand Down
36 changes: 25 additions & 11 deletions core/types/l2trace.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package types

import (
"math/big"

"github.com/scroll-tech/go-ethereum/common"
)

Expand All @@ -17,12 +19,12 @@ type ExecutionResult struct {
Gas uint64 `json:"gas"`
Failed bool `json:"failed"`
ReturnValue string `json:"returnValue,omitempty"`
// Sender's account proof.
Sender *AccountProofWrapper `json:"sender,omitempty"`
// It's exist only 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"`
// The account's proof.
Proof []string `json:"proof,omitempty"`
ByteCode string `json:"byteCode,omitempty"`
StructLogs []StructLogRes `json:"structLogs"`
}

Expand All @@ -42,26 +44,38 @@ type StructLogRes struct {
}

type ExtraData struct {
// CREATE | CREATE2: sender address
From *common.Address `json:"from,omitempty"`
// CREATE: sender nonce
Nonce *uint64 `json:"nonce,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]
// CREATE | CREATE2: [sender's accountProof, created contract address’s accountProof]
// CALL | CALLCODE: [caller contract address’s accountProof, stack.nth_last(1) address’s accountProof]
ProofList [][]string `json:"proofList,omitempty"`
ProofList []*AccountProofWrapper `json:"proofList,omitempty"`
}

type AccountProofWrapper struct {
Address common.Address `json:"address,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
Balance *big.Int `json:"balance,omitempty"`
Proof []string `json:"proof,omitempty"`
Storage *StorageProofWrapper `json:"storage,omitempty"` // StorageProofWrapper can be empty if irrelated to storage operation
}

// while key & value can also be retrieved from StructLogRes.Storage,
// we still stored in here for roller's processing convenience.
type StorageProofWrapper struct {
Key string `json:"key,omitempty"`
Value string `json:"value,omitempty"`
Proof []string `json:"proof,omitempty"`
}

// NewExtraData create, init and return ExtraData
func NewExtraData() *ExtraData {
return &ExtraData{
CodeList: make([][]byte, 0),
ProofList: make([][]string, 0),
ProofList: make([]*AccountProofWrapper, 0),
}
}

Expand All @@ -73,7 +87,7 @@ func (e *ExtraData) SealExtraData() *ExtraData {
if len(e.ProofList) == 0 {
e.ProofList = nil
}
if e.From == nil && e.Nonce == nil && e.CodeList == nil && e.ProofList == nil {
if e.CodeList == nil && e.ProofList == nil {
return nil
}
return e
Expand Down
6 changes: 6 additions & 0 deletions core/vm/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@ func (l *StructLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scop
)
l.storage[contract.Address()][address] = value
storage = l.storage[contract.Address()].Copy()

extraData = types.NewExtraData()
if err := traceStorageProof(l, scope, extraData); err != nil {
log.Warn("Failed to get proof", "contract address", contract.Address().String(), "key", address.String(), "err", err)
}

} else if op == SSTORE && stack.len() >= 2 {
// capture SSTORE opcodes and record the written entry in the local storage.
var (
Expand Down
84 changes: 54 additions & 30 deletions core/vm/logger_trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ var (
CALLCODE: {traceToAddressCode, traceLastNAddressCode(1), traceCallerProof, traceLastNAddressProof(1)},
DELEGATECALL: {traceToAddressCode, traceLastNAddressCode(1)},
STATICCALL: {traceToAddressCode, traceLastNAddressCode(1)},
CREATE: {traceSenderAddress, traceCreatedContractProof, traceNonce},
CREATE2: {traceSenderAddress, traceCreatedContractProof},
SSTORE: {traceStorageProof},
SLOAD: {traceStorageProof},
CREATE: {traceCreatedContractProof}, // sender's wrapped_proof is already recorded in BlockChain.writeBlockResult
CREATE2: {traceCreatedContractProof}, // sender's wrapped_proof is already recorded in BlockChain.writeBlockResult
SLOAD: {}, // only record state_before, instead of state_after
SSTORE: {traceStorageProof}, // record state_after besides state_before
SELFDESTRUCT: {traceContractProof, traceLastNAddressProof(0)},
SELFBALANCE: {traceContractProof},
BALANCE: {traceLastNAddressProof(0)},
Expand Down Expand Up @@ -52,40 +52,25 @@ func traceLastNAddressCode(n int) traceFunc {
}
}

// traceSenderAddress gets sender address
func traceSenderAddress(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
extraData.From = &l.env.Origin
return nil
}

// traceNonce gets sender nonce
func traceNonce(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
nonce := l.env.StateDB.GetNonce(l.env.Origin)
extraData.Nonce = &nonce
return nil
}

// traceStorageProof get contract's storage proof at storage_address
func traceStorageProof(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
if scope.Stack.len() == 0 {
return nil
}
address := common.Hash(scope.Stack.peek().Bytes32())
contract := scope.Contract
// Get storage proof.
storageProof, err := l.env.StateDB.GetStorageProof(contract.Address(), address)
key := common.Hash(scope.Stack.peek().Bytes32())
proof, err := getWrappedProofForStorage(l, scope.Contract.Address(), key)
if err == nil {
extraData.ProofList = append(extraData.ProofList, encodeProof(storageProof))
extraData.ProofList = append(extraData.ProofList, proof)
}
return err
}

// traceContractProof gets the contract's account proof
func traceContractProof(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
// Get account proof.
proof, err := l.env.StateDB.GetProof(scope.Contract.Address())
proof, err := getWrappedProofForAddr(l, scope.Contract.Address())
if err == nil {
extraData.ProofList = append(extraData.ProofList, encodeProof(proof))
extraData.ProofList = append(extraData.ProofList, proof)
}
return err
}
Expand All @@ -101,9 +86,9 @@ func traceCreatedContractProof(l *StructLogger, scope *ScopeContext, extraData *
return errors.New("can't get created contract address from stack")
}
address := common.BytesToAddress(stackvalue.Bytes())
proof, err := l.env.StateDB.GetProof(address)
proof, err := getWrappedProofForAddr(l, address)
if err == nil {
extraData.ProofList = append(extraData.ProofList, encodeProof(proof))
extraData.ProofList = append(extraData.ProofList, proof)
}
return err
}
Expand All @@ -117,9 +102,9 @@ func traceLastNAddressProof(n int) traceFunc {
}

address := common.Address(stack.data[stack.len()-1-n].Bytes20())
proof, err := l.env.StateDB.GetProof(address)
proof, err := getWrappedProofForAddr(l, address)
if err == nil {
extraData.ProofList = append(extraData.ProofList, encodeProof(proof))
extraData.ProofList = append(extraData.ProofList, proof)
}
return err
}
Expand All @@ -128,13 +113,52 @@ func traceLastNAddressProof(n int) traceFunc {
// traceCallerProof gets caller address's proof.
func traceCallerProof(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
address := scope.Contract.CallerAddress
proof, err := l.env.StateDB.GetProof(address)
proof, err := getWrappedProofForAddr(l, address)
if err == nil {
extraData.ProofList = append(extraData.ProofList, encodeProof(proof))
extraData.ProofList = append(extraData.ProofList, proof)
}
return err
}

// StorageProofWrapper will be empty
func getWrappedProofForAddr(l *StructLogger, address common.Address) (*types.AccountProofWrapper, error) {
proof, err := l.env.StateDB.GetProof(address)
if err != nil {
return nil, err
}

return &types.AccountProofWrapper{
Address: address,
Nonce: l.env.StateDB.GetNonce(address),
Balance: l.env.StateDB.GetBalance(address),
Proof: encodeProof(proof),
}, nil
}

func getWrappedProofForStorage(l *StructLogger, address common.Address, key common.Hash) (*types.AccountProofWrapper, error) {
proof, err := l.env.StateDB.GetProof(address)
if err != nil {
return nil, err
}

storageProof, err := l.env.StateDB.GetStorageProof(address, key)
if err != nil {
return nil, err
}

return &types.AccountProofWrapper{
Address: address,
Nonce: l.env.StateDB.GetNonce(address),
Balance: l.env.StateDB.GetBalance(address),
Proof: encodeProof(proof),
Storage: &types.StorageProofWrapper{
Key: key.String(),
Value: l.env.StateDB.GetState(address, key).String(),
Proof: encodeProof(storageProof),
},
}, nil
}

func encodeProof(proof [][]byte) (res []string) {
if len(proof) == 0 {
return nil
Expand Down

0 comments on commit 13ea5c2

Please sign in to comment.