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