mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
fix(trace): update proofList struct (#46)
This commit is contained in:
parent
9fb413d702
commit
13ea5c234b
4 changed files with 96 additions and 45 deletions
|
|
@ -1348,18 +1348,25 @@ func (bc *BlockChain) writeBlockResult(state *state.StateDB, block *types.Block,
|
||||||
blockResult.BlockTrace = types.NewTraceBlock(bc.chainConfig, block)
|
blockResult.BlockTrace = types.NewTraceBlock(bc.chainConfig, block)
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
evmTrace := blockResult.ExecutionResults[i]
|
evmTrace := blockResult.ExecutionResults[i]
|
||||||
// Get the sender's address.
|
|
||||||
|
// Get sender's address.
|
||||||
from, _ := types.Sender(types.MakeSigner(bc.chainConfig, block.Number()), tx)
|
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)
|
proof, err := state.GetProof(from)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to get proof", "blockNumber", block.NumberU64(), "address", from.String(), "err", err)
|
log.Error("Failed to get proof", "blockNumber", block.NumberU64(), "address", from.String(), "err", err)
|
||||||
} else {
|
} else {
|
||||||
evmTrace.Proof = make([]string, len(proof))
|
evmTrace.Sender.Proof = make([]string, len(proof))
|
||||||
for i := range proof {
|
for i := range proof {
|
||||||
evmTrace.Proof[i] = hexutil.Encode(proof[i])
|
evmTrace.Sender.Proof[i] = hexutil.Encode(proof[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contract is called
|
// Contract is called
|
||||||
if len(tx.Data()) != 0 && tx.To() != nil {
|
if len(tx.Data()) != 0 && tx.To() != nil {
|
||||||
evmTrace.ByteCode = hexutil.Encode(state.GetCode(*tx.To()))
|
evmTrace.ByteCode = hexutil.Encode(state.GetCode(*tx.To()))
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
"github.com/scroll-tech/go-ethereum/common"
|
"github.com/scroll-tech/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -17,12 +19,12 @@ type ExecutionResult struct {
|
||||||
Gas uint64 `json:"gas"`
|
Gas uint64 `json:"gas"`
|
||||||
Failed bool `json:"failed"`
|
Failed bool `json:"failed"`
|
||||||
ReturnValue string `json:"returnValue,omitempty"`
|
ReturnValue string `json:"returnValue,omitempty"`
|
||||||
|
// Sender's account proof.
|
||||||
|
Sender *AccountProofWrapper `json:"sender,omitempty"`
|
||||||
// It's exist only when tx is a contract call.
|
// It's exist only when tx is a contract call.
|
||||||
CodeHash *common.Hash `json:"codeHash,omitempty"`
|
CodeHash *common.Hash `json:"codeHash,omitempty"`
|
||||||
// If it is a contract call, the contract code is returned.
|
// If it is a contract call, the contract code is returned.
|
||||||
ByteCode string `json:"byteCode,omitempty"`
|
ByteCode string `json:"byteCode,omitempty"`
|
||||||
// The account's proof.
|
|
||||||
Proof []string `json:"proof,omitempty"`
|
|
||||||
StructLogs []StructLogRes `json:"structLogs"`
|
StructLogs []StructLogRes `json:"structLogs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,26 +44,38 @@ type StructLogRes struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExtraData 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]
|
// CALL | CALLCODE | DELEGATECALL | STATICCALL: [tx.to address’s code, stack.nth_last(1) address’s code]
|
||||||
CodeList [][]byte `json:"codeList,omitempty"`
|
CodeList [][]byte `json:"codeList,omitempty"`
|
||||||
// SSTORE | SLOAD: [storageProof]
|
// SSTORE | SLOAD: [storageProof]
|
||||||
// SELFDESTRUCT: [contract address’s accountProof, stack.nth_last(0) address’s accountProof]
|
// SELFDESTRUCT: [contract address’s accountProof, stack.nth_last(0) address’s accountProof]
|
||||||
// SELFBALANCE: [contract address’s accountProof]
|
// SELFBALANCE: [contract address’s accountProof]
|
||||||
// BALANCE | EXTCODEHASH: [stack.nth_last(0) 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]
|
// 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
|
// NewExtraData create, init and return ExtraData
|
||||||
func NewExtraData() *ExtraData {
|
func NewExtraData() *ExtraData {
|
||||||
return &ExtraData{
|
return &ExtraData{
|
||||||
CodeList: make([][]byte, 0),
|
CodeList: make([][]byte, 0),
|
||||||
ProofList: make([][]string, 0),
|
ProofList: make([]*AccountProofWrapper, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,7 +87,7 @@ func (e *ExtraData) SealExtraData() *ExtraData {
|
||||||
if len(e.ProofList) == 0 {
|
if len(e.ProofList) == 0 {
|
||||||
e.ProofList = nil
|
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 nil
|
||||||
}
|
}
|
||||||
return e
|
return e
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,12 @@ func (l *StructLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scop
|
||||||
)
|
)
|
||||||
l.storage[contract.Address()][address] = value
|
l.storage[contract.Address()][address] = value
|
||||||
storage = l.storage[contract.Address()].Copy()
|
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 {
|
} else if op == SSTORE && stack.len() >= 2 {
|
||||||
// capture SSTORE opcodes and record the written entry in the local storage.
|
// capture SSTORE opcodes and record the written entry in the local storage.
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,10 @@ var (
|
||||||
CALLCODE: {traceToAddressCode, traceLastNAddressCode(1), traceCallerProof, traceLastNAddressProof(1)},
|
CALLCODE: {traceToAddressCode, traceLastNAddressCode(1), traceCallerProof, traceLastNAddressProof(1)},
|
||||||
DELEGATECALL: {traceToAddressCode, traceLastNAddressCode(1)},
|
DELEGATECALL: {traceToAddressCode, traceLastNAddressCode(1)},
|
||||||
STATICCALL: {traceToAddressCode, traceLastNAddressCode(1)},
|
STATICCALL: {traceToAddressCode, traceLastNAddressCode(1)},
|
||||||
CREATE: {traceSenderAddress, traceCreatedContractProof, traceNonce},
|
CREATE: {traceCreatedContractProof}, // sender's wrapped_proof is already recorded in BlockChain.writeBlockResult
|
||||||
CREATE2: {traceSenderAddress, traceCreatedContractProof},
|
CREATE2: {traceCreatedContractProof}, // sender's wrapped_proof is already recorded in BlockChain.writeBlockResult
|
||||||
SSTORE: {traceStorageProof},
|
SLOAD: {}, // only record state_before, instead of state_after
|
||||||
SLOAD: {traceStorageProof},
|
SSTORE: {traceStorageProof}, // record state_after besides state_before
|
||||||
SELFDESTRUCT: {traceContractProof, traceLastNAddressProof(0)},
|
SELFDESTRUCT: {traceContractProof, traceLastNAddressProof(0)},
|
||||||
SELFBALANCE: {traceContractProof},
|
SELFBALANCE: {traceContractProof},
|
||||||
BALANCE: {traceLastNAddressProof(0)},
|
BALANCE: {traceLastNAddressProof(0)},
|
||||||
|
|
@ -52,30 +52,15 @@ 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
|
// traceStorageProof get contract's storage proof at storage_address
|
||||||
func traceStorageProof(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
|
func traceStorageProof(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
|
||||||
if scope.Stack.len() == 0 {
|
if scope.Stack.len() == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
address := common.Hash(scope.Stack.peek().Bytes32())
|
key := common.Hash(scope.Stack.peek().Bytes32())
|
||||||
contract := scope.Contract
|
proof, err := getWrappedProofForStorage(l, scope.Contract.Address(), key)
|
||||||
// Get storage proof.
|
|
||||||
storageProof, err := l.env.StateDB.GetStorageProof(contract.Address(), address)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
extraData.ProofList = append(extraData.ProofList, encodeProof(storageProof))
|
extraData.ProofList = append(extraData.ProofList, proof)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -83,9 +68,9 @@ func traceStorageProof(l *StructLogger, scope *ScopeContext, extraData *types.Ex
|
||||||
// traceContractProof gets the contract's account proof
|
// traceContractProof gets the contract's account proof
|
||||||
func traceContractProof(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
|
func traceContractProof(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
|
||||||
// Get account proof.
|
// Get account proof.
|
||||||
proof, err := l.env.StateDB.GetProof(scope.Contract.Address())
|
proof, err := getWrappedProofForAddr(l, scope.Contract.Address())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
extraData.ProofList = append(extraData.ProofList, encodeProof(proof))
|
extraData.ProofList = append(extraData.ProofList, proof)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -101,9 +86,9 @@ func traceCreatedContractProof(l *StructLogger, scope *ScopeContext, extraData *
|
||||||
return errors.New("can't get created contract address from stack")
|
return errors.New("can't get created contract address from stack")
|
||||||
}
|
}
|
||||||
address := common.BytesToAddress(stackvalue.Bytes())
|
address := common.BytesToAddress(stackvalue.Bytes())
|
||||||
proof, err := l.env.StateDB.GetProof(address)
|
proof, err := getWrappedProofForAddr(l, address)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
extraData.ProofList = append(extraData.ProofList, encodeProof(proof))
|
extraData.ProofList = append(extraData.ProofList, proof)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -117,9 +102,9 @@ func traceLastNAddressProof(n int) traceFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
address := common.Address(stack.data[stack.len()-1-n].Bytes20())
|
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 {
|
if err == nil {
|
||||||
extraData.ProofList = append(extraData.ProofList, encodeProof(proof))
|
extraData.ProofList = append(extraData.ProofList, proof)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -128,13 +113,52 @@ func traceLastNAddressProof(n int) traceFunc {
|
||||||
// traceCallerProof gets caller address's proof.
|
// traceCallerProof gets caller address's proof.
|
||||||
func traceCallerProof(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
|
func traceCallerProof(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
|
||||||
address := scope.Contract.CallerAddress
|
address := scope.Contract.CallerAddress
|
||||||
proof, err := l.env.StateDB.GetProof(address)
|
proof, err := getWrappedProofForAddr(l, address)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
extraData.ProofList = append(extraData.ProofList, encodeProof(proof))
|
extraData.ProofList = append(extraData.ProofList, proof)
|
||||||
}
|
}
|
||||||
return err
|
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) {
|
func encodeProof(proof [][]byte) (res []string) {
|
||||||
if len(proof) == 0 {
|
if len(proof) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue