mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 07:06:42 +00:00
feat: add more data into the execution trace (#20)
This commit is contained in:
parent
8b16b4cefa
commit
69c291cf7a
25 changed files with 457 additions and 580 deletions
|
|
@ -30,6 +30,7 @@ import (
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
"github.com/scroll-tech/go-ethereum/common"
|
"github.com/scroll-tech/go-ethereum/common"
|
||||||
|
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
||||||
"github.com/scroll-tech/go-ethereum/common/mclock"
|
"github.com/scroll-tech/go-ethereum/common/mclock"
|
||||||
"github.com/scroll-tech/go-ethereum/common/prque"
|
"github.com/scroll-tech/go-ethereum/common/prque"
|
||||||
"github.com/scroll-tech/go-ethereum/consensus"
|
"github.com/scroll-tech/go-ethereum/consensus"
|
||||||
|
|
@ -84,13 +85,14 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
bodyCacheLimit = 256
|
bodyCacheLimit = 256
|
||||||
blockCacheLimit = 256
|
blockCacheLimit = 256
|
||||||
receiptsCacheLimit = 32
|
receiptsCacheLimit = 32
|
||||||
txLookupCacheLimit = 1024
|
txLookupCacheLimit = 1024
|
||||||
maxFutureBlocks = 256
|
maxFutureBlocks = 256
|
||||||
maxTimeFutureBlocks = 30
|
maxTimeFutureBlocks = 30
|
||||||
TriesInMemory = 128
|
TriesInMemory = 128
|
||||||
|
blockResultCacheLimit = 128
|
||||||
|
|
||||||
// BlockChainVersion ensures that an incompatible database forces a resync from scratch.
|
// BlockChainVersion ensures that an incompatible database forces a resync from scratch.
|
||||||
//
|
//
|
||||||
|
|
@ -191,13 +193,14 @@ type BlockChain struct {
|
||||||
currentBlock atomic.Value // Current head of the block chain
|
currentBlock atomic.Value // Current head of the block chain
|
||||||
currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
|
currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
|
||||||
|
|
||||||
stateCache state.Database // State database to reuse between imports (contains state cache)
|
stateCache state.Database // State database to reuse between imports (contains state cache)
|
||||||
bodyCache *lru.Cache // Cache for the most recent block bodies
|
bodyCache *lru.Cache // Cache for the most recent block bodies
|
||||||
bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format
|
bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format
|
||||||
receiptsCache *lru.Cache // Cache for the most recent receipts per block
|
receiptsCache *lru.Cache // Cache for the most recent receipts per block
|
||||||
blockCache *lru.Cache // Cache for the most recent entire blocks
|
blockCache *lru.Cache // Cache for the most recent entire blocks
|
||||||
txLookupCache *lru.Cache // Cache for the most recent transaction lookup data.
|
txLookupCache *lru.Cache // Cache for the most recent transaction lookup data.
|
||||||
futureBlocks *lru.Cache // future blocks are blocks added for later processing
|
futureBlocks *lru.Cache // future blocks are blocks added for later processing
|
||||||
|
blockResultCache *lru.Cache // Cache for the most recent block results.
|
||||||
|
|
||||||
wg sync.WaitGroup //
|
wg sync.WaitGroup //
|
||||||
quit chan struct{} // shutdown signal, closed in Stop.
|
quit chan struct{} // shutdown signal, closed in Stop.
|
||||||
|
|
@ -226,6 +229,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
|
||||||
blockCache, _ := lru.New(blockCacheLimit)
|
blockCache, _ := lru.New(blockCacheLimit)
|
||||||
txLookupCache, _ := lru.New(txLookupCacheLimit)
|
txLookupCache, _ := lru.New(txLookupCacheLimit)
|
||||||
futureBlocks, _ := lru.New(maxFutureBlocks)
|
futureBlocks, _ := lru.New(maxFutureBlocks)
|
||||||
|
blockResultCache, _ := lru.New(blockResultCacheLimit)
|
||||||
|
|
||||||
bc := &BlockChain{
|
bc := &BlockChain{
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
|
|
@ -237,17 +241,18 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
|
||||||
Journal: cacheConfig.TrieCleanJournal,
|
Journal: cacheConfig.TrieCleanJournal,
|
||||||
Preimages: cacheConfig.Preimages,
|
Preimages: cacheConfig.Preimages,
|
||||||
}),
|
}),
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
chainmu: syncx.NewClosableMutex(),
|
chainmu: syncx.NewClosableMutex(),
|
||||||
shouldPreserve: shouldPreserve,
|
shouldPreserve: shouldPreserve,
|
||||||
bodyCache: bodyCache,
|
bodyCache: bodyCache,
|
||||||
bodyRLPCache: bodyRLPCache,
|
bodyRLPCache: bodyRLPCache,
|
||||||
receiptsCache: receiptsCache,
|
receiptsCache: receiptsCache,
|
||||||
blockCache: blockCache,
|
blockCache: blockCache,
|
||||||
txLookupCache: txLookupCache,
|
txLookupCache: txLookupCache,
|
||||||
futureBlocks: futureBlocks,
|
futureBlocks: futureBlocks,
|
||||||
engine: engine,
|
blockResultCache: blockResultCache,
|
||||||
vmConfig: vmConfig,
|
engine: engine,
|
||||||
|
vmConfig: vmConfig,
|
||||||
}
|
}
|
||||||
bc.validator = NewBlockValidator(chainConfig, bc, engine)
|
bc.validator = NewBlockValidator(chainConfig, bc, engine)
|
||||||
bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine)
|
bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine)
|
||||||
|
|
@ -1215,7 +1220,6 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
||||||
rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd)
|
rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd)
|
||||||
rawdb.WriteBlock(blockBatch, block)
|
rawdb.WriteBlock(blockBatch, block)
|
||||||
rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts)
|
rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts)
|
||||||
rawdb.WriteBlockResult(blockBatch, block.Hash(), blockResult)
|
|
||||||
rawdb.WritePreimages(blockBatch, state.Preimages())
|
rawdb.WritePreimages(blockBatch, state.Preimages())
|
||||||
if err := blockBatch.Write(); err != nil {
|
if err := blockBatch.Write(); err != nil {
|
||||||
log.Crit("Failed to write block into disk", "err", err)
|
log.Crit("Failed to write block into disk", "err", err)
|
||||||
|
|
@ -1314,6 +1318,12 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
||||||
}
|
}
|
||||||
bc.futureBlocks.Remove(block.Hash())
|
bc.futureBlocks.Remove(block.Hash())
|
||||||
|
|
||||||
|
// Fill blockResult content
|
||||||
|
if blockResult != nil {
|
||||||
|
bc.writeBlockResult(state, block, blockResult)
|
||||||
|
bc.blockResultCache.Add(block.Hash(), blockResult)
|
||||||
|
}
|
||||||
|
|
||||||
if status == CanonStatTy {
|
if status == CanonStatTy {
|
||||||
bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs, BlockResult: blockResult})
|
bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs, BlockResult: blockResult})
|
||||||
if len(logs) > 0 {
|
if len(logs) > 0 {
|
||||||
|
|
@ -1333,6 +1343,35 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
||||||
return status, nil
|
return status, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fill blockResult content
|
||||||
|
func (bc *BlockChain) writeBlockResult(state *state.StateDB, block *types.Block, blockResult *types.BlockResult) {
|
||||||
|
blockResult.BlockTrace = types.NewTraceBlock(bc.chainConfig, block)
|
||||||
|
for i, tx := range block.Transactions() {
|
||||||
|
evmTrace := blockResult.ExecutionResults[i]
|
||||||
|
// Get the sender's address.
|
||||||
|
from, _ := types.Sender(types.MakeSigner(bc.chainConfig, block.Number()), tx)
|
||||||
|
// Get account's 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))
|
||||||
|
for i := range proof {
|
||||||
|
evmTrace.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()))
|
||||||
|
// Get tx.to address's code hash.
|
||||||
|
codeHash := state.GetCodeHash(*tx.To())
|
||||||
|
evmTrace.CodeHash = &codeHash
|
||||||
|
} else if tx.To() == nil { // Contract is created.
|
||||||
|
evmTrace.ByteCode = hexutil.Encode(tx.Data())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// addFutureBlock checks if the block is within the max allowed window to get
|
// addFutureBlock checks if the block is within the max allowed window to get
|
||||||
// accepted for future processing, and returns an error if the block is too far
|
// accepted for future processing, and returns an error if the block is too far
|
||||||
// ahead and was not added.
|
// ahead and was not added.
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,13 @@ func (bc *BlockChain) GetBlockByHash(hash common.Hash) *types.Block {
|
||||||
return bc.GetBlock(hash, *number)
|
return bc.GetBlock(hash, *number)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bc *BlockChain) GetBlockResultByHash(blockHash common.Hash) *types.BlockResult {
|
||||||
|
if blockResult, ok := bc.blockResultCache.Get(blockHash); ok {
|
||||||
|
return blockResult.(*types.BlockResult)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetBlockByNumber retrieves a block from the database by number, caching it
|
// GetBlockByNumber retrieves a block from the database by number, caching it
|
||||||
// (associated with its hash) if found.
|
// (associated with its hash) if found.
|
||||||
func (bc *BlockChain) GetBlockByNumber(number uint64) *types.Block {
|
func (bc *BlockChain) GetBlockByNumber(number uint64) *types.Block {
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
|
||||||
func NewEVMTxContext(msg Message) vm.TxContext {
|
func NewEVMTxContext(msg Message) vm.TxContext {
|
||||||
return vm.TxContext{
|
return vm.TxContext{
|
||||||
Origin: msg.From(),
|
Origin: msg.From(),
|
||||||
|
To: msg.To(),
|
||||||
GasPrice: new(big.Int).Set(msg.GasPrice()),
|
GasPrice: new(big.Int).Set(msg.GasPrice()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
package rawdb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/scroll-tech/go-ethereum/common"
|
|
||||||
"github.com/scroll-tech/go-ethereum/core/types"
|
|
||||||
"github.com/scroll-tech/go-ethereum/ethdb"
|
|
||||||
"github.com/scroll-tech/go-ethereum/log"
|
|
||||||
"github.com/scroll-tech/go-ethereum/rlp"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ReadBlockResult retrieves all data required by roller.
|
|
||||||
func ReadBlockResult(db ethdb.Reader, hash common.Hash) *types.BlockResult {
|
|
||||||
data, _ := db.Get(blockResultKey(hash))
|
|
||||||
if len(data) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var blockResult types.BlockResult
|
|
||||||
if err := rlp.DecodeBytes(data, &blockResult); err != nil {
|
|
||||||
log.Error("Failed to decode BlockResult", "err", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &blockResult
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteBlockResult stores blockResult into leveldb.
|
|
||||||
func WriteBlockResult(db ethdb.KeyValueWriter, hash common.Hash, blockResult *types.BlockResult) {
|
|
||||||
bytes, err := rlp.EncodeToBytes(blockResult)
|
|
||||||
if err != nil {
|
|
||||||
log.Crit("Failed to RLP encode BlockResult", "err", err)
|
|
||||||
}
|
|
||||||
db.Put(blockResultKey(hash), bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteBlockResult removes blockResult with a block hash.
|
|
||||||
func DeleteBlockResult(db ethdb.KeyValueWriter, hash common.Hash) {
|
|
||||||
if err := db.Delete(blockResultKey(hash)); err != nil {
|
|
||||||
log.Crit("Failed to delete BlockResult", "err", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,355 +0,0 @@
|
||||||
package rawdb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/scroll-tech/go-ethereum/common"
|
|
||||||
"github.com/scroll-tech/go-ethereum/core/types"
|
|
||||||
"github.com/scroll-tech/go-ethereum/rlp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestBlockEvmTracesStorage(t *testing.T) {
|
|
||||||
db := NewMemoryDatabase()
|
|
||||||
|
|
||||||
data1 := []byte(`{
|
|
||||||
"gas": 1,
|
|
||||||
"failed": false,
|
|
||||||
"returnValue": "",
|
|
||||||
"structLogs": [
|
|
||||||
{
|
|
||||||
"pc": 0,
|
|
||||||
"op": "PUSH1",
|
|
||||||
"gas": 1000000,
|
|
||||||
"gasCost": 3,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [],
|
|
||||||
"memory": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 2,
|
|
||||||
"op": "SLOAD",
|
|
||||||
"gas": 999997,
|
|
||||||
"gasCost": 2100,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [
|
|
||||||
"0x1"
|
|
||||||
],
|
|
||||||
"memory": [],
|
|
||||||
"storage": {
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000001": "0000000000000000000000000000000000000000000000000000000000000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 3,
|
|
||||||
"op": "POP",
|
|
||||||
"gas": 997897,
|
|
||||||
"gasCost": 2,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [
|
|
||||||
"0x0"
|
|
||||||
],
|
|
||||||
"memory": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 4,
|
|
||||||
"op": "PUSH1",
|
|
||||||
"gas": 997895,
|
|
||||||
"gasCost": 3,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [],
|
|
||||||
"memory": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 6,
|
|
||||||
"op": "PUSH1",
|
|
||||||
"gas": 997892,
|
|
||||||
"gasCost": 3,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [
|
|
||||||
"0x11"
|
|
||||||
],
|
|
||||||
"memory": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 8,
|
|
||||||
"op": "SSTORE",
|
|
||||||
"gas": 997889,
|
|
||||||
"gasCost": 20000,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [
|
|
||||||
"0x11",
|
|
||||||
"0x1"
|
|
||||||
],
|
|
||||||
"memory": [],
|
|
||||||
"storage": {
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000001": "0000000000000000000000000000000000000000000000000000000000000011"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 9,
|
|
||||||
"op": "PUSH1",
|
|
||||||
"gas": 977889,
|
|
||||||
"gasCost": 3,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [],
|
|
||||||
"memory": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 11,
|
|
||||||
"op": "PUSH1",
|
|
||||||
"gas": 977886,
|
|
||||||
"gasCost": 3,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [
|
|
||||||
"0x11"
|
|
||||||
],
|
|
||||||
"memory": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 13,
|
|
||||||
"op": "SSTORE",
|
|
||||||
"gas": 977883,
|
|
||||||
"gasCost": 22100,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [
|
|
||||||
"0x11",
|
|
||||||
"0x2"
|
|
||||||
],
|
|
||||||
"memory": [],
|
|
||||||
"storage": {
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000001": "0000000000000000000000000000000000000000000000000000000000000011",
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000002": "0000000000000000000000000000000000000000000000000000000000000011"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 14,
|
|
||||||
"op": "PUSH1",
|
|
||||||
"gas": 955783,
|
|
||||||
"gasCost": 3,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [],
|
|
||||||
"memory": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 16,
|
|
||||||
"op": "PUSH1",
|
|
||||||
"gas": 955780,
|
|
||||||
"gasCost": 3,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [
|
|
||||||
"0x11"
|
|
||||||
],
|
|
||||||
"memory": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 18,
|
|
||||||
"op": "SSTORE",
|
|
||||||
"gas": 955777,
|
|
||||||
"gasCost": 100,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [
|
|
||||||
"0x11",
|
|
||||||
"0x2"
|
|
||||||
],
|
|
||||||
"memory": [],
|
|
||||||
"storage": {
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000001": "0000000000000000000000000000000000000000000000000000000000000011",
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000002": "0000000000000000000000000000000000000000000000000000000000000011"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 19,
|
|
||||||
"op": "PUSH1",
|
|
||||||
"gas": 955677,
|
|
||||||
"gasCost": 3,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [],
|
|
||||||
"memory": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 21,
|
|
||||||
"op": "SLOAD",
|
|
||||||
"gas": 955674,
|
|
||||||
"gasCost": 100,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [
|
|
||||||
"0x2"
|
|
||||||
],
|
|
||||||
"memory": [],
|
|
||||||
"storage": {
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000001": "0000000000000000000000000000000000000000000000000000000000000011",
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000002": "0000000000000000000000000000000000000000000000000000000000000011"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 22,
|
|
||||||
"op": "PUSH1",
|
|
||||||
"gas": 955574,
|
|
||||||
"gasCost": 3,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [
|
|
||||||
"0x11"
|
|
||||||
],
|
|
||||||
"memory": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 24,
|
|
||||||
"op": "SLOAD",
|
|
||||||
"gas": 955571,
|
|
||||||
"gasCost": 100,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [
|
|
||||||
"0x11",
|
|
||||||
"0x1"
|
|
||||||
],
|
|
||||||
"memory": [],
|
|
||||||
"storage": {
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000001": "0000000000000000000000000000000000000000000000000000000000000011",
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000002": "0000000000000000000000000000000000000000000000000000000000000011"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 25,
|
|
||||||
"op": "STOP",
|
|
||||||
"gas": 955471,
|
|
||||||
"gasCost": 0,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [
|
|
||||||
"0x11",
|
|
||||||
"0x11"
|
|
||||||
],
|
|
||||||
"memory": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}`)
|
|
||||||
evmTrace1 := &types.ExecutionResult{ReturnValue: "0xaaa"}
|
|
||||||
if err := json.Unmarshal(data1, evmTrace1); err != nil {
|
|
||||||
t.Fatalf(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
data2 := []byte(`{
|
|
||||||
"gas": 1,
|
|
||||||
"failed": false,
|
|
||||||
"returnValue": "000000000000000000000000000000000000000000000000000000000000000a",
|
|
||||||
"structLogs": [
|
|
||||||
{
|
|
||||||
"pc": 0,
|
|
||||||
"op": "PUSH1",
|
|
||||||
"gas": 1000000,
|
|
||||||
"gasCost": 3,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [],
|
|
||||||
"memory": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 2,
|
|
||||||
"op": "PUSH1",
|
|
||||||
"gas": 999997,
|
|
||||||
"gasCost": 3,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [
|
|
||||||
"0xa"
|
|
||||||
],
|
|
||||||
"memory": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 4,
|
|
||||||
"op": "MSTORE",
|
|
||||||
"gas": 999994,
|
|
||||||
"gasCost": 6,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [
|
|
||||||
"0xa",
|
|
||||||
"0x0"
|
|
||||||
],
|
|
||||||
"memory": [
|
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 5,
|
|
||||||
"op": "PUSH1",
|
|
||||||
"gas": 999988,
|
|
||||||
"gasCost": 3,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [],
|
|
||||||
"memory": [
|
|
||||||
"000000000000000000000000000000000000000000000000000000000000000a"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 7,
|
|
||||||
"op": "PUSH1",
|
|
||||||
"gas": 999985,
|
|
||||||
"gasCost": 3,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [
|
|
||||||
"0x20"
|
|
||||||
],
|
|
||||||
"memory": [
|
|
||||||
"000000000000000000000000000000000000000000000000000000000000000a"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pc": 9,
|
|
||||||
"op": "RETURN",
|
|
||||||
"gas": 999982,
|
|
||||||
"gasCost": 0,
|
|
||||||
"depth": 1,
|
|
||||||
"stack": [
|
|
||||||
"0x20",
|
|
||||||
"0x0"
|
|
||||||
],
|
|
||||||
"memory": [
|
|
||||||
"000000000000000000000000000000000000000000000000000000000000000a"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}`)
|
|
||||||
evmTrace2 := &types.ExecutionResult{ReturnValue: "0xbbb"}
|
|
||||||
if err := json.Unmarshal(data2, evmTrace2); err != nil {
|
|
||||||
t.Fatalf(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
evmTraces := []*types.ExecutionResult{evmTrace1, evmTrace2}
|
|
||||||
hash := common.BytesToHash([]byte{0x03, 0x04})
|
|
||||||
// Insert the blockResult into the database and check presence.
|
|
||||||
WriteBlockResult(db, hash, &types.BlockResult{ExecutionResults: evmTraces})
|
|
||||||
// Read blockResult from db.
|
|
||||||
if blockResult := ReadBlockResult(db, hash); len(blockResult.ExecutionResults) == 0 {
|
|
||||||
t.Fatalf("No evmTraces returned")
|
|
||||||
} else {
|
|
||||||
if err := checkEvmTracesRLP(blockResult.ExecutionResults, evmTraces); err != nil {
|
|
||||||
t.Fatalf(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Delete blockResult by blockHash.
|
|
||||||
DeleteBlockResult(db, hash)
|
|
||||||
if blockResult := ReadBlockResult(db, hash); blockResult != nil && len(blockResult.ExecutionResults) != 0 {
|
|
||||||
t.Fatalf("The evmTrace list should be empty.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkEvmTracesRLP(have, want []*types.ExecutionResult) error {
|
|
||||||
if len(have) != len(want) {
|
|
||||||
return fmt.Errorf("evmTraces sizes mismatch: have: %d, want: %d", len(have), len(want))
|
|
||||||
}
|
|
||||||
for i := 0; i < len(want); i++ {
|
|
||||||
rlpHave, err := rlp.EncodeToBytes(have[i])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rlpWant, err := rlp.EncodeToBytes(want[i])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !bytes.Equal(rlpHave, rlpWant) {
|
|
||||||
return fmt.Errorf("evmTrace #%d: evmTrace mismatch: have %s, want %s", i, hex.EncodeToString(rlpHave), hex.EncodeToString(rlpWant))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
@ -89,7 +89,6 @@ var (
|
||||||
SnapshotAccountPrefix = []byte("a") // SnapshotAccountPrefix + account hash -> account trie value
|
SnapshotAccountPrefix = []byte("a") // SnapshotAccountPrefix + account hash -> account trie value
|
||||||
SnapshotStoragePrefix = []byte("o") // SnapshotStoragePrefix + account hash + storage hash -> storage trie value
|
SnapshotStoragePrefix = []byte("o") // SnapshotStoragePrefix + account hash + storage hash -> storage trie value
|
||||||
CodePrefix = []byte("c") // CodePrefix + code hash -> account code
|
CodePrefix = []byte("c") // CodePrefix + code hash -> account code
|
||||||
blockResultPrefix = []byte("T") // blockResultPrefix + hash -> blockResult
|
|
||||||
|
|
||||||
PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage
|
PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage
|
||||||
configPrefix = []byte("ethereum-config-") // config prefix for the db
|
configPrefix = []byte("ethereum-config-") // config prefix for the db
|
||||||
|
|
@ -231,8 +230,3 @@ func IsCodeKey(key []byte) (bool, []byte) {
|
||||||
func configKey(hash common.Hash) []byte {
|
func configKey(hash common.Hash) []byte {
|
||||||
return append(configPrefix, hash.Bytes()...)
|
return append(configPrefix, hash.Bytes()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// blockResultKey = blockResultPrefix + hash
|
|
||||||
func blockResultKey(hash common.Hash) []byte {
|
|
||||||
return append(blockResultPrefix, hash.Bytes()...)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,165 +1,80 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"github.com/scroll-tech/go-ethereum/common"
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/scroll-tech/go-ethereum/rlp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// BlockResult contains block execution traces and results required for rollers.
|
// BlockResult contains block execution traces and results required for rollers.
|
||||||
type BlockResult struct {
|
type BlockResult struct {
|
||||||
|
BlockTrace *BlockTrace `json:"blockTrace"`
|
||||||
ExecutionResults []*ExecutionResult `json:"executionResults"`
|
ExecutionResults []*ExecutionResult `json:"executionResults"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type rlpBlockResult struct {
|
|
||||||
ExecutionResults []*ExecutionResult
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BlockResult) EncodeRLP(w io.Writer) error {
|
|
||||||
return rlp.Encode(w, &rlpBlockResult{
|
|
||||||
ExecutionResults: b.ExecutionResults,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BlockResult) DecodeRLP(s *rlp.Stream) error {
|
|
||||||
var dec rlpBlockResult
|
|
||||||
err := s.Decode(&dec)
|
|
||||||
if err == nil {
|
|
||||||
b.ExecutionResults = dec.ExecutionResults
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExecutionResult groups all structured logs emitted by the EVM
|
// ExecutionResult groups all structured logs emitted by the EVM
|
||||||
// while replaying a transaction in debug mode as well as transaction
|
// while replaying a transaction in debug mode as well as transaction
|
||||||
// execution status, the amount of gas used and the return value
|
// execution status, the amount of gas used and the return value
|
||||||
type ExecutionResult struct {
|
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"`
|
||||||
StructLogs []StructLogRes `json:"structLogs"`
|
// 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.
|
||||||
type rlpExecutionResult struct {
|
ByteCode string `json:"byteCode,omitempty"`
|
||||||
Gas uint64
|
// The account's proof.
|
||||||
Failed bool
|
Proof []string `json:"proof,omitempty"`
|
||||||
ReturnValue string
|
StructLogs []StructLogRes `json:"structLogs"`
|
||||||
StructLogs []StructLogRes
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ExecutionResult) EncodeRLP(w io.Writer) error {
|
|
||||||
return rlp.Encode(w, rlpExecutionResult{
|
|
||||||
Gas: e.Gas,
|
|
||||||
Failed: e.Failed,
|
|
||||||
ReturnValue: e.ReturnValue,
|
|
||||||
StructLogs: e.StructLogs,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ExecutionResult) DecodeRLP(s *rlp.Stream) error {
|
|
||||||
var dec rlpExecutionResult
|
|
||||||
err := s.Decode(&dec)
|
|
||||||
if err == nil {
|
|
||||||
e.Gas, e.Failed, e.ReturnValue, e.StructLogs = dec.Gas, dec.Failed, dec.ReturnValue, dec.StructLogs
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructLogRes stores a structured log emitted by the EVM while replaying a
|
// StructLogRes stores a structured log emitted by the EVM while replaying a
|
||||||
// transaction in debug mode
|
// transaction in debug mode
|
||||||
type StructLogRes struct {
|
type StructLogRes struct {
|
||||||
Pc uint64 `json:"pc"`
|
Pc uint64 `json:"pc"`
|
||||||
Op string `json:"op"`
|
Op string `json:"op"`
|
||||||
Gas uint64 `json:"gas"`
|
Gas uint64 `json:"gas"`
|
||||||
GasCost uint64 `json:"gasCost"`
|
GasCost uint64 `json:"gasCost"`
|
||||||
Depth int `json:"depth"`
|
Depth int `json:"depth"`
|
||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
Stack *[]string `json:"stack,omitempty"`
|
Stack *[]string `json:"stack,omitempty"`
|
||||||
Memory *[]string `json:"memory,omitempty"`
|
Memory *[]string `json:"memory,omitempty"`
|
||||||
Storage *map[string]string `json:"storage,omitempty"`
|
Storage *map[string]string `json:"storage,omitempty"`
|
||||||
|
ExtraData *ExtraData `json:"extraData,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type rlpStructLogRes struct {
|
type ExtraData struct {
|
||||||
Pc uint64
|
// CREATE | CREATE2: sender address
|
||||||
Op string
|
From *common.Address `json:"from,omitempty"`
|
||||||
Gas uint64
|
// CREATE: sender nonce
|
||||||
GasCost uint64
|
Nonce *uint64 `json:"nonce,omitempty"`
|
||||||
Depth uint
|
// CALL | CALLCODE | DELEGATECALL | STATICCALL: [tx.to address’s code_hash, stack.nth_last(1) address’s code_hash]
|
||||||
Error string
|
CodeHashList []common.Hash `json:"codeHashList,omitempty"`
|
||||||
Stack []string
|
// SSTORE | SLOAD: [storageProof]
|
||||||
Memory []string
|
// SELFDESTRUCT: [contract address’s accountProof, stack.nth_last(0) address’s accountProof]
|
||||||
Storage []string
|
// SELFBALANCE: [contract address’s accountProof]
|
||||||
|
// BALANCE | EXTCODEHASH: [stack.nth_last(0) address’s accountProof]
|
||||||
|
// CREATE | CREATE2: [created contract address’s accountProof]
|
||||||
|
// CALL | CALLCODE: [caller contract address’s accountProof, stack.nth_last(1) address’s accountProof]
|
||||||
|
ProofList [][]string `json:"proofList,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeRLP implements rlp.Encoder.
|
// NewExtraData create, init and return ExtraData
|
||||||
func (r *StructLogRes) EncodeRLP(w io.Writer) error {
|
func NewExtraData() *ExtraData {
|
||||||
data := rlpStructLogRes{
|
return &ExtraData{
|
||||||
Pc: r.Pc,
|
CodeHashList: make([]common.Hash, 0),
|
||||||
Op: r.Op,
|
ProofList: make([][]string, 0),
|
||||||
Gas: r.Gas,
|
|
||||||
GasCost: r.GasCost,
|
|
||||||
Depth: uint(r.Depth),
|
|
||||||
Error: r.Error,
|
|
||||||
}
|
}
|
||||||
if r.Stack != nil {
|
|
||||||
data.Stack = make([]string, len(*r.Stack))
|
|
||||||
for i, val := range *r.Stack {
|
|
||||||
data.Stack[i] = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if r.Memory != nil {
|
|
||||||
data.Memory = make([]string, len(*r.Memory))
|
|
||||||
for i, val := range *r.Memory {
|
|
||||||
data.Memory[i] = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if r.Storage != nil {
|
|
||||||
keys := make([]string, 0, len(*r.Storage))
|
|
||||||
for key := range *r.Storage {
|
|
||||||
keys = append(keys, key)
|
|
||||||
}
|
|
||||||
sort.Slice(keys, func(i, j int) bool {
|
|
||||||
return strings.Compare(keys[i], keys[j]) >= 0
|
|
||||||
})
|
|
||||||
data.Storage = make([]string, 0, len(*r.Storage)*2)
|
|
||||||
for _, key := range keys {
|
|
||||||
data.Storage = append(data.Storage, []string{key, (*r.Storage)[key]}...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rlp.Encode(w, data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeRLP implements rlp.Decoder.
|
// SealExtraData doesn't show empty fields.
|
||||||
func (r *StructLogRes) DecodeRLP(s *rlp.Stream) error {
|
func (e *ExtraData) SealExtraData() *ExtraData {
|
||||||
var dec rlpStructLogRes
|
if len(e.CodeHashList) == 0 {
|
||||||
err := s.Decode(&dec)
|
e.CodeHashList = nil
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
r.Pc, r.Op, r.Gas, r.GasCost, r.Depth, r.Error = dec.Pc, dec.Op, dec.Gas, dec.GasCost, int(dec.Depth), dec.Error
|
if len(e.ProofList) == 0 {
|
||||||
if len(dec.Stack) != 0 {
|
e.ProofList = nil
|
||||||
stack := make([]string, len(dec.Stack))
|
|
||||||
for i, val := range dec.Stack {
|
|
||||||
stack[i] = val
|
|
||||||
}
|
|
||||||
r.Stack = &stack
|
|
||||||
}
|
}
|
||||||
if len(dec.Memory) != 0 {
|
if e.From == nil && e.Nonce == nil && e.CodeHashList == nil && e.ProofList == nil {
|
||||||
memory := make([]string, len(dec.Memory))
|
return nil
|
||||||
for i, val := range dec.Memory {
|
|
||||||
memory[i] = val
|
|
||||||
}
|
|
||||||
r.Memory = &memory
|
|
||||||
}
|
}
|
||||||
if len(dec.Storage) != 0 {
|
return e
|
||||||
storage := make(map[string]string, len(dec.Storage)*2)
|
|
||||||
for i := 0; i < len(dec.Storage); i += 2 {
|
|
||||||
key, val := dec.Storage[i], dec.Storage[i+1]
|
|
||||||
storage[key] = val
|
|
||||||
}
|
|
||||||
r.Storage = &storage
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
78
core/types/l2trace_block.go
Normal file
78
core/types/l2trace_block.go
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/scroll-tech/go-ethereum/common"
|
||||||
|
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
||||||
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BlockTrace struct {
|
||||||
|
Number *big.Int `json:"number"`
|
||||||
|
Hash common.Hash `json:"hash"`
|
||||||
|
GasLimit uint64 `json:"gasLimit"`
|
||||||
|
Difficulty *big.Int `json:"difficulty"`
|
||||||
|
BaseFee *big.Int `json:"baseFee"`
|
||||||
|
Coinbase common.Address `json:"coinbase"`
|
||||||
|
Time uint64 `json:"time"`
|
||||||
|
Transaction []*TransactionTrace `json:"transaction"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TransactionTrace struct {
|
||||||
|
Type uint8 `json:"type"`
|
||||||
|
Nonce uint64 `json:"nonce"`
|
||||||
|
Gas uint64 `json:"gas"`
|
||||||
|
GasPrice *big.Int `json:"gasPrice"`
|
||||||
|
From common.Address `json:"from"`
|
||||||
|
To *common.Address `json:"to"`
|
||||||
|
ChainId *big.Int `json:"chainId"`
|
||||||
|
Value *big.Int `json:"value"`
|
||||||
|
Data string `json:"data"`
|
||||||
|
IsCreate bool `json:"isCreate"`
|
||||||
|
V *big.Int `json:"v"`
|
||||||
|
R *big.Int `json:"r"`
|
||||||
|
S *big.Int `json:"s"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTraceBlock supports necessary fields for roller.
|
||||||
|
func NewTraceBlock(config *params.ChainConfig, block *Block) *BlockTrace {
|
||||||
|
txs := make([]*TransactionTrace, block.Transactions().Len())
|
||||||
|
for i, tx := range block.Transactions() {
|
||||||
|
txs[i] = newTraceTransaction(tx, block.NumberU64(), config)
|
||||||
|
}
|
||||||
|
return &BlockTrace{
|
||||||
|
Number: block.Number(),
|
||||||
|
Hash: block.Hash(),
|
||||||
|
GasLimit: block.GasLimit(),
|
||||||
|
Difficulty: block.Difficulty(),
|
||||||
|
BaseFee: block.BaseFee(),
|
||||||
|
Coinbase: block.Coinbase(),
|
||||||
|
Time: block.Time(),
|
||||||
|
Transaction: txs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// newTraceTransaction returns a transaction that will serialize to the trace
|
||||||
|
// representation, with the given location metadata set (if available).
|
||||||
|
func newTraceTransaction(tx *Transaction, blockNumber uint64, config *params.ChainConfig) *TransactionTrace {
|
||||||
|
signer := MakeSigner(config, big.NewInt(0).SetUint64(blockNumber))
|
||||||
|
from, _ := Sender(signer, tx)
|
||||||
|
v, r, s := tx.RawSignatureValues()
|
||||||
|
result := &TransactionTrace{
|
||||||
|
Type: tx.Type(),
|
||||||
|
Nonce: tx.Nonce(),
|
||||||
|
ChainId: tx.ChainId(),
|
||||||
|
From: from,
|
||||||
|
Gas: tx.Gas(),
|
||||||
|
GasPrice: tx.GasPrice(),
|
||||||
|
To: tx.To(),
|
||||||
|
Value: tx.Value(),
|
||||||
|
Data: hexutil.Encode(tx.Data()),
|
||||||
|
IsCreate: tx.To() == nil,
|
||||||
|
V: v,
|
||||||
|
R: r,
|
||||||
|
S: s,
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
@ -161,6 +161,10 @@ func (a *AccessListTracer) CaptureState(pc uint64, op OpCode, gas, cost uint64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CaptureStateAfter for special needs, tracks SSTORE ops and records the storage change.
|
||||||
|
func (*AccessListTracer) CaptureStateAfter(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
||||||
|
}
|
||||||
|
|
||||||
func (*AccessListTracer) CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
|
func (*AccessListTracer) CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,8 +81,9 @@ type BlockContext struct {
|
||||||
// All fields can change between transactions.
|
// All fields can change between transactions.
|
||||||
type TxContext struct {
|
type TxContext struct {
|
||||||
// Message information
|
// Message information
|
||||||
Origin common.Address // Provides information for ORIGIN
|
Origin common.Address // Provides information for ORIGIN
|
||||||
GasPrice *big.Int // Provides information for GASPRICE
|
To *common.Address // Provides information for trace
|
||||||
|
GasPrice *big.Int // Provides information for GASPRICE
|
||||||
}
|
}
|
||||||
|
|
||||||
// EVM is the Ethereum Virtual Machine base object and provides
|
// EVM is the Ethereum Virtual Machine base object and provides
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,10 @@ type StateDB interface {
|
||||||
GetState(common.Address, common.Hash) common.Hash
|
GetState(common.Address, common.Hash) common.Hash
|
||||||
SetState(common.Address, common.Hash, common.Hash)
|
SetState(common.Address, common.Hash, common.Hash)
|
||||||
|
|
||||||
|
GetProof(addr common.Address) ([][]byte, error)
|
||||||
|
GetProofByHash(addrHash common.Hash) ([][]byte, error)
|
||||||
|
GetStorageProof(a common.Address, key common.Hash) ([][]byte, error)
|
||||||
|
|
||||||
Suicide(common.Address) bool
|
Suicide(common.Address) bool
|
||||||
HasSuicided(common.Address) bool
|
HasSuicided(common.Address) bool
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -265,6 +265,10 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
in.returnData = res
|
in.returnData = res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if in.cfg.Debug {
|
||||||
|
in.cfg.Tracer.CaptureStateAfter(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
||||||
"github.com/scroll-tech/go-ethereum/common/math"
|
"github.com/scroll-tech/go-ethereum/common/math"
|
||||||
"github.com/scroll-tech/go-ethereum/core/types"
|
"github.com/scroll-tech/go-ethereum/core/types"
|
||||||
|
"github.com/scroll-tech/go-ethereum/log"
|
||||||
"github.com/scroll-tech/go-ethereum/params"
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -72,6 +73,7 @@ type StructLog struct {
|
||||||
Storage map[common.Hash]common.Hash `json:"-"`
|
Storage map[common.Hash]common.Hash `json:"-"`
|
||||||
Depth int `json:"depth"`
|
Depth int `json:"depth"`
|
||||||
RefundCounter uint64 `json:"refund"`
|
RefundCounter uint64 `json:"refund"`
|
||||||
|
ExtraData *types.ExtraData `json:"extraData"`
|
||||||
Err error `json:"-"`
|
Err error `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,6 +108,7 @@ func (s *StructLog) ErrorString() string {
|
||||||
type EVMLogger interface {
|
type EVMLogger interface {
|
||||||
CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int)
|
CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int)
|
||||||
CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error)
|
CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error)
|
||||||
|
CaptureStateAfter(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error)
|
||||||
CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int)
|
CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int)
|
||||||
CaptureExit(output []byte, gasUsed uint64, err error)
|
CaptureExit(output []byte, gasUsed uint64, err error)
|
||||||
CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error)
|
CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error)
|
||||||
|
|
@ -177,7 +180,10 @@ func (l *StructLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Copy a snapshot of the current storage to a new container
|
// Copy a snapshot of the current storage to a new container
|
||||||
var storage Storage
|
var (
|
||||||
|
storage Storage
|
||||||
|
extraData *types.ExtraData
|
||||||
|
)
|
||||||
if !l.cfg.DisableStorage && (op == SLOAD || op == SSTORE) {
|
if !l.cfg.DisableStorage && (op == SLOAD || op == SSTORE) {
|
||||||
// initialise new changed values storage container for this contract
|
// initialise new changed values storage container for this contract
|
||||||
// if not present.
|
// if not present.
|
||||||
|
|
@ -200,6 +206,11 @@ 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var rdata []byte
|
var rdata []byte
|
||||||
|
|
@ -207,8 +218,32 @@ func (l *StructLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scop
|
||||||
rdata = make([]byte, len(rData))
|
rdata = make([]byte, len(rData))
|
||||||
copy(rdata, rData)
|
copy(rdata, rData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a new snapshot of the EVM.
|
// create a new snapshot of the EVM.
|
||||||
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err}
|
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), extraData, err}
|
||||||
|
l.logs = append(l.logs, log)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaptureStateAfter for special needs, tracks SSTORE ops and records the storage change.
|
||||||
|
func (l *StructLogger) CaptureStateAfter(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
||||||
|
// check if already accumulated the specified number of logs
|
||||||
|
if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
execFuncList, ok := OpcodeExecs[op]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
extraData := types.NewExtraData()
|
||||||
|
// execute trace func list.
|
||||||
|
for _, exec := range execFuncList {
|
||||||
|
if err = exec(l, scope, extraData); err != nil {
|
||||||
|
log.Error("Failed to trace data", "opcode", op.String(), "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log := StructLog{pc, op, gas, cost, nil, scope.Memory.Len(), nil, nil, nil, depth, l.env.StateDB.GetRefund(), extraData, err}
|
||||||
l.logs = append(l.logs, log)
|
l.logs = append(l.logs, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -345,6 +380,10 @@ func (t *mdLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *S
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CaptureStateAfter for special needs, tracks SSTORE ops and records the storage change.
|
||||||
|
func (t *mdLogger) CaptureStateAfter(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
||||||
|
}
|
||||||
|
|
||||||
func (t *mdLogger) CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
|
func (t *mdLogger) CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
|
||||||
fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err)
|
fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err)
|
||||||
}
|
}
|
||||||
|
|
@ -371,27 +410,31 @@ func FormatLogs(logs []StructLog) []types.StructLogRes {
|
||||||
Depth: trace.Depth,
|
Depth: trace.Depth,
|
||||||
Error: trace.ErrorString(),
|
Error: trace.ErrorString(),
|
||||||
}
|
}
|
||||||
if trace.Stack != nil {
|
if len(trace.Stack) != 0 {
|
||||||
stack := make([]string, len(trace.Stack))
|
stack := make([]string, len(trace.Stack))
|
||||||
for i, stackValue := range trace.Stack {
|
for i, stackValue := range trace.Stack {
|
||||||
stack[i] = stackValue.Hex()
|
stack[i] = stackValue.Hex()
|
||||||
}
|
}
|
||||||
formatted[index].Stack = &stack
|
formatted[index].Stack = &stack
|
||||||
}
|
}
|
||||||
if trace.Memory != nil {
|
if len(trace.Memory) != 0 {
|
||||||
memory := make([]string, 0, (len(trace.Memory)+31)/32)
|
memory := make([]string, 0, (len(trace.Memory)+31)/32)
|
||||||
for i := 0; i+32 <= len(trace.Memory); i += 32 {
|
for i := 0; i+32 <= len(trace.Memory); i += 32 {
|
||||||
memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:i+32]))
|
bytes := new(big.Int).SetBytes(trace.Memory[i : i+32]).Bytes()
|
||||||
|
memory = append(memory, hexutil.Encode(bytes))
|
||||||
}
|
}
|
||||||
formatted[index].Memory = &memory
|
formatted[index].Memory = &memory
|
||||||
}
|
}
|
||||||
if trace.Storage != nil {
|
if len(trace.Storage) != 0 {
|
||||||
storage := make(map[string]string)
|
storage := make(map[string]string)
|
||||||
for i, storageValue := range trace.Storage {
|
for i, storageValue := range trace.Storage {
|
||||||
storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue)
|
storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue)
|
||||||
}
|
}
|
||||||
formatted[index].Storage = &storage
|
formatted[index].Storage = &storage
|
||||||
}
|
}
|
||||||
|
if trace.ExtraData != nil {
|
||||||
|
formatted[index].ExtraData = trace.ExtraData.SealExtraData()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return formatted
|
return formatted
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,10 @@ func (l *JSONLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scope
|
||||||
l.encoder.Encode(log)
|
l.encoder.Encode(log)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CaptureStateAfter for special needs, tracks SSTORE ops and records the storage change.
|
||||||
|
func (l *JSONLogger) CaptureStateAfter(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
||||||
|
}
|
||||||
|
|
||||||
// CaptureEnd is triggered at end of execution.
|
// CaptureEnd is triggered at end of execution.
|
||||||
func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
|
func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
|
||||||
type endLog struct {
|
type endLog struct {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,9 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
|
|
||||||
"github.com/scroll-tech/go-ethereum/common"
|
"github.com/scroll-tech/go-ethereum/common"
|
||||||
|
"github.com/scroll-tech/go-ethereum/core/rawdb"
|
||||||
"github.com/scroll-tech/go-ethereum/core/state"
|
"github.com/scroll-tech/go-ethereum/core/state"
|
||||||
"github.com/scroll-tech/go-ethereum/params"
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
@ -42,6 +44,14 @@ func (d *dummyContractRef) SetBalance(*big.Int) {}
|
||||||
func (d *dummyContractRef) SetNonce(uint64) {}
|
func (d *dummyContractRef) SetNonce(uint64) {}
|
||||||
func (d *dummyContractRef) Balance() *big.Int { return new(big.Int) }
|
func (d *dummyContractRef) Balance() *big.Int { return new(big.Int) }
|
||||||
|
|
||||||
|
// makeTestState create a sample test state to test node-wise reconstruction.
|
||||||
|
func makeTestState() *state.StateDB {
|
||||||
|
// Create an empty state
|
||||||
|
db := state.NewDatabase(rawdb.NewMemoryDatabase())
|
||||||
|
stateDb, _ := state.New(common.Hash{}, db, nil)
|
||||||
|
return stateDb
|
||||||
|
}
|
||||||
|
|
||||||
type dummyStatedb struct {
|
type dummyStatedb struct {
|
||||||
state.StateDB
|
state.StateDB
|
||||||
}
|
}
|
||||||
|
|
@ -50,7 +60,7 @@ func (*dummyStatedb) GetRefund() uint64 { return 1337 }
|
||||||
|
|
||||||
func TestStoreCapture(t *testing.T) {
|
func TestStoreCapture(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
env = NewEVM(BlockContext{}, TxContext{}, &dummyStatedb{}, params.TestChainConfig, Config{})
|
env = NewEVM(BlockContext{}, TxContext{}, makeTestState(), params.TestChainConfig, Config{})
|
||||||
logger = NewStructLogger(nil)
|
logger = NewStructLogger(nil)
|
||||||
contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0)
|
contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0)
|
||||||
scope = &ScopeContext{
|
scope = &ScopeContext{
|
||||||
|
|
|
||||||
146
core/vm/logger_trace.go
Normal file
146
core/vm/logger_trace.go
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/scroll-tech/go-ethereum/common"
|
||||||
|
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
||||||
|
"github.com/scroll-tech/go-ethereum/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type traceFunc func(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error
|
||||||
|
|
||||||
|
var (
|
||||||
|
// OpcodeExecs the map to load opcodes' trace funcs.
|
||||||
|
OpcodeExecs = map[OpCode][]traceFunc{
|
||||||
|
CALL: {traceToAddressCodeHash, traceLastNAddressCodeHash(1), traceCallerProof, traceLastNAddressProof(1)},
|
||||||
|
CALLCODE: {traceToAddressCodeHash, traceLastNAddressCodeHash(1), traceCallerProof, traceLastNAddressProof(1)},
|
||||||
|
DELEGATECALL: {traceToAddressCodeHash, traceLastNAddressCodeHash(1)},
|
||||||
|
STATICCALL: {traceToAddressCodeHash, traceLastNAddressCodeHash(1)},
|
||||||
|
CREATE: {traceSenderAddress, traceCreatedContractProof, traceNonce},
|
||||||
|
CREATE2: {traceSenderAddress, traceCreatedContractProof},
|
||||||
|
SSTORE: {traceStorageProof},
|
||||||
|
SLOAD: {traceStorageProof},
|
||||||
|
SELFDESTRUCT: {traceContractProof, traceLastNAddressProof(0)},
|
||||||
|
SELFBALANCE: {traceContractProof},
|
||||||
|
BALANCE: {traceLastNAddressProof(0)},
|
||||||
|
EXTCODEHASH: {traceLastNAddressProof(0)},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// traceToAddressCodeHash gets tx.to address’s code_hash
|
||||||
|
func traceToAddressCodeHash(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
|
||||||
|
if l.env.To == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
codeHash := l.env.StateDB.GetCodeHash(*l.env.To)
|
||||||
|
extraData.CodeHashList = append(extraData.CodeHashList, codeHash)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// traceLastNAddressCodeHash
|
||||||
|
func traceLastNAddressCodeHash(n int) traceFunc {
|
||||||
|
return func(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
|
||||||
|
stack := scope.Stack
|
||||||
|
if stack.len() <= n {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
address := common.Address(stack.data[stack.len()-1-n].Bytes20())
|
||||||
|
codeHash := l.env.StateDB.GetCodeHash(address)
|
||||||
|
extraData.CodeHashList = append(extraData.CodeHashList, codeHash)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
if err == nil {
|
||||||
|
extraData.ProofList = append(extraData.ProofList, encodeProof(storageProof))
|
||||||
|
}
|
||||||
|
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())
|
||||||
|
if err == nil {
|
||||||
|
extraData.ProofList = append(extraData.ProofList, encodeProof(proof))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
/// traceCreatedContractProof get created contract address’s accountProof
|
||||||
|
func traceCreatedContractProof(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
|
||||||
|
stack := scope.Stack
|
||||||
|
if stack.len() < 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
stackvalue := stack.peek()
|
||||||
|
if stackvalue.IsZero() {
|
||||||
|
return errors.New("can't get created contract address from stack")
|
||||||
|
}
|
||||||
|
address := common.BytesToAddress(stackvalue.Bytes())
|
||||||
|
proof, err := l.env.StateDB.GetProof(address)
|
||||||
|
if err == nil {
|
||||||
|
extraData.ProofList = append(extraData.ProofList, encodeProof(proof))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// traceLastNAddressProof returns func about the last N's address proof.
|
||||||
|
func traceLastNAddressProof(n int) traceFunc {
|
||||||
|
return func(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
|
||||||
|
stack := scope.Stack
|
||||||
|
if stack.len() <= n {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
address := common.Address(stack.data[stack.len()-1-n].Bytes20())
|
||||||
|
proof, err := l.env.StateDB.GetProof(address)
|
||||||
|
if err == nil {
|
||||||
|
extraData.ProofList = append(extraData.ProofList, encodeProof(proof))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
if err == nil {
|
||||||
|
extraData.ProofList = append(extraData.ProofList, encodeProof(proof))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeProof(proof [][]byte) (res []string) {
|
||||||
|
if len(proof) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, node := range proof {
|
||||||
|
res = append(res, hexutil.Encode(node))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
@ -618,7 +618,10 @@ func NewPublicTraceAPI(eth *Ethereum) *PublicTraceAPI {
|
||||||
return &PublicTraceAPI{eth}
|
return &PublicTraceAPI{eth}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockResultByHash returns the blockResult by blockHash.
|
// GetBlockResultByHash returns the blockResult by blockHash.
|
||||||
func (api *PublicTraceAPI) BlockResultByHash(blockHash common.Hash) (*types.BlockResult, error) {
|
func (api *PublicTraceAPI) GetBlockResultByHash(blockHash common.Hash) (*types.BlockResult, error) {
|
||||||
return rawdb.ReadBlockResult(api.e.chainDb, blockHash), nil
|
if blockResult := api.e.blockchain.GetBlockResultByHash(blockHash); blockResult != nil {
|
||||||
|
return blockResult, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("No block result found")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -371,8 +371,10 @@ func (es *EventSystem) handleChainEvent(filters filterIndex, ev core.ChainEvent)
|
||||||
for _, f := range filters[BlocksSubscription] {
|
for _, f := range filters[BlocksSubscription] {
|
||||||
f.headers <- ev.Block.Header()
|
f.headers <- ev.Block.Header()
|
||||||
}
|
}
|
||||||
for _, f := range filters[BlockResultsSubscription] {
|
if ev.BlockResult != nil {
|
||||||
f.blockResults <- ev.BlockResult
|
for _, f := range filters[BlockResultsSubscription] {
|
||||||
|
f.blockResults <- ev.BlockResult
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if es.lightMode && len(filters[LogsSubscription]) > 0 {
|
if es.lightMode && len(filters[LogsSubscription]) > 0 {
|
||||||
es.lightFilterNewHead(ev.Block.Header(), func(header *types.Header, remove bool) {
|
es.lightFilterNewHead(ev.Block.Header(), func(header *types.Header, remove bool) {
|
||||||
|
|
|
||||||
|
|
@ -746,6 +746,10 @@ func (jst *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CaptureStateAfter for special needs, tracks SSTORE ops and records the storage change.
|
||||||
|
func (jst *jsTracer) CaptureStateAfter(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
||||||
|
}
|
||||||
|
|
||||||
// CaptureFault implements the Tracer interface to trace an execution fault
|
// CaptureFault implements the Tracer interface to trace an execution fault
|
||||||
func (jst *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
|
func (jst *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
|
||||||
if jst.err != nil {
|
if jst.err != nil {
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,10 @@ func (t *fourByteTracer) CaptureStart(env *vm.EVM, from common.Address, to commo
|
||||||
func (t *fourByteTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
func (t *fourByteTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CaptureStateAfter for special needs, tracks SSTORE ops and records the storage change.
|
||||||
|
func (t *fourByteTracer) CaptureStateAfter(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
||||||
|
}
|
||||||
|
|
||||||
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
|
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
|
||||||
func (t *fourByteTracer) CaptureEnter(op vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
func (t *fourByteTracer) CaptureEnter(op vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||||
// Skip if tracing was interrupted
|
// Skip if tracing was interrupted
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,10 @@ func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration,
|
||||||
func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CaptureStateAfter for special needs, tracks SSTORE ops and records the storage change.
|
||||||
|
func (t *callTracer) CaptureStateAfter(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
||||||
|
}
|
||||||
|
|
||||||
// CaptureFault implements the EVMLogger interface to trace an execution fault.
|
// CaptureFault implements the EVMLogger interface to trace an execution fault.
|
||||||
func (t *callTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) {
|
func (t *callTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) {
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,10 @@ func (t *noopTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration,
|
||||||
func (t *noopTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
func (t *noopTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CaptureStateAfter for special needs, tracks SSTORE ops and records the storage change.
|
||||||
|
func (t *noopTracer) CaptureStateAfter(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
||||||
|
}
|
||||||
|
|
||||||
// CaptureFault implements the EVMLogger interface to trace an execution fault.
|
// CaptureFault implements the EVMLogger interface to trace an execution fault.
|
||||||
func (t *noopTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) {
|
func (t *noopTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) {
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -325,10 +325,10 @@ func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header)
|
||||||
return ec.c.EthSubscribe(ctx, ch, "newHeads")
|
return ec.c.EthSubscribe(ctx, ch, "newHeads")
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockResultByHash returns the blockResult.
|
// GetBlockResultByHash returns the blockResult.
|
||||||
func (ec *Client) BlockResultByHash(ctx context.Context, blockHash common.Hash) (*types.BlockResult, error) {
|
func (ec *Client) GetBlockResultByHash(ctx context.Context, blockHash common.Hash) (*types.BlockResult, error) {
|
||||||
var blockResult types.BlockResult
|
var blockResult types.BlockResult
|
||||||
if err := ec.c.CallContext(ctx, &blockResult, "eth_blockResultByHash", blockHash); err != nil {
|
if err := ec.c.CallContext(ctx, &blockResult, "eth_getBlockResultByHash", blockHash); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &blockResult, nil
|
return &blockResult, nil
|
||||||
|
|
|
||||||
|
|
@ -794,7 +794,7 @@ func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Addres
|
||||||
w.current.receipts = append(w.current.receipts, receipt)
|
w.current.receipts = append(w.current.receipts, receipt)
|
||||||
w.current.executionResults = append(w.current.executionResults, &types.ExecutionResult{
|
w.current.executionResults = append(w.current.executionResults, &types.ExecutionResult{
|
||||||
Gas: receipt.GasUsed,
|
Gas: receipt.GasUsed,
|
||||||
Failed: receipt.Status == types.ReceiptStatusSuccessful,
|
Failed: receipt.Status != types.ReceiptStatusSuccessful,
|
||||||
ReturnValue: fmt.Sprintf("%x", receipt.ReturnValue),
|
ReturnValue: fmt.Sprintf("%x", receipt.ReturnValue),
|
||||||
StructLogs: vm.FormatLogs(tracer.StructLogs()),
|
StructLogs: vm.FormatLogs(tracer.StructLogs()),
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,7 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool) {
|
||||||
b.genesis.MustCommit(db2)
|
b.genesis.MustCommit(db2)
|
||||||
chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{
|
chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{
|
||||||
Debug: true,
|
Debug: true,
|
||||||
Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true})}, nil, nil)
|
Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true, EnableReturnData: true})}, nil, nil)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
// Ignore empty commit here for less noise.
|
// Ignore empty commit here for less noise.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue