From 22bd6485d5e26a94e39e1704941f6f520f602e5f Mon Sep 17 00:00:00 2001 From: maskpp <32827930+mask-pp@users.noreply.github.com> Date: Wed, 12 Jan 2022 10:38:32 +0800 Subject: [PATCH 01/37] Create go.yml --- .github/workflows/go.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/go.yml diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 000000000000..b25386a38795 --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,21 @@ +on: [pull_request] +name: Continuous Integration +jobs: + check: + runs-on: ubuntu-latest + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: 1.17.x + - name: Checkout code + uses: actions/checkout@v2 + - name: Lint + run: | + make lint + - name: Test + run: | + go get ./... + make test + - name: Upload coverage report + run: bash <(curl -s https://codecov.io/bash) From e958633dd4adb7314907e2a240a95f1c80dcb4b0 Mon Sep 17 00:00:00 2001 From: mask-pp Date: Thu, 6 Jan 2022 14:02:16 +0800 Subject: [PATCH 02/37] Merge from zkrollup and fix conflict --- core/rawdb/schema.go | 6 +++ eth/api.go | 15 ++++++ eth/backend.go | 5 ++ eth/evmTrace.go | 36 +++++++++++++ eth/evmTrace_test.go | 120 +++++++++++++++++++++++++++++++++++++++++ internal/ethapi/api.go | 108 +++++++++++++++++++++++++++++++++++++ miner/miner.go | 3 ++ miner/miner_test.go | 7 +++ miner/worker.go | 51 +++++++++++++++--- miner/worker_test.go | 5 ++ 10 files changed, 348 insertions(+), 8 deletions(-) create mode 100644 eth/evmTrace.go create mode 100644 eth/evmTrace_test.go diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 73dc69ea3122..257d987cb7bd 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -89,6 +89,7 @@ var ( SnapshotAccountPrefix = []byte("a") // SnapshotAccountPrefix + account hash -> account trie value SnapshotStoragePrefix = []byte("o") // SnapshotStoragePrefix + account hash + storage hash -> storage trie value CodePrefix = []byte("c") // CodePrefix + code hash -> account code + evmTracesPrefix = []byte("e") // evmTracesPrefix + hash -> evmTrace list PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage configPrefix = []byte("ethereum-config-") // config prefix for the db @@ -230,3 +231,8 @@ func IsCodeKey(key []byte) (bool, []byte) { func configKey(hash common.Hash) []byte { return append(configPrefix, hash.Bytes()...) } + +// EvmTracesKey = evmTracesPrefix + hash +func EvmTracesKey(hash common.Hash) []byte { + return append(evmTracesPrefix, hash.Bytes()...) +} diff --git a/eth/api.go b/eth/api.go index 2e9b91246043..581a37f0b5ae 100644 --- a/eth/api.go +++ b/eth/api.go @@ -607,3 +607,18 @@ func (api *PrivateDebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64 } return 0, fmt.Errorf("No state found") } + +// PublicTraceAPI provides an API to get evmTrace, mpt proof. +type PublicTraceAPI struct { + e *Ethereum +} + +// NewPublicTraceAPI creates a new Ethereum trace API. +func NewPublicTraceAPI(eth *Ethereum) *PublicTraceAPI { + return &PublicTraceAPI{eth} +} + +// GetEvmTracesByHash returns the block's evmTrace list by blockHash. +func (api *PublicTraceAPI) GetEvmTracesByHash(blockHash common.Hash) ([]*ethapi.ExecutionResult, error) { + return api.e.ReadEvmTraces(blockHash), nil +} diff --git a/eth/backend.go b/eth/backend.go index 2adee3f2cf16..d5b8edff02cc 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -314,6 +314,11 @@ func (s *Ethereum) APIs() []rpc.API { Version: "1.0", Service: downloader.NewPublicDownloaderAPI(s.handler.downloader, s.eventMux), Public: true, + }, { + Namespace: "eth", + Version: "1.0", + Service: NewPublicTraceAPI(s), + Public: true, }, { Namespace: "miner", Version: "1.0", diff --git a/eth/evmTrace.go b/eth/evmTrace.go new file mode 100644 index 000000000000..cb01a5bd916f --- /dev/null +++ b/eth/evmTrace.go @@ -0,0 +1,36 @@ +package eth + +import ( + "github.com/scroll-tech/go-ethereum/common" + "github.com/scroll-tech/go-ethereum/core/rawdb" + "github.com/scroll-tech/go-ethereum/internal/ethapi" + "github.com/scroll-tech/go-ethereum/log" + "github.com/scroll-tech/go-ethereum/rlp" +) + +// ReadEvmTraces retrieves all the evmTraces belonging to a block. +func (s *Ethereum) ReadEvmTraces(hash common.Hash) []*ethapi.ExecutionResult { + data, _ := s.chainDb.Get(rawdb.EvmTracesKey(hash)) + if len(data) == 0 { + return nil + } + var evmTraces []*ethapi.ExecutionResult + if err := rlp.DecodeBytes(data, &evmTraces); err != nil { + log.Error("") + } + return evmTraces +} + +// WriteEvmTraces stores evmTrace list into leveldb. +func (s *Ethereum) WriteEvmTraces(hash common.Hash, evmTraces []*ethapi.ExecutionResult) error { + bytes, err := rlp.EncodeToBytes(evmTraces) + if err != nil { + return err + } + return s.chainDb.Put(rawdb.EvmTracesKey(hash), bytes) +} + +// DeleteEvmTraces removes all evmTraces with a block hash. +func (s *Ethereum) DeleteEvmTraces(hash common.Hash) error { + return s.chainDb.Delete(rawdb.EvmTracesKey(hash)) +} diff --git a/eth/evmTrace_test.go b/eth/evmTrace_test.go new file mode 100644 index 000000000000..3acdac8829cf --- /dev/null +++ b/eth/evmTrace_test.go @@ -0,0 +1,120 @@ +package eth + +import ( + "bytes" + "encoding/hex" + "fmt" + "testing" + + "github.com/pkg/errors" + "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/vm" + "github.com/scroll-tech/go-ethereum/core/vm/runtime" + "github.com/scroll-tech/go-ethereum/ethdb" + "github.com/scroll-tech/go-ethereum/internal/ethapi" + "github.com/scroll-tech/go-ethereum/rlp" +) + +func traceOps(db ethdb.Database, code []byte) (*ethapi.ExecutionResult, error) { + newState, err := state.New(common.Hash{}, state.NewDatabase(db), nil) + if err != nil { + return nil, errors.Wrap(err, "failed to initialize new state") + } + toAddress := common.Address{0xff} + newState.SetCode(toAddress, code) + config := &runtime.Config{ + GasLimit: 1000000, + State: newState, + } + tracer := vm.NewStructLogger(nil) + // Overwrite config with tracer + config.EVMConfig.Debug = true + config.EVMConfig.Tracer = tracer + + res, _, err := runtime.Call(toAddress, nil, config) + if err != nil { + return nil, errors.Wrap(err, "transaction fails") + } + return ðapi.ExecutionResult{ + Gas: 1, + Failed: false, + ReturnValue: fmt.Sprintf("%x", res), + StructLogs: ethapi.FormatLogs(tracer.StructLogs()), + }, nil +} + +func TestBlockEvmTracesStorage(t *testing.T) { + db := rawdb.NewMemoryDatabase() + evmTrace1, err := traceOps(db, []byte{ + // Add slot `0x1` to access list + byte(vm.PUSH1), 0x01, byte(vm.SLOAD), byte(vm.POP), // SLOAD( 0x1) (add to access list) + // Write to `0x1` which is already in access list + byte(vm.PUSH1), 0x11, byte(vm.PUSH1), 0x01, byte(vm.SSTORE), // SSTORE( loc: 0x01, val: 0x11) + // Write to `0x2` which is not in access list + byte(vm.PUSH1), 0x11, byte(vm.PUSH1), 0x02, byte(vm.SSTORE), // SSTORE( loc: 0x02, val: 0x11) + // Write again to `0x2` + byte(vm.PUSH1), 0x11, byte(vm.PUSH1), 0x02, byte(vm.SSTORE), // SSTORE( loc: 0x02, val: 0x11) + // Read slot in access list (0x2) + byte(vm.PUSH1), 0x02, byte(vm.SLOAD), // SLOAD( 0x2) + // Read slot in access list (0x1) + byte(vm.PUSH1), 0x01, byte(vm.SLOAD), // SLOAD( 0x1) + }) + if err != nil { + t.Fatal("Failed to traceOps", "err", err) + } + evmTrace2, err := traceOps(db, []byte{ + byte(vm.PUSH1), 10, + byte(vm.PUSH1), 0, + byte(vm.MSTORE), + byte(vm.PUSH1), 32, + byte(vm.PUSH1), 0, + byte(vm.RETURN), + }) + if err != nil { + t.Fatal("Failed to traceOps", "err", err) + } + evmTraces := []*ethapi.ExecutionResult{evmTrace1, evmTrace2} + hash := common.BytesToHash([]byte{0x03, 0x04}) + eth := Ethereum{chainDb: db} + // Insert the evmTrace list into the database and check presence. + if err := eth.WriteEvmTraces(hash, evmTraces); err != nil { + t.Fatalf(err.Error()) + } + // Read evmTrace list from db. + if traces := eth.ReadEvmTraces(hash); len(traces) == 0 { + t.Fatalf("No evmTraces returned") + } else { + if err := checkEvmTracesRLP(traces, evmTraces); err != nil { + t.Fatalf(err.Error()) + } + } + // Delete evmTrace list by blockHash. + if err := eth.DeleteEvmTraces(hash); err != nil { + t.Fatalf(err.Error()) + } + if traces := eth.ReadEvmTraces(hash); len(traces) != 0 { + t.Fatalf("The evmTrace list should be empty.") + } +} + +func checkEvmTracesRLP(have, want []*ethapi.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 +} diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index a998af86ea74..0bb6deff6502 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -20,7 +20,9 @@ import ( "context" "errors" "fmt" + "io" "math/big" + "sort" "strings" "time" @@ -1123,6 +1125,29 @@ type ExecutionResult struct { StructLogs []StructLogRes `json:"structLogs"` } +type rlpExecutionResult struct { + Gas uint64 + Failed bool + StructLogs []StructLogRes +} + +func (e *ExecutionResult) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, rlpExecutionResult{ + Gas: e.Gas, + Failed: e.Failed, + 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.StructLogs = dec.Gas, dec.Failed, dec.StructLogs + } + return err +} + // StructLogRes stores a structured log emitted by the EVM while replaying a // transaction in debug mode type StructLogRes struct { @@ -1137,6 +1162,89 @@ type StructLogRes struct { Storage *map[string]string `json:"storage,omitempty"` } +type rlpStructLogRes struct { + Pc uint64 `json:"pc"` + Op string `json:"op"` + Gas uint64 `json:"gas"` + GasCost uint64 `json:"gasCost"` + Depth uint `json:"depth"` + Error string `json:"error,omitempty"` + Stack []string `json:"stack,omitempty"` + Memory []string `json:"memory,omitempty"` + Storage []string `json:"storage,omitempty"` +} + +// EncodeRLP implements rlp.Encoder. +func (r *StructLogRes) EncodeRLP(w io.Writer) error { + data := rlpStructLogRes{ + Pc: r.Pc, + Op: r.Op, + 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. +func (r *StructLogRes) DecodeRLP(s *rlp.Stream) error { + var dec rlpStructLogRes + err := s.Decode(&dec) + 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(dec.Stack) != 0 { + stack := make([]string, len(dec.Stack)) + for i, val := range dec.Stack { + stack[i] = val + } + r.Stack = &stack + } + if len(dec.Memory) != 0 { + memory := make([]string, len(dec.Memory)) + for i, val := range dec.Memory { + memory[i] = val + } + r.Memory = &memory + } + if len(dec.Storage) != 0 { + 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 +} + // FormatLogs formats EVM returned structured logs for json output func FormatLogs(logs []vm.StructLog) []StructLogRes { formatted := make([]StructLogRes, len(logs)) diff --git a/miner/miner.go b/miner/miner.go index 5edc72e1d343..0842f849dbeb 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -31,6 +31,7 @@ import ( "github.com/scroll-tech/go-ethereum/core/types" "github.com/scroll-tech/go-ethereum/eth/downloader" "github.com/scroll-tech/go-ethereum/event" + "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/params" ) @@ -39,6 +40,8 @@ import ( type Backend interface { BlockChain() *core.BlockChain TxPool() *core.TxPool + WriteEvmTraces(hash common.Hash, evmTraces []*ethapi.ExecutionResult) error + DeleteEvmTraces(hash common.Hash) error } // Config is the configuration parameters of mining. diff --git a/miner/miner_test.go b/miner/miner_test.go index 56a3ec079f01..1c27b4e9f515 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -31,6 +31,7 @@ import ( "github.com/scroll-tech/go-ethereum/eth/downloader" "github.com/scroll-tech/go-ethereum/ethdb/memorydb" "github.com/scroll-tech/go-ethereum/event" + "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/trie" ) @@ -54,6 +55,12 @@ func (m *mockBackend) TxPool() *core.TxPool { return m.txPool } +func (m *mockBackend) WriteEvmTraces(hash common.Hash, evmTraces []*ethapi.ExecutionResult) error { + return nil +} + +func (m *mockBackend) DeleteEvmTraces(hash common.Hash) error { return nil } + type testBlockChain struct { statedb *state.StateDB gasLimit uint64 diff --git a/miner/worker.go b/miner/worker.go index 8a3cdc3905e5..a0876fdc5a2c 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -31,7 +31,9 @@ import ( "github.com/scroll-tech/go-ethereum/core" "github.com/scroll-tech/go-ethereum/core/state" "github.com/scroll-tech/go-ethereum/core/types" + "github.com/scroll-tech/go-ethereum/core/vm" "github.com/scroll-tech/go-ethereum/event" + "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/params" "github.com/scroll-tech/go-ethereum/trie" @@ -91,14 +93,17 @@ type environment struct { header *types.Header txs []*types.Transaction receipts []*types.Receipt + + executionResults []*ethapi.ExecutionResult } // task contains all information for consensus engine sealing and result submitting. type task struct { - receipts []*types.Receipt - state *state.StateDB - block *types.Block - createdAt time.Time + receipts []*types.Receipt + executionResults []*ethapi.ExecutionResult + state *state.StateDB + block *types.Block + createdAt time.Time } const ( @@ -462,6 +467,7 @@ func (w *worker) mainLoop() { select { case req := <-w.newWorkCh: w.commitNewWork(req.interrupt, req.noempty, req.timestamp) + // new block created. case ev := <-w.chainSideCh: // Short circuit for duplicate side blocks @@ -632,14 +638,19 @@ func (w *worker) resultLoop() { } // Different block could share same sealhash, deep copy here to prevent write-write conflict. var ( - receipts = make([]*types.Receipt, len(task.receipts)) - logs []*types.Log + receipts = make([]*types.Receipt, len(task.receipts)) + evmTraces = make([]*ethapi.ExecutionResult, len(task.executionResults)) + logs []*types.Log ) for i, taskReceipt := range task.receipts { receipt := new(types.Receipt) receipts[i] = receipt *receipt = *taskReceipt + evmTrace := new(ethapi.ExecutionResult) + evmTraces[i] = evmTrace + *evmTrace = *task.executionResults[i] + // add block location fields receipt.BlockHash = hash receipt.BlockNumber = block.Number() @@ -662,6 +673,10 @@ func (w *worker) resultLoop() { log.Error("Failed writing block to chain", "err", err) continue } + if err := w.eth.WriteEvmTraces(hash, evmTraces); err != nil { + log.Error("Failed writing evmTrace list to db", "err", err) + } + w.chain.Genesis() log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealhash, "hash", hash, "elapsed", common.PrettyDuration(time.Since(task.createdAt))) @@ -771,13 +786,23 @@ func (w *worker) updateSnapshot() { func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { snap := w.current.state.Snapshot() - receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, *w.chain.GetVMConfig()) + tracer := vm.StructLogger{} + config := *w.chain.GetVMConfig() + config.Debug = true + config.Tracer = &tracer + + receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, config) if err != nil { w.current.state.RevertToSnapshot(snap) return nil, err } w.current.txs = append(w.current.txs, tx) w.current.receipts = append(w.current.receipts, receipt) + w.current.executionResults = append(w.current.executionResults, ðapi.ExecutionResult{ + Gas: receipt.GasUsed, + Failed: receipt.Status == types.ReceiptStatusSuccessful, + StructLogs: ethapi.FormatLogs(tracer.StructLogs()), + }) return receipt.Logs, nil } @@ -1032,6 +1057,7 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) func (w *worker) commit(uncles []*types.Header, interval func(), update bool, start time.Time) error { // Deep copy receipts here to avoid interaction between different tasks. receipts := copyReceipts(w.current.receipts) + executionResults := copyExecutionResults(w.current.executionResults) s := w.current.state.Copy() block, err := w.engine.FinalizeAndAssemble(w.chain, w.current.header, s, w.current.txs, uncles, receipts) if err != nil { @@ -1042,7 +1068,7 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st interval() } select { - case w.taskCh <- &task{receipts: receipts, state: s, block: block, createdAt: time.Now()}: + case w.taskCh <- &task{receipts: receipts, executionResults: executionResults, state: s, block: block, createdAt: time.Now()}: w.unconfirmed.Shift(block.NumberU64() - 1) log.Info("Commit new mining work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()), "uncles", len(uncles), "txs", w.current.tcount, @@ -1069,6 +1095,15 @@ func copyReceipts(receipts []*types.Receipt) []*types.Receipt { return result } +func copyExecutionResults(executionResults []*ethapi.ExecutionResult) []*ethapi.ExecutionResult { + result := make([]*ethapi.ExecutionResult, len(executionResults)) + for i, l := range executionResults { + cpy := *l + result[i] = &cpy + } + return result +} + // postSideBlock fires a side chain event, only use it for testing. func (w *worker) postSideBlock(event core.ChainSideEvent) { select { diff --git a/miner/worker_test.go b/miner/worker_test.go index 010eb6cd16c9..c851439b51ed 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -35,6 +35,7 @@ import ( "github.com/scroll-tech/go-ethereum/crypto" "github.com/scroll-tech/go-ethereum/ethdb" "github.com/scroll-tech/go-ethereum/event" + "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/params" ) @@ -166,6 +167,10 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain } func (b *testWorkerBackend) TxPool() *core.TxPool { return b.txPool } +func (b *testWorkerBackend) WriteEvmTraces(hash common.Hash, evmTraces []*ethapi.ExecutionResult) error { + return nil +} +func (b *testWorkerBackend) DeleteEvmTraces(hash common.Hash) error { return nil } func (b *testWorkerBackend) newRandomUncle() *types.Block { var parent *types.Block From ed1a8a3422857f2e659c37379f33832a24badb68 Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 13 Jan 2022 12:42:56 +0800 Subject: [PATCH 03/37] go mod tidy --- go.mod | 1 + 1 file changed, 1 insertion(+) diff --git a/go.mod b/go.mod index 9d896b5279f9..a3a501ff8c1e 100644 --- a/go.mod +++ b/go.mod @@ -52,6 +52,7 @@ require ( github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 + github.com/pkg/errors v0.9.1 github.com/prometheus/tsdb v0.7.1 github.com/rjeczalik/notify v0.9.1 github.com/rs/cors v1.7.0 From 0efcb0a9ed359d68476b9f1e692a39b665e6af38 Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 13 Jan 2022 14:50:54 +0800 Subject: [PATCH 04/37] fix worker_test test case --- miner/worker.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index a0876fdc5a2c..a15d2c3c700a 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -786,10 +786,10 @@ func (w *worker) updateSnapshot() { func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { snap := w.current.state.Snapshot() - tracer := vm.StructLogger{} + tracer := vm.NewStructLogger(nil) config := *w.chain.GetVMConfig() config.Debug = true - config.Tracer = &tracer + config.Tracer = tracer receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, config) if err != nil { From 9925d5f0a3889caa46c0126ed43288ae416518c4 Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 13 Jan 2022 14:50:54 +0800 Subject: [PATCH 05/37] fix worker_test test case --- .github/workflows/go.yml | 21 --------------------- .gitignore | 3 +++ miner/worker.go | 4 ++-- 3 files changed, 5 insertions(+), 23 deletions(-) delete mode 100644 .github/workflows/go.yml diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml deleted file mode 100644 index b25386a38795..000000000000 --- a/.github/workflows/go.yml +++ /dev/null @@ -1,21 +0,0 @@ -on: [pull_request] -name: Continuous Integration -jobs: - check: - runs-on: ubuntu-latest - steps: - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: 1.17.x - - name: Checkout code - uses: actions/checkout@v2 - - name: Lint - run: | - make lint - - name: Test - run: | - go get ./... - make test - - name: Upload coverage report - run: bash <(curl -s https://codecov.io/bash) diff --git a/.gitignore b/.gitignore index 1ee8b83022ef..bd3dcb7452c9 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,6 @@ profile.cov /dashboard/assets/package-lock.json **/yarn-error.log + +# github +.github diff --git a/miner/worker.go b/miner/worker.go index a0876fdc5a2c..a15d2c3c700a 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -786,10 +786,10 @@ func (w *worker) updateSnapshot() { func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { snap := w.current.state.Snapshot() - tracer := vm.StructLogger{} + tracer := vm.NewStructLogger(nil) config := *w.chain.GetVMConfig() config.Debug = true - config.Tracer = &tracer + config.Tracer = tracer receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, config) if err != nil { From cae5f4ae99516af6289136bf032427c8ea673dd7 Mon Sep 17 00:00:00 2001 From: maskpp <32827930+mask-pp@users.noreply.github.com> Date: Thu, 13 Jan 2022 14:59:54 +0800 Subject: [PATCH 06/37] Delete go.yml --- .github/workflows/go.yml | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 .github/workflows/go.yml diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml deleted file mode 100644 index b25386a38795..000000000000 --- a/.github/workflows/go.yml +++ /dev/null @@ -1,21 +0,0 @@ -on: [pull_request] -name: Continuous Integration -jobs: - check: - runs-on: ubuntu-latest - steps: - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: 1.17.x - - name: Checkout code - uses: actions/checkout@v2 - - name: Lint - run: | - make lint - - name: Test - run: | - go get ./... - make test - - name: Upload coverage report - run: bash <(curl -s https://codecov.io/bash) From 65e5539f583438c93f6e2cd16eb661bfe891b616 Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 13 Jan 2022 15:14:35 +0800 Subject: [PATCH 07/37] add log content, enable memory trace --- eth/evmTrace.go | 2 +- miner/worker.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/evmTrace.go b/eth/evmTrace.go index cb01a5bd916f..23b3cfb83e9d 100644 --- a/eth/evmTrace.go +++ b/eth/evmTrace.go @@ -16,7 +16,7 @@ func (s *Ethereum) ReadEvmTraces(hash common.Hash) []*ethapi.ExecutionResult { } var evmTraces []*ethapi.ExecutionResult if err := rlp.DecodeBytes(data, &evmTraces); err != nil { - log.Error("") + log.Error("Failed to decode evmTraces", "err", err) } return evmTraces } diff --git a/miner/worker.go b/miner/worker.go index a15d2c3c700a..a175510da213 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -786,7 +786,7 @@ func (w *worker) updateSnapshot() { func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { snap := w.current.state.Snapshot() - tracer := vm.NewStructLogger(nil) + tracer := vm.NewStructLogger(&vm.LogConfig{EnableMemory: true}) config := *w.chain.GetVMConfig() config.Debug = true config.Tracer = tracer From 8368dcaf3f0c2189f8302e07182c9a0118d3f683 Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 13 Jan 2022 15:27:47 +0800 Subject: [PATCH 08/37] add tracer pool handler --- miner/worker.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/miner/worker.go b/miner/worker.go index a175510da213..f58f29fb4598 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -39,6 +39,12 @@ import ( "github.com/scroll-tech/go-ethereum/trie" ) +var ( + tracerPool = sync.Pool{ + New: func() interface{} { return vm.NewStructLogger(&vm.LogConfig{EnableMemory: true}) }, + } +) + const ( // resultQueueSize is the size of channel listening to sealing result. resultQueueSize = 10 @@ -786,7 +792,11 @@ func (w *worker) updateSnapshot() { func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { snap := w.current.state.Snapshot() - tracer := vm.NewStructLogger(&vm.LogConfig{EnableMemory: true}) + tracer := tracerPool.Get().(*vm.StructLogger) + defer func() { + tracer.Reset() + tracerPool.Put(tracer) + }() config := *w.chain.GetVMConfig() config.Debug = true config.Tracer = tracer From 3510875e85227bfb2f21cc7113cd84ba1be33079 Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 13 Jan 2022 15:33:48 +0800 Subject: [PATCH 09/37] Add comments and format code --- miner/worker.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index f58f29fb4598..2fdfa6171be1 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -96,10 +96,9 @@ type environment struct { tcount int // tx count in cycle gasPool *core.GasPool // available gas used to pack transactions - header *types.Header - txs []*types.Transaction - receipts []*types.Receipt - + header *types.Header + txs []*types.Transaction + receipts []*types.Receipt executionResults []*ethapi.ExecutionResult } @@ -792,6 +791,7 @@ func (w *worker) updateSnapshot() { func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { snap := w.current.state.Snapshot() + // Enables debugging and set tracer. tracer := tracerPool.Get().(*vm.StructLogger) defer func() { tracer.Reset() From fc18a619dcd1aecdad63f4b4adab2b41479451d8 Mon Sep 17 00:00:00 2001 From: maskpp Date: Mon, 17 Jan 2022 18:56:43 +0800 Subject: [PATCH 10/37] add evmTrace subscribe api --- accounts/abi/bind/backends/simulated.go | 5 +++ eth/api_backend.go | 5 +++ eth/filters/api.go | 30 +++++++++++++++++ eth/filters/filter.go | 2 ++ eth/filters/filter_system.go | 44 ++++++++++++++++++++----- eth/filters/filter_system_test.go | 8 +++++ internal/ethapi/backend.go | 1 + les/api_backend.go | 8 +++++ miner/miner.go | 5 +++ miner/worker.go | 2 ++ 10 files changed, 102 insertions(+), 8 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index d8b4dea4a6bf..8996ab5e25f1 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -40,6 +40,7 @@ import ( "github.com/scroll-tech/go-ethereum/eth/filters" "github.com/scroll-tech/go-ethereum/ethdb" "github.com/scroll-tech/go-ethereum/event" + "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/params" "github.com/scroll-tech/go-ethereum/rpc" @@ -876,6 +877,10 @@ func (fb *filterBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event return nullSubscription() } +func (fb *filterBackend) SubscribeEvmTracesEvent(ch chan<- []*ethapi.ExecutionResult) event.Subscription { + return nullSubscription() +} + func (fb *filterBackend) BloomStatus() (uint64, uint64) { return 4096, 0 } func (fb *filterBackend) ServiceFilter(ctx context.Context, ms *bloombits.MatcherSession) { diff --git a/eth/api_backend.go b/eth/api_backend.go index d6ea967f0b4c..8dd0112a055d 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -35,6 +35,7 @@ import ( "github.com/scroll-tech/go-ethereum/eth/gasprice" "github.com/scroll-tech/go-ethereum/ethdb" "github.com/scroll-tech/go-ethereum/event" + "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/miner" "github.com/scroll-tech/go-ethereum/params" "github.com/scroll-tech/go-ethereum/rpc" @@ -235,6 +236,10 @@ func (b *EthAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscri return b.eth.BlockChain().SubscribeLogsEvent(ch) } +func (b EthAPIBackend) SubscribeEvmTracesEvent(ch chan<- []*ethapi.ExecutionResult) event.Subscription { + return b.eth.miner.SubscribeEvmTraces(ch) +} + func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { return b.eth.txPool.AddLocal(signedTx) } diff --git a/eth/filters/api.go b/eth/filters/api.go index 66d62a86de64..920672beb1b3 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -31,6 +31,7 @@ import ( "github.com/scroll-tech/go-ethereum/core/types" "github.com/scroll-tech/go-ethereum/ethdb" "github.com/scroll-tech/go-ethereum/event" + "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/rpc" ) @@ -278,6 +279,35 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc return rpcSub, nil } +// NewEvmTraces send evmTrace list when a new block is created. +func (api *PublicFilterAPI) NewEvmTraces(ctx context.Context) (*rpc.Subscription, error) { + notifier, supported := rpc.NotifierFromContext(ctx) + if !supported { + return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported + } + + rpcSub := notifier.CreateSubscription() + + go func() { + evmTraces := make(chan []*ethapi.ExecutionResult) + evmTracesSub := api.events.SubscribeEvmTraces(evmTraces) + + for { + select { + case traces := <-evmTraces: + notifier.Notify(rpcSub.ID, traces) + case <-rpcSub.Err(): + evmTracesSub.Unsubscribe() + return + case <-notifier.Closed(): + evmTracesSub.Unsubscribe() + return + } + } + }() + return rpcSub, nil +} + // FilterCriteria represents a request to create a new filter. // Same as ethereum.FilterQuery but with UnmarshalJSON() method. type FilterCriteria ethereum.FilterQuery diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 3574613b5569..052594ce9bb0 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -27,6 +27,7 @@ import ( "github.com/scroll-tech/go-ethereum/core/types" "github.com/scroll-tech/go-ethereum/ethdb" "github.com/scroll-tech/go-ethereum/event" + "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/rpc" ) @@ -42,6 +43,7 @@ type Backend interface { SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription + SubscribeEvmTracesEvent(ch chan<- []*ethapi.ExecutionResult) event.Subscription BloomStatus() (uint64, uint64) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index 6275a57bb82a..e59e85110160 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -30,6 +30,7 @@ import ( "github.com/scroll-tech/go-ethereum/core/rawdb" "github.com/scroll-tech/go-ethereum/core/types" "github.com/scroll-tech/go-ethereum/event" + "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/rpc" ) @@ -52,6 +53,8 @@ const ( PendingTransactionsSubscription // BlocksSubscription queries hashes for blocks that are imported BlocksSubscription + // EvmTracesSubscription queries evmTrace list when new block created + EvmTracesSubscription // LastSubscription keeps track of the last index LastIndexSubscription ) @@ -76,6 +79,7 @@ type subscription struct { logs chan []*types.Log hashes chan []common.Hash headers chan *types.Header + evmTraces chan []*ethapi.ExecutionResult installed chan struct{} // closed when the filter is installed err chan error // closed when the filter is uninstalled } @@ -93,15 +97,17 @@ type EventSystem struct { rmLogsSub event.Subscription // Subscription for removed log event pendingLogsSub event.Subscription // Subscription for pending log event chainSub event.Subscription // Subscription for new chain event + evmTracesSub event.Subscription // Subscription for new evmTraces event // Channels - install chan *subscription // install filter for event notification - uninstall chan *subscription // remove filter for event notification - txsCh chan core.NewTxsEvent // Channel to receive new transactions event - logsCh chan []*types.Log // Channel to receive new log event - pendingLogsCh chan []*types.Log // Channel to receive new log event - rmLogsCh chan core.RemovedLogsEvent // Channel to receive removed log event - chainCh chan core.ChainEvent // Channel to receive new chain event + install chan *subscription // install filter for event notification + uninstall chan *subscription // remove filter for event notification + txsCh chan core.NewTxsEvent // Channel to receive new transactions event + logsCh chan []*types.Log // Channel to receive new log event + pendingLogsCh chan []*types.Log // Channel to receive new log event + rmLogsCh chan core.RemovedLogsEvent // Channel to receive removed log event + chainCh chan core.ChainEvent // Channel to receive new chain event + evmTracesCh chan []*ethapi.ExecutionResult // Channel to receive new evmTraces event } // NewEventSystem creates a new manager that listens for event on the given mux, @@ -129,6 +135,7 @@ func NewEventSystem(backend Backend, lightMode bool) *EventSystem { m.rmLogsSub = m.backend.SubscribeRemovedLogsEvent(m.rmLogsCh) m.chainSub = m.backend.SubscribeChainEvent(m.chainCh) m.pendingLogsSub = m.backend.SubscribePendingLogsEvent(m.pendingLogsCh) + m.evmTracesSub = m.backend.SubscribeEvmTracesEvent(m.evmTracesCh) // Make sure none of the subscriptions are empty if m.txsSub == nil || m.logsSub == nil || m.rmLogsSub == nil || m.chainSub == nil || m.pendingLogsSub == nil { @@ -290,6 +297,19 @@ func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscripti return es.subscribe(sub) } +// SubscribeEvmTraces creates a subscription that writes the evmTraces when a new block is created. +func (es *EventSystem) SubscribeEvmTraces(evmTraces chan []*ethapi.ExecutionResult) *Subscription { + sub := &subscription{ + id: rpc.NewID(), + typ: EvmTracesSubscription, + created: time.Now(), + evmTraces: evmTraces, + installed: make(chan struct{}), + err: make(chan error), + } + return es.subscribe(sub) +} + // SubscribePendingTxs creates a subscription that writes transaction hashes for // transactions that enter the transaction pool. func (es *EventSystem) SubscribePendingTxs(hashes chan []common.Hash) *Subscription { @@ -366,6 +386,12 @@ func (es *EventSystem) handleChainEvent(filters filterIndex, ev core.ChainEvent) } } +func (es *EventSystem) handleEvmTracesEvent(filters filterIndex, ev []*ethapi.ExecutionResult) { + for _, f := range filters[EvmTracesSubscription] { + f.evmTraces <- ev + } +} + func (es *EventSystem) lightFilterNewHead(newHeader *types.Header, callBack func(*types.Header, bool)) { oldh := es.lastHead es.lastHead = newHeader @@ -448,6 +474,7 @@ func (es *EventSystem) eventLoop() { es.rmLogsSub.Unsubscribe() es.pendingLogsSub.Unsubscribe() es.chainSub.Unsubscribe() + es.evmTracesSub.Unsubscribe() }() index := make(filterIndex) @@ -467,7 +494,8 @@ func (es *EventSystem) eventLoop() { es.handlePendingLogs(index, ev) case ev := <-es.chainCh: es.handleChainEvent(index, ev) - + case ev := <-es.evmTracesCh: + es.handleEvmTracesEvent(index, ev) case f := <-es.install: if f.typ == MinedAndPendingLogsSubscription { // the type are logs and pending logs subscriptions diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 8e1a4bcaeb4b..ba472b4cd5c1 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -35,6 +35,7 @@ import ( "github.com/scroll-tech/go-ethereum/core/types" "github.com/scroll-tech/go-ethereum/ethdb" "github.com/scroll-tech/go-ethereum/event" + "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/params" "github.com/scroll-tech/go-ethereum/rpc" ) @@ -126,6 +127,13 @@ func (b *testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subsc return b.chainFeed.Subscribe(ch) } +func (b *testBackend) SubscribeEvmTracesEvent(ch chan<- []*ethapi.ExecutionResult) event.Subscription { + return event.NewSubscription(func(quit <-chan struct{}) error { + <-quit + return nil + }) +} + func (b *testBackend) BloomStatus() (uint64, uint64) { return params.BloomBitsBlocks, b.sections } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index c8764161f6e2..fb99ddf2efcc 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -90,6 +90,7 @@ type Backend interface { SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription + SubscribeEvmTracesEvent(ch chan<- []*ExecutionResult) event.Subscription ChainConfig() *params.ChainConfig Engine() consensus.Engine diff --git a/les/api_backend.go b/les/api_backend.go index fa1d17f0f254..77b900aba4c3 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -35,6 +35,7 @@ import ( "github.com/scroll-tech/go-ethereum/eth/gasprice" "github.com/scroll-tech/go-ethereum/ethdb" "github.com/scroll-tech/go-ethereum/event" + "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/light" "github.com/scroll-tech/go-ethereum/params" "github.com/scroll-tech/go-ethereum/rpc" @@ -258,6 +259,13 @@ func (b *LesApiBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEven return b.eth.blockchain.SubscribeRemovedLogsEvent(ch) } +func (b *LesApiBackend) SubscribeEvmTracesEvent(ch chan<- []*ethapi.ExecutionResult) event.Subscription { + return event.NewSubscription(func(quit <-chan struct{}) error { + <-quit + return nil + }) +} + func (b *LesApiBackend) SyncProgress() ethereum.SyncProgress { return b.eth.Downloader().Progress() } diff --git a/miner/miner.go b/miner/miner.go index 0842f849dbeb..736eba70ffaa 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -241,3 +241,8 @@ func (miner *Miner) DisablePreseal() { func (miner *Miner) SubscribePendingLogs(ch chan<- []*types.Log) event.Subscription { return miner.worker.pendingLogsFeed.Subscribe(ch) } + +// SubscribeEvmTraces starts delivering evmTraces when a new block is created. +func (miner *Miner) SubscribeEvmTraces(ch chan<- []*ethapi.ExecutionResult) event.Subscription { + return miner.worker.evmTracesFeed.Subscribe(ch) +} diff --git a/miner/worker.go b/miner/worker.go index 2fdfa6171be1..7cabaf043930 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -141,6 +141,7 @@ type worker struct { // Feeds pendingLogsFeed event.Feed + evmTracesFeed event.Feed // Subscriptions mux *event.TypeMux @@ -678,6 +679,7 @@ func (w *worker) resultLoop() { log.Error("Failed writing block to chain", "err", err) continue } + w.evmTracesFeed.Send(evmTraces) if err := w.eth.WriteEvmTraces(hash, evmTraces); err != nil { log.Error("Failed writing evmTrace list to db", "err", err) } From 7571c53eefc0203c0020609c13b854bb369e5265 Mon Sep 17 00:00:00 2001 From: maskpp Date: Tue, 18 Jan 2022 19:46:06 +0800 Subject: [PATCH 11/37] Move the evmTrace struct. --- accounts/abi/bind/backends/simulated.go | 5 - core/blockchain.go | 12 +- core/events.go | 7 +- core/rawdb/l2trace.go | 39 +++ core/rawdb/l2trace_test.go | 384 ++++++++++++++++++++++++ core/rawdb/schema.go | 4 +- core/types/l2trace.go | 139 +++++++++ core/vm/logger.go | 37 +++ eth/api.go | 4 +- eth/api_backend.go | 5 - eth/backend.go | 2 + eth/evmTrace.go | 36 --- eth/evmTrace_test.go | 120 -------- eth/filters/api.go | 3 +- eth/filters/filter.go | 2 - eth/filters/filter_system.go | 35 +-- eth/filters/filter_system_test.go | 8 - eth/tracers/api.go | 4 +- eth/tracers/api_test.go | 20 +- ethclient/ethclient.go | 5 + internal/ethapi/api.go | 169 ----------- internal/ethapi/backend.go | 1 - les/api_backend.go | 8 - miner/miner.go | 8 - miner/miner_test.go | 7 - miner/worker.go | 44 +-- miner/worker_test.go | 5 - 27 files changed, 660 insertions(+), 453 deletions(-) create mode 100644 core/rawdb/l2trace.go create mode 100644 core/rawdb/l2trace_test.go create mode 100644 core/types/l2trace.go delete mode 100644 eth/evmTrace.go delete mode 100644 eth/evmTrace_test.go diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 8996ab5e25f1..d8b4dea4a6bf 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -40,7 +40,6 @@ import ( "github.com/scroll-tech/go-ethereum/eth/filters" "github.com/scroll-tech/go-ethereum/ethdb" "github.com/scroll-tech/go-ethereum/event" - "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/params" "github.com/scroll-tech/go-ethereum/rpc" @@ -877,10 +876,6 @@ func (fb *filterBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event return nullSubscription() } -func (fb *filterBackend) SubscribeEvmTracesEvent(ch chan<- []*ethapi.ExecutionResult) event.Subscription { - return nullSubscription() -} - func (fb *filterBackend) BloomStatus() (uint64, uint64) { return 4096, 0 } func (fb *filterBackend) ServiceFilter(ctx context.Context, ms *bloombits.MatcherSession) { diff --git a/core/blockchain.go b/core/blockchain.go index 38c37a432525..fff221dbb23b 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1182,17 +1182,18 @@ func (bc *BlockChain) writeKnownBlock(block *types.Block) error { } // WriteBlockWithState writes the block and all associated state to the database. -func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) { +func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, evmTraces []*types.ExecutionResult, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) { if !bc.chainmu.TryLock() { return NonStatTy, errInsertionInterrupted } defer bc.chainmu.Unlock() - return bc.writeBlockWithState(block, receipts, logs, state, emitHeadEvent) + //rawdb.WriteEvmTraces(bc.db, block.Hash(), evmTraces) + return bc.writeBlockWithState(block, receipts, logs, evmTraces, state, emitHeadEvent) } // writeBlockWithState writes the block and all associated state to the database, // but is expects the chain mutex to be held. -func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) { +func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, evmTraces []*types.ExecutionResult, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) { if bc.insertStopped() { return NonStatTy, errInsertionInterrupted } @@ -1215,6 +1216,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd) rawdb.WriteBlock(blockBatch, block) rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts) + rawdb.WriteEvmTraces(blockBatch, block.Hash(), evmTraces) rawdb.WritePreimages(blockBatch, state.Preimages()) if err := blockBatch.Write(); err != nil { log.Crit("Failed to write block into disk", "err", err) @@ -1314,7 +1316,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. bc.futureBlocks.Remove(block.Hash()) if status == CanonStatTy { - bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs}) + bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs, Traces: evmTraces}) if len(logs) > 0 { bc.logsFeed.Send(logs) } @@ -1644,7 +1646,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er // Write the block to the chain and get the status. substart = time.Now() - status, err := bc.writeBlockWithState(block, receipts, logs, statedb, false) + status, err := bc.writeBlockWithState(block, receipts, logs, nil, statedb, false) atomic.StoreUint32(&followupInterrupt, 1) if err != nil { return it.index, err diff --git a/core/events.go b/core/events.go index 398bac1ba0e6..4f93cb0946fe 100644 --- a/core/events.go +++ b/core/events.go @@ -31,9 +31,10 @@ type NewMinedBlockEvent struct{ Block *types.Block } type RemovedLogsEvent struct{ Logs []*types.Log } type ChainEvent struct { - Block *types.Block - Hash common.Hash - Logs []*types.Log + Block *types.Block + Hash common.Hash + Logs []*types.Log + Traces []*types.ExecutionResult } type ChainSideEvent struct { diff --git a/core/rawdb/l2trace.go b/core/rawdb/l2trace.go new file mode 100644 index 000000000000..ab7aa7f8241e --- /dev/null +++ b/core/rawdb/l2trace.go @@ -0,0 +1,39 @@ +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" +) + +// ReadEvmTraces retrieves all the evmTraces belonging to a block. +func ReadEvmTraces(db ethdb.Reader, hash common.Hash) []*types.ExecutionResult { + data, _ := db.Get(evmTracesKey(hash)) + if len(data) == 0 { + return nil + } + var evmTraces []*types.ExecutionResult + if err := rlp.DecodeBytes(data, &evmTraces); err != nil { + log.Error("Failed to decode evmTraces", "err", err) + return nil + } + return evmTraces +} + +// WriteEvmTraces stores evmTrace list into leveldb. +func WriteEvmTraces(db ethdb.KeyValueWriter, hash common.Hash, evmTraces []*types.ExecutionResult) { + bytes, err := rlp.EncodeToBytes(evmTraces) + if err != nil { + log.Crit("Failed to RLP encode evmTraces", "err", err) + } + db.Put(evmTracesKey(hash), bytes) +} + +// DeleteEvmTraces removes all evmTraces with a block hash. +func DeleteEvmTraces(db ethdb.KeyValueWriter, hash common.Hash) { + if err := db.Delete(evmTracesKey(hash)); err != nil { + log.Crit("Failed to delete evmTraces", "err", err) + } +} diff --git a/core/rawdb/l2trace_test.go b/core/rawdb/l2trace_test.go new file mode 100644 index 000000000000..dd0f25ab66ba --- /dev/null +++ b/core/rawdb/l2trace_test.go @@ -0,0 +1,384 @@ +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" +) + +// TODO reference code +/*func traceOps(db ethdb.Database, code []byte) (*types.ExecutionResult, error) { + newState, err := state.New(common.Hash{}, state.NewDatabase(db), nil) + if err != nil { + return nil, errors.Wrap(err, "failed to initialize new state") + } + toAddress := common.Address{0xff} + newState.SetCode(toAddress, code) + config := &runtime.Config{ + GasLimit: 1000000, + State: newState, + } + tracer := vm.NewStructLogger(&vm.LogConfig{EnableMemory: true}) + // Overwrite config with tracer + config.EVMConfig.Debug = true + config.EVMConfig.Tracer = tracer + + res, _, err := runtime.Call(toAddress, nil, config) + if err != nil { + return nil, errors.Wrap(err, "transaction fails") + } + return &types.ExecutionResult{ + Gas: 1, + Failed: false, + ReturnValue: fmt.Sprintf("%x", res), + StructLogs: vm.FormatLogs(tracer.StructLogs()), + }, nil +}*/ + +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{} + 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{} + 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 evmTrace list into the database and check presence. + WriteEvmTraces(db, hash, evmTraces) + // Read evmTrace list from db. + if traces := ReadEvmTraces(db, hash); len(traces) == 0 { + t.Fatalf("No evmTraces returned") + } else { + if err := checkEvmTracesRLP(traces, evmTraces); err != nil { + t.Fatalf(err.Error()) + } + } + // Delete evmTrace list by blockHash. + DeleteEvmTraces(db, hash) + if traces := ReadEvmTraces(db, hash); len(traces) != 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 +} diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 257d987cb7bd..25cfae7022cd 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -232,7 +232,7 @@ func configKey(hash common.Hash) []byte { return append(configPrefix, hash.Bytes()...) } -// EvmTracesKey = evmTracesPrefix + hash -func EvmTracesKey(hash common.Hash) []byte { +// evmTracesKey = evmTracesPrefix + hash +func evmTracesKey(hash common.Hash) []byte { return append(evmTracesPrefix, hash.Bytes()...) } diff --git a/core/types/l2trace.go b/core/types/l2trace.go new file mode 100644 index 000000000000..fe7049654eee --- /dev/null +++ b/core/types/l2trace.go @@ -0,0 +1,139 @@ +package types + +import ( + "io" + "sort" + "strings" + + "github.com/scroll-tech/go-ethereum/rlp" +) + +// ExecutionResult groups all structured logs emitted by the EVM +// while replaying a transaction in debug mode as well as transaction +// execution status, the amount of gas used and the return value +type ExecutionResult struct { + Gas uint64 `json:"gas"` + Failed bool `json:"failed"` + ReturnValue string `json:"returnValue"` + StructLogs []StructLogRes `json:"structLogs"` +} + +type rlpExecutionResult struct { + Gas uint64 + Failed bool + StructLogs []StructLogRes +} + +func (e *ExecutionResult) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, rlpExecutionResult{ + Gas: e.Gas, + Failed: e.Failed, + 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.StructLogs = dec.Gas, dec.Failed, dec.StructLogs + } + return err +} + +// StructLogRes stores a structured log emitted by the EVM while replaying a +// transaction in debug mode +type StructLogRes struct { + Pc uint64 `json:"pc"` + Op string `json:"op"` + Gas uint64 `json:"gas"` + GasCost uint64 `json:"gasCost"` + Depth int `json:"depth"` + Error string `json:"error,omitempty"` + Stack *[]string `json:"stack,omitempty"` + Memory *[]string `json:"memory,omitempty"` + Storage *map[string]string `json:"storage,omitempty"` +} + +type rlpStructLogRes struct { + Pc uint64 `json:"pc"` + Op string `json:"op"` + Gas uint64 `json:"gas"` + GasCost uint64 `json:"gasCost"` + Depth uint `json:"depth"` + Error string `json:"error,omitempty"` + Stack []string `json:"stack,omitempty"` + Memory []string `json:"memory,omitempty"` + Storage []string `json:"storage,omitempty"` +} + +// EncodeRLP implements rlp.Encoder. +func (r *StructLogRes) EncodeRLP(w io.Writer) error { + data := rlpStructLogRes{ + Pc: r.Pc, + Op: r.Op, + 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. +func (r *StructLogRes) DecodeRLP(s *rlp.Stream) error { + var dec rlpStructLogRes + err := s.Decode(&dec) + 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(dec.Stack) != 0 { + stack := make([]string, len(dec.Stack)) + for i, val := range dec.Stack { + stack[i] = val + } + r.Stack = &stack + } + if len(dec.Memory) != 0 { + memory := make([]string, len(dec.Memory)) + for i, val := range dec.Memory { + memory[i] = val + } + r.Memory = &memory + } + if len(dec.Storage) != 0 { + 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 +} diff --git a/core/vm/logger.go b/core/vm/logger.go index 9e547fd29474..196cf0aefd6a 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -358,3 +358,40 @@ func (t *mdLogger) CaptureEnter(typ OpCode, from common.Address, to common.Addre } func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} + +// FormatLogs formats EVM returned structured logs for json output +func FormatLogs(logs []StructLog) []types.StructLogRes { + formatted := make([]types.StructLogRes, len(logs)) + for index, trace := range logs { + formatted[index] = types.StructLogRes{ + Pc: trace.Pc, + Op: trace.Op.String(), + Gas: trace.Gas, + GasCost: trace.GasCost, + Depth: trace.Depth, + Error: trace.ErrorString(), + } + if trace.Stack != nil { + stack := make([]string, len(trace.Stack)) + for i, stackValue := range trace.Stack { + stack[i] = stackValue.Hex() + } + formatted[index].Stack = &stack + } + if trace.Memory != nil { + memory := make([]string, 0, (len(trace.Memory)+31)/32) + for i := 0; i+32 <= len(trace.Memory); i += 32 { + memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:i+32])) + } + formatted[index].Memory = &memory + } + if trace.Storage != nil { + storage := make(map[string]string) + for i, storageValue := range trace.Storage { + storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue) + } + formatted[index].Storage = &storage + } + } + return formatted +} diff --git a/eth/api.go b/eth/api.go index 581a37f0b5ae..db91c7fa81e4 100644 --- a/eth/api.go +++ b/eth/api.go @@ -619,6 +619,6 @@ func NewPublicTraceAPI(eth *Ethereum) *PublicTraceAPI { } // GetEvmTracesByHash returns the block's evmTrace list by blockHash. -func (api *PublicTraceAPI) GetEvmTracesByHash(blockHash common.Hash) ([]*ethapi.ExecutionResult, error) { - return api.e.ReadEvmTraces(blockHash), nil +func (api *PublicTraceAPI) GetEvmTracesByHash(blockHash common.Hash) ([]*types.ExecutionResult, error) { + return rawdb.ReadEvmTraces(api.e.chainDb, blockHash), nil } diff --git a/eth/api_backend.go b/eth/api_backend.go index 8dd0112a055d..d6ea967f0b4c 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -35,7 +35,6 @@ import ( "github.com/scroll-tech/go-ethereum/eth/gasprice" "github.com/scroll-tech/go-ethereum/ethdb" "github.com/scroll-tech/go-ethereum/event" - "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/miner" "github.com/scroll-tech/go-ethereum/params" "github.com/scroll-tech/go-ethereum/rpc" @@ -236,10 +235,6 @@ func (b *EthAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscri return b.eth.BlockChain().SubscribeLogsEvent(ch) } -func (b EthAPIBackend) SubscribeEvmTracesEvent(ch chan<- []*ethapi.ExecutionResult) event.Subscription { - return b.eth.miner.SubscribeEvmTraces(ch) -} - func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { return b.eth.txPool.AddLocal(signedTx) } diff --git a/eth/backend.go b/eth/backend.go index d5b8edff02cc..4e3ae461a7c0 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -175,6 +175,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { var ( vmConfig = vm.Config{ EnablePreimageRecording: config.EnablePreimageRecording, + Debug: true, + Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true}), } cacheConfig = &core.CacheConfig{ TrieCleanLimit: config.TrieCleanCache, diff --git a/eth/evmTrace.go b/eth/evmTrace.go deleted file mode 100644 index 23b3cfb83e9d..000000000000 --- a/eth/evmTrace.go +++ /dev/null @@ -1,36 +0,0 @@ -package eth - -import ( - "github.com/scroll-tech/go-ethereum/common" - "github.com/scroll-tech/go-ethereum/core/rawdb" - "github.com/scroll-tech/go-ethereum/internal/ethapi" - "github.com/scroll-tech/go-ethereum/log" - "github.com/scroll-tech/go-ethereum/rlp" -) - -// ReadEvmTraces retrieves all the evmTraces belonging to a block. -func (s *Ethereum) ReadEvmTraces(hash common.Hash) []*ethapi.ExecutionResult { - data, _ := s.chainDb.Get(rawdb.EvmTracesKey(hash)) - if len(data) == 0 { - return nil - } - var evmTraces []*ethapi.ExecutionResult - if err := rlp.DecodeBytes(data, &evmTraces); err != nil { - log.Error("Failed to decode evmTraces", "err", err) - } - return evmTraces -} - -// WriteEvmTraces stores evmTrace list into leveldb. -func (s *Ethereum) WriteEvmTraces(hash common.Hash, evmTraces []*ethapi.ExecutionResult) error { - bytes, err := rlp.EncodeToBytes(evmTraces) - if err != nil { - return err - } - return s.chainDb.Put(rawdb.EvmTracesKey(hash), bytes) -} - -// DeleteEvmTraces removes all evmTraces with a block hash. -func (s *Ethereum) DeleteEvmTraces(hash common.Hash) error { - return s.chainDb.Delete(rawdb.EvmTracesKey(hash)) -} diff --git a/eth/evmTrace_test.go b/eth/evmTrace_test.go deleted file mode 100644 index 3acdac8829cf..000000000000 --- a/eth/evmTrace_test.go +++ /dev/null @@ -1,120 +0,0 @@ -package eth - -import ( - "bytes" - "encoding/hex" - "fmt" - "testing" - - "github.com/pkg/errors" - "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/vm" - "github.com/scroll-tech/go-ethereum/core/vm/runtime" - "github.com/scroll-tech/go-ethereum/ethdb" - "github.com/scroll-tech/go-ethereum/internal/ethapi" - "github.com/scroll-tech/go-ethereum/rlp" -) - -func traceOps(db ethdb.Database, code []byte) (*ethapi.ExecutionResult, error) { - newState, err := state.New(common.Hash{}, state.NewDatabase(db), nil) - if err != nil { - return nil, errors.Wrap(err, "failed to initialize new state") - } - toAddress := common.Address{0xff} - newState.SetCode(toAddress, code) - config := &runtime.Config{ - GasLimit: 1000000, - State: newState, - } - tracer := vm.NewStructLogger(nil) - // Overwrite config with tracer - config.EVMConfig.Debug = true - config.EVMConfig.Tracer = tracer - - res, _, err := runtime.Call(toAddress, nil, config) - if err != nil { - return nil, errors.Wrap(err, "transaction fails") - } - return ðapi.ExecutionResult{ - Gas: 1, - Failed: false, - ReturnValue: fmt.Sprintf("%x", res), - StructLogs: ethapi.FormatLogs(tracer.StructLogs()), - }, nil -} - -func TestBlockEvmTracesStorage(t *testing.T) { - db := rawdb.NewMemoryDatabase() - evmTrace1, err := traceOps(db, []byte{ - // Add slot `0x1` to access list - byte(vm.PUSH1), 0x01, byte(vm.SLOAD), byte(vm.POP), // SLOAD( 0x1) (add to access list) - // Write to `0x1` which is already in access list - byte(vm.PUSH1), 0x11, byte(vm.PUSH1), 0x01, byte(vm.SSTORE), // SSTORE( loc: 0x01, val: 0x11) - // Write to `0x2` which is not in access list - byte(vm.PUSH1), 0x11, byte(vm.PUSH1), 0x02, byte(vm.SSTORE), // SSTORE( loc: 0x02, val: 0x11) - // Write again to `0x2` - byte(vm.PUSH1), 0x11, byte(vm.PUSH1), 0x02, byte(vm.SSTORE), // SSTORE( loc: 0x02, val: 0x11) - // Read slot in access list (0x2) - byte(vm.PUSH1), 0x02, byte(vm.SLOAD), // SLOAD( 0x2) - // Read slot in access list (0x1) - byte(vm.PUSH1), 0x01, byte(vm.SLOAD), // SLOAD( 0x1) - }) - if err != nil { - t.Fatal("Failed to traceOps", "err", err) - } - evmTrace2, err := traceOps(db, []byte{ - byte(vm.PUSH1), 10, - byte(vm.PUSH1), 0, - byte(vm.MSTORE), - byte(vm.PUSH1), 32, - byte(vm.PUSH1), 0, - byte(vm.RETURN), - }) - if err != nil { - t.Fatal("Failed to traceOps", "err", err) - } - evmTraces := []*ethapi.ExecutionResult{evmTrace1, evmTrace2} - hash := common.BytesToHash([]byte{0x03, 0x04}) - eth := Ethereum{chainDb: db} - // Insert the evmTrace list into the database and check presence. - if err := eth.WriteEvmTraces(hash, evmTraces); err != nil { - t.Fatalf(err.Error()) - } - // Read evmTrace list from db. - if traces := eth.ReadEvmTraces(hash); len(traces) == 0 { - t.Fatalf("No evmTraces returned") - } else { - if err := checkEvmTracesRLP(traces, evmTraces); err != nil { - t.Fatalf(err.Error()) - } - } - // Delete evmTrace list by blockHash. - if err := eth.DeleteEvmTraces(hash); err != nil { - t.Fatalf(err.Error()) - } - if traces := eth.ReadEvmTraces(hash); len(traces) != 0 { - t.Fatalf("The evmTrace list should be empty.") - } -} - -func checkEvmTracesRLP(have, want []*ethapi.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 -} diff --git a/eth/filters/api.go b/eth/filters/api.go index 920672beb1b3..b528d31bbb9c 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -31,7 +31,6 @@ import ( "github.com/scroll-tech/go-ethereum/core/types" "github.com/scroll-tech/go-ethereum/ethdb" "github.com/scroll-tech/go-ethereum/event" - "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/rpc" ) @@ -289,7 +288,7 @@ func (api *PublicFilterAPI) NewEvmTraces(ctx context.Context) (*rpc.Subscription rpcSub := notifier.CreateSubscription() go func() { - evmTraces := make(chan []*ethapi.ExecutionResult) + evmTraces := make(chan []*types.ExecutionResult) evmTracesSub := api.events.SubscribeEvmTraces(evmTraces) for { diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 052594ce9bb0..3574613b5569 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -27,7 +27,6 @@ import ( "github.com/scroll-tech/go-ethereum/core/types" "github.com/scroll-tech/go-ethereum/ethdb" "github.com/scroll-tech/go-ethereum/event" - "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/rpc" ) @@ -43,7 +42,6 @@ type Backend interface { SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription - SubscribeEvmTracesEvent(ch chan<- []*ethapi.ExecutionResult) event.Subscription BloomStatus() (uint64, uint64) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index e59e85110160..c65d992fa3fc 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -30,7 +30,6 @@ import ( "github.com/scroll-tech/go-ethereum/core/rawdb" "github.com/scroll-tech/go-ethereum/core/types" "github.com/scroll-tech/go-ethereum/event" - "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/rpc" ) @@ -79,7 +78,7 @@ type subscription struct { logs chan []*types.Log hashes chan []common.Hash headers chan *types.Header - evmTraces chan []*ethapi.ExecutionResult + evmTraces chan []*types.ExecutionResult installed chan struct{} // closed when the filter is installed err chan error // closed when the filter is uninstalled } @@ -97,17 +96,15 @@ type EventSystem struct { rmLogsSub event.Subscription // Subscription for removed log event pendingLogsSub event.Subscription // Subscription for pending log event chainSub event.Subscription // Subscription for new chain event - evmTracesSub event.Subscription // Subscription for new evmTraces event // Channels - install chan *subscription // install filter for event notification - uninstall chan *subscription // remove filter for event notification - txsCh chan core.NewTxsEvent // Channel to receive new transactions event - logsCh chan []*types.Log // Channel to receive new log event - pendingLogsCh chan []*types.Log // Channel to receive new log event - rmLogsCh chan core.RemovedLogsEvent // Channel to receive removed log event - chainCh chan core.ChainEvent // Channel to receive new chain event - evmTracesCh chan []*ethapi.ExecutionResult // Channel to receive new evmTraces event + install chan *subscription // install filter for event notification + uninstall chan *subscription // remove filter for event notification + txsCh chan core.NewTxsEvent // Channel to receive new transactions event + logsCh chan []*types.Log // Channel to receive new log event + pendingLogsCh chan []*types.Log // Channel to receive new log event + rmLogsCh chan core.RemovedLogsEvent // Channel to receive removed log event + chainCh chan core.ChainEvent // Channel to receive new chain event } // NewEventSystem creates a new manager that listens for event on the given mux, @@ -135,7 +132,6 @@ func NewEventSystem(backend Backend, lightMode bool) *EventSystem { m.rmLogsSub = m.backend.SubscribeRemovedLogsEvent(m.rmLogsCh) m.chainSub = m.backend.SubscribeChainEvent(m.chainCh) m.pendingLogsSub = m.backend.SubscribePendingLogsEvent(m.pendingLogsCh) - m.evmTracesSub = m.backend.SubscribeEvmTracesEvent(m.evmTracesCh) // Make sure none of the subscriptions are empty if m.txsSub == nil || m.logsSub == nil || m.rmLogsSub == nil || m.chainSub == nil || m.pendingLogsSub == nil { @@ -298,7 +294,7 @@ func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscripti } // SubscribeEvmTraces creates a subscription that writes the evmTraces when a new block is created. -func (es *EventSystem) SubscribeEvmTraces(evmTraces chan []*ethapi.ExecutionResult) *Subscription { +func (es *EventSystem) SubscribeEvmTraces(evmTraces chan []*types.ExecutionResult) *Subscription { sub := &subscription{ id: rpc.NewID(), typ: EvmTracesSubscription, @@ -375,6 +371,9 @@ func (es *EventSystem) handleChainEvent(filters filterIndex, ev core.ChainEvent) for _, f := range filters[BlocksSubscription] { f.headers <- ev.Block.Header() } + for _, f := range filters[EvmTracesSubscription] { + f.evmTraces <- ev.Traces + } if es.lightMode && len(filters[LogsSubscription]) > 0 { es.lightFilterNewHead(ev.Block.Header(), func(header *types.Header, remove bool) { for _, f := range filters[LogsSubscription] { @@ -386,12 +385,6 @@ func (es *EventSystem) handleChainEvent(filters filterIndex, ev core.ChainEvent) } } -func (es *EventSystem) handleEvmTracesEvent(filters filterIndex, ev []*ethapi.ExecutionResult) { - for _, f := range filters[EvmTracesSubscription] { - f.evmTraces <- ev - } -} - func (es *EventSystem) lightFilterNewHead(newHeader *types.Header, callBack func(*types.Header, bool)) { oldh := es.lastHead es.lastHead = newHeader @@ -474,7 +467,6 @@ func (es *EventSystem) eventLoop() { es.rmLogsSub.Unsubscribe() es.pendingLogsSub.Unsubscribe() es.chainSub.Unsubscribe() - es.evmTracesSub.Unsubscribe() }() index := make(filterIndex) @@ -494,8 +486,7 @@ func (es *EventSystem) eventLoop() { es.handlePendingLogs(index, ev) case ev := <-es.chainCh: es.handleChainEvent(index, ev) - case ev := <-es.evmTracesCh: - es.handleEvmTracesEvent(index, ev) + case f := <-es.install: if f.typ == MinedAndPendingLogsSubscription { // the type are logs and pending logs subscriptions diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index ba472b4cd5c1..8e1a4bcaeb4b 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -35,7 +35,6 @@ import ( "github.com/scroll-tech/go-ethereum/core/types" "github.com/scroll-tech/go-ethereum/ethdb" "github.com/scroll-tech/go-ethereum/event" - "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/params" "github.com/scroll-tech/go-ethereum/rpc" ) @@ -127,13 +126,6 @@ func (b *testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subsc return b.chainFeed.Subscribe(ch) } -func (b *testBackend) SubscribeEvmTracesEvent(ch chan<- []*ethapi.ExecutionResult) event.Subscription { - return event.NewSubscription(func(quit <-chan struct{}) error { - <-quit - return nil - }) -} - func (b *testBackend) BloomStatus() (uint64, uint64) { return params.BloomBitsBlocks, b.sections } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index fd6b622519b9..cf209d7f721d 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -912,11 +912,11 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex if len(result.Revert()) > 0 { returnVal = fmt.Sprintf("%x", result.Revert()) } - return ðapi.ExecutionResult{ + return &types.ExecutionResult{ Gas: result.UsedGas, Failed: result.Failed(), ReturnValue: returnVal, - StructLogs: ethapi.FormatLogs(tracer.StructLogs()), + StructLogs: vm.FormatLogs(tracer.StructLogs()), }, nil case Tracer: diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 6a917e8fd7d9..284b4c59c780 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -213,11 +213,11 @@ func TestTraceCall(t *testing.T) { }, config: nil, expectErr: nil, - expect: ðapi.ExecutionResult{ + expect: &types.ExecutionResult{ Gas: params.TxGas, Failed: false, ReturnValue: "", - StructLogs: []ethapi.StructLogRes{}, + StructLogs: []types.StructLogRes{}, }, }, // Standard JSON trace upon the head, plain transfer. @@ -230,11 +230,11 @@ func TestTraceCall(t *testing.T) { }, config: nil, expectErr: nil, - expect: ðapi.ExecutionResult{ + expect: &types.ExecutionResult{ Gas: params.TxGas, Failed: false, ReturnValue: "", - StructLogs: []ethapi.StructLogRes{}, + StructLogs: []types.StructLogRes{}, }, }, // Standard JSON trace upon the non-existent block, error expects @@ -259,11 +259,11 @@ func TestTraceCall(t *testing.T) { }, config: nil, expectErr: nil, - expect: ðapi.ExecutionResult{ + expect: &types.ExecutionResult{ Gas: params.TxGas, Failed: false, ReturnValue: "", - StructLogs: []ethapi.StructLogRes{}, + StructLogs: []types.StructLogRes{}, }, }, // Standard JSON trace upon the pending block @@ -276,11 +276,11 @@ func TestTraceCall(t *testing.T) { }, config: nil, expectErr: nil, - expect: ðapi.ExecutionResult{ + expect: &types.ExecutionResult{ Gas: params.TxGas, Failed: false, ReturnValue: "", - StructLogs: []ethapi.StructLogRes{}, + StructLogs: []types.StructLogRes{}, }, }, } @@ -329,11 +329,11 @@ func TestTraceTransaction(t *testing.T) { if err != nil { t.Errorf("Failed to trace transaction %v", err) } - if !reflect.DeepEqual(result, ðapi.ExecutionResult{ + if !reflect.DeepEqual(result, &types.ExecutionResult{ Gas: params.TxGas, Failed: false, ReturnValue: "", - StructLogs: []ethapi.StructLogRes{}, + StructLogs: []types.StructLogRes{}, }) { t.Error("Transaction tracing result is different") } diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 0bad4aa44ca4..3dd087e85404 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -325,6 +325,11 @@ func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) return ec.c.EthSubscribe(ctx, ch, "newHeads") } +// SubscribeNewEvmTraces subscribe to evmTraces when new block created. +func (ec *Client) SubscribeNewEvmTraces(ctx context.Context, ch chan<- *types.ExecutionResult) (ethereum.Subscription, error) { + return ec.c.EthSubscribe(ctx, ch, "newEvmTraces") +} + // State Access // NetworkID returns the network ID (also known as the chain ID) for this chain. diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 0bb6deff6502..5c957dc0afcf 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -20,9 +20,7 @@ import ( "context" "errors" "fmt" - "io" "math/big" - "sort" "strings" "time" @@ -1115,173 +1113,6 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args TransactionA return DoEstimateGas(ctx, s.b, args, bNrOrHash, s.b.RPCGasCap()) } -// ExecutionResult groups all structured logs emitted by the EVM -// while replaying a transaction in debug mode as well as transaction -// execution status, the amount of gas used and the return value -type ExecutionResult struct { - Gas uint64 `json:"gas"` - Failed bool `json:"failed"` - ReturnValue string `json:"returnValue"` - StructLogs []StructLogRes `json:"structLogs"` -} - -type rlpExecutionResult struct { - Gas uint64 - Failed bool - StructLogs []StructLogRes -} - -func (e *ExecutionResult) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, rlpExecutionResult{ - Gas: e.Gas, - Failed: e.Failed, - 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.StructLogs = dec.Gas, dec.Failed, dec.StructLogs - } - return err -} - -// StructLogRes stores a structured log emitted by the EVM while replaying a -// transaction in debug mode -type StructLogRes struct { - Pc uint64 `json:"pc"` - Op string `json:"op"` - Gas uint64 `json:"gas"` - GasCost uint64 `json:"gasCost"` - Depth int `json:"depth"` - Error string `json:"error,omitempty"` - Stack *[]string `json:"stack,omitempty"` - Memory *[]string `json:"memory,omitempty"` - Storage *map[string]string `json:"storage,omitempty"` -} - -type rlpStructLogRes struct { - Pc uint64 `json:"pc"` - Op string `json:"op"` - Gas uint64 `json:"gas"` - GasCost uint64 `json:"gasCost"` - Depth uint `json:"depth"` - Error string `json:"error,omitempty"` - Stack []string `json:"stack,omitempty"` - Memory []string `json:"memory,omitempty"` - Storage []string `json:"storage,omitempty"` -} - -// EncodeRLP implements rlp.Encoder. -func (r *StructLogRes) EncodeRLP(w io.Writer) error { - data := rlpStructLogRes{ - Pc: r.Pc, - Op: r.Op, - 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. -func (r *StructLogRes) DecodeRLP(s *rlp.Stream) error { - var dec rlpStructLogRes - err := s.Decode(&dec) - 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(dec.Stack) != 0 { - stack := make([]string, len(dec.Stack)) - for i, val := range dec.Stack { - stack[i] = val - } - r.Stack = &stack - } - if len(dec.Memory) != 0 { - memory := make([]string, len(dec.Memory)) - for i, val := range dec.Memory { - memory[i] = val - } - r.Memory = &memory - } - if len(dec.Storage) != 0 { - 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 -} - -// FormatLogs formats EVM returned structured logs for json output -func FormatLogs(logs []vm.StructLog) []StructLogRes { - formatted := make([]StructLogRes, len(logs)) - for index, trace := range logs { - formatted[index] = StructLogRes{ - Pc: trace.Pc, - Op: trace.Op.String(), - Gas: trace.Gas, - GasCost: trace.GasCost, - Depth: trace.Depth, - Error: trace.ErrorString(), - } - if trace.Stack != nil { - stack := make([]string, len(trace.Stack)) - for i, stackValue := range trace.Stack { - stack[i] = stackValue.Hex() - } - formatted[index].Stack = &stack - } - if trace.Memory != nil { - memory := make([]string, 0, (len(trace.Memory)+31)/32) - for i := 0; i+32 <= len(trace.Memory); i += 32 { - memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:i+32])) - } - formatted[index].Memory = &memory - } - if trace.Storage != nil { - storage := make(map[string]string) - for i, storageValue := range trace.Storage { - storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue) - } - formatted[index].Storage = &storage - } - } - return formatted -} - // RPCMarshalHeader converts the given header to the RPC output . func RPCMarshalHeader(head *types.Header) map[string]interface{} { result := map[string]interface{}{ diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index fb99ddf2efcc..c8764161f6e2 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -90,7 +90,6 @@ type Backend interface { SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription - SubscribeEvmTracesEvent(ch chan<- []*ExecutionResult) event.Subscription ChainConfig() *params.ChainConfig Engine() consensus.Engine diff --git a/les/api_backend.go b/les/api_backend.go index 77b900aba4c3..fa1d17f0f254 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -35,7 +35,6 @@ import ( "github.com/scroll-tech/go-ethereum/eth/gasprice" "github.com/scroll-tech/go-ethereum/ethdb" "github.com/scroll-tech/go-ethereum/event" - "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/light" "github.com/scroll-tech/go-ethereum/params" "github.com/scroll-tech/go-ethereum/rpc" @@ -259,13 +258,6 @@ func (b *LesApiBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEven return b.eth.blockchain.SubscribeRemovedLogsEvent(ch) } -func (b *LesApiBackend) SubscribeEvmTracesEvent(ch chan<- []*ethapi.ExecutionResult) event.Subscription { - return event.NewSubscription(func(quit <-chan struct{}) error { - <-quit - return nil - }) -} - func (b *LesApiBackend) SyncProgress() ethereum.SyncProgress { return b.eth.Downloader().Progress() } diff --git a/miner/miner.go b/miner/miner.go index 736eba70ffaa..5edc72e1d343 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -31,7 +31,6 @@ import ( "github.com/scroll-tech/go-ethereum/core/types" "github.com/scroll-tech/go-ethereum/eth/downloader" "github.com/scroll-tech/go-ethereum/event" - "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/params" ) @@ -40,8 +39,6 @@ import ( type Backend interface { BlockChain() *core.BlockChain TxPool() *core.TxPool - WriteEvmTraces(hash common.Hash, evmTraces []*ethapi.ExecutionResult) error - DeleteEvmTraces(hash common.Hash) error } // Config is the configuration parameters of mining. @@ -241,8 +238,3 @@ func (miner *Miner) DisablePreseal() { func (miner *Miner) SubscribePendingLogs(ch chan<- []*types.Log) event.Subscription { return miner.worker.pendingLogsFeed.Subscribe(ch) } - -// SubscribeEvmTraces starts delivering evmTraces when a new block is created. -func (miner *Miner) SubscribeEvmTraces(ch chan<- []*ethapi.ExecutionResult) event.Subscription { - return miner.worker.evmTracesFeed.Subscribe(ch) -} diff --git a/miner/miner_test.go b/miner/miner_test.go index 1c27b4e9f515..56a3ec079f01 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -31,7 +31,6 @@ import ( "github.com/scroll-tech/go-ethereum/eth/downloader" "github.com/scroll-tech/go-ethereum/ethdb/memorydb" "github.com/scroll-tech/go-ethereum/event" - "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/trie" ) @@ -55,12 +54,6 @@ func (m *mockBackend) TxPool() *core.TxPool { return m.txPool } -func (m *mockBackend) WriteEvmTraces(hash common.Hash, evmTraces []*ethapi.ExecutionResult) error { - return nil -} - -func (m *mockBackend) DeleteEvmTraces(hash common.Hash) error { return nil } - type testBlockChain struct { statedb *state.StateDB gasLimit uint64 diff --git a/miner/worker.go b/miner/worker.go index 7cabaf043930..3075d9d910cc 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -33,18 +33,11 @@ import ( "github.com/scroll-tech/go-ethereum/core/types" "github.com/scroll-tech/go-ethereum/core/vm" "github.com/scroll-tech/go-ethereum/event" - "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/params" "github.com/scroll-tech/go-ethereum/trie" ) -var ( - tracerPool = sync.Pool{ - New: func() interface{} { return vm.NewStructLogger(&vm.LogConfig{EnableMemory: true}) }, - } -) - const ( // resultQueueSize is the size of channel listening to sealing result. resultQueueSize = 10 @@ -99,13 +92,13 @@ type environment struct { header *types.Header txs []*types.Transaction receipts []*types.Receipt - executionResults []*ethapi.ExecutionResult + executionResults []*types.ExecutionResult } // task contains all information for consensus engine sealing and result submitting. type task struct { receipts []*types.Receipt - executionResults []*ethapi.ExecutionResult + executionResults []*types.ExecutionResult state *state.StateDB block *types.Block createdAt time.Time @@ -141,7 +134,6 @@ type worker struct { // Feeds pendingLogsFeed event.Feed - evmTracesFeed event.Feed // Subscriptions mux *event.TypeMux @@ -645,7 +637,7 @@ func (w *worker) resultLoop() { // Different block could share same sealhash, deep copy here to prevent write-write conflict. var ( receipts = make([]*types.Receipt, len(task.receipts)) - evmTraces = make([]*ethapi.ExecutionResult, len(task.executionResults)) + evmTraces = make([]*types.ExecutionResult, len(task.executionResults)) logs []*types.Log ) for i, taskReceipt := range task.receipts { @@ -653,7 +645,7 @@ func (w *worker) resultLoop() { receipts[i] = receipt *receipt = *taskReceipt - evmTrace := new(ethapi.ExecutionResult) + evmTrace := new(types.ExecutionResult) evmTraces[i] = evmTrace *evmTrace = *task.executionResults[i] @@ -674,15 +666,11 @@ func (w *worker) resultLoop() { logs = append(logs, receipt.Logs...) } // Commit block and state to database. - _, err := w.chain.WriteBlockWithState(block, receipts, logs, task.state, true) + _, err := w.chain.WriteBlockWithState(block, receipts, logs, evmTraces, task.state, true) if err != nil { log.Error("Failed writing block to chain", "err", err) continue } - w.evmTracesFeed.Send(evmTraces) - if err := w.eth.WriteEvmTraces(hash, evmTraces); err != nil { - log.Error("Failed writing evmTrace list to db", "err", err) - } w.chain.Genesis() log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealhash, "hash", hash, "elapsed", common.PrettyDuration(time.Since(task.createdAt))) @@ -793,27 +781,21 @@ func (w *worker) updateSnapshot() { func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { snap := w.current.state.Snapshot() - // Enables debugging and set tracer. - tracer := tracerPool.Get().(*vm.StructLogger) - defer func() { - tracer.Reset() - tracerPool.Put(tracer) - }() - config := *w.chain.GetVMConfig() - config.Debug = true - config.Tracer = tracer + // reset tracer. + tracer := w.chain.GetVMConfig().Tracer.(*vm.StructLogger) + tracer.Reset() - receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, config) + receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, *w.chain.GetVMConfig()) if err != nil { w.current.state.RevertToSnapshot(snap) return nil, err } w.current.txs = append(w.current.txs, tx) w.current.receipts = append(w.current.receipts, receipt) - w.current.executionResults = append(w.current.executionResults, ðapi.ExecutionResult{ + w.current.executionResults = append(w.current.executionResults, &types.ExecutionResult{ Gas: receipt.GasUsed, Failed: receipt.Status == types.ReceiptStatusSuccessful, - StructLogs: ethapi.FormatLogs(tracer.StructLogs()), + StructLogs: vm.FormatLogs(tracer.StructLogs()), }) return receipt.Logs, nil @@ -1107,8 +1089,8 @@ func copyReceipts(receipts []*types.Receipt) []*types.Receipt { return result } -func copyExecutionResults(executionResults []*ethapi.ExecutionResult) []*ethapi.ExecutionResult { - result := make([]*ethapi.ExecutionResult, len(executionResults)) +func copyExecutionResults(executionResults []*types.ExecutionResult) []*types.ExecutionResult { + result := make([]*types.ExecutionResult, len(executionResults)) for i, l := range executionResults { cpy := *l result[i] = &cpy diff --git a/miner/worker_test.go b/miner/worker_test.go index c851439b51ed..010eb6cd16c9 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -35,7 +35,6 @@ import ( "github.com/scroll-tech/go-ethereum/crypto" "github.com/scroll-tech/go-ethereum/ethdb" "github.com/scroll-tech/go-ethereum/event" - "github.com/scroll-tech/go-ethereum/internal/ethapi" "github.com/scroll-tech/go-ethereum/params" ) @@ -167,10 +166,6 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain } func (b *testWorkerBackend) TxPool() *core.TxPool { return b.txPool } -func (b *testWorkerBackend) WriteEvmTraces(hash common.Hash, evmTraces []*ethapi.ExecutionResult) error { - return nil -} -func (b *testWorkerBackend) DeleteEvmTraces(hash common.Hash) error { return nil } func (b *testWorkerBackend) newRandomUncle() *types.Block { var parent *types.Block From f5446f342a67faf2b20ed85d926edd495e325d48 Mon Sep 17 00:00:00 2001 From: maskpp Date: Tue, 18 Jan 2022 20:12:30 +0800 Subject: [PATCH 12/37] Fix miner bug. --- miner/worker_test.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/miner/worker_test.go b/miner/worker_test.go index 010eb6cd16c9..49324cc92edc 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -135,7 +135,9 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine } genesis := gspec.MustCommit(db) - chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{ + Debug: true, + Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true})}, nil, nil) txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain) // Generate a small n-block chain and an uncle block for it @@ -232,7 +234,9 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool) { // This test chain imports the mined blocks. db2 := rawdb.NewMemoryDatabase() b.genesis.MustCommit(db2) - chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{ + Debug: true, + Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true})}, nil, nil) defer chain.Stop() // Ignore empty commit here for less noise. From 5da523aae6dc4a83e377ef6bfa31074b3540c94b Mon Sep 17 00:00:00 2001 From: maskpp Date: Tue, 18 Jan 2022 21:42:46 +0800 Subject: [PATCH 13/37] upgrade evmTrace api --- eth/api.go | 4 ++-- ethclient/ethclient.go | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/eth/api.go b/eth/api.go index db91c7fa81e4..13d4d463cf89 100644 --- a/eth/api.go +++ b/eth/api.go @@ -618,7 +618,7 @@ func NewPublicTraceAPI(eth *Ethereum) *PublicTraceAPI { return &PublicTraceAPI{eth} } -// GetEvmTracesByHash returns the block's evmTrace list by blockHash. -func (api *PublicTraceAPI) GetEvmTracesByHash(blockHash common.Hash) ([]*types.ExecutionResult, error) { +// EvmTracesByHash returns the block's evmTrace list by blockHash. +func (api *PublicTraceAPI) EvmTracesByHash(blockHash common.Hash) ([]*types.ExecutionResult, error) { return rawdb.ReadEvmTraces(api.e.chainDb, blockHash), nil } diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 3dd087e85404..dc71a97417ce 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -325,8 +325,17 @@ func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) return ec.c.EthSubscribe(ctx, ch, "newHeads") } +// EvmTracesByHash returns the evmTraces. +func (ec *Client) EvmTracesByHash(ctx context.Context, blockHash common.Hash) ([]*types.ExecutionResult, error) { + var traces []*types.ExecutionResult + if err := ec.c.CallContext(ctx, &traces, "eth_evmTracesByHash"); err != nil { + return nil, err + } + return traces, nil +} + // SubscribeNewEvmTraces subscribe to evmTraces when new block created. -func (ec *Client) SubscribeNewEvmTraces(ctx context.Context, ch chan<- *types.ExecutionResult) (ethereum.Subscription, error) { +func (ec *Client) SubscribeNewEvmTraces(ctx context.Context, ch chan<- []*types.ExecutionResult) (ethereum.Subscription, error) { return ec.c.EthSubscribe(ctx, ch, "newEvmTraces") } From 9aea333c22b729b26b2a52d6d5c2cb40432602a5 Mon Sep 17 00:00:00 2001 From: maskpp Date: Wed, 19 Jan 2022 15:12:35 +0800 Subject: [PATCH 14/37] fix bug about evmTracesByHash api --- ethclient/ethclient.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index dc71a97417ce..7ec721f2e2ed 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -328,7 +328,7 @@ func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) // EvmTracesByHash returns the evmTraces. func (ec *Client) EvmTracesByHash(ctx context.Context, blockHash common.Hash) ([]*types.ExecutionResult, error) { var traces []*types.ExecutionResult - if err := ec.c.CallContext(ctx, &traces, "eth_evmTracesByHash"); err != nil { + if err := ec.c.CallContext(ctx, &traces, "eth_evmTracesByHash", blockHash); err != nil { return nil, err } return traces, nil From e59132325c356f68a41681107f86753def92942e Mon Sep 17 00:00:00 2001 From: maskpp Date: Wed, 19 Jan 2022 21:03:30 +0800 Subject: [PATCH 15/37] Fix the bug about block.timestamp and remove unnecessary copy. --- miner/worker.go | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 3075d9d910cc..20e9e77b0064 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -396,10 +396,10 @@ func (w *worker) newWorkLoop(recommit time.Duration) { timestamp = time.Now().Unix() commit(false, commitInterruptNewHead) - /*case head := <-w.chainHeadCh: - clearPending(head.Block.NumberU64()) - timestamp = time.Now().Unix() - commit(false, commitInterruptNewHead)*/ + case head := <-w.chainHeadCh: + clearPending(head.Block.NumberU64()) + timestamp = time.Now().Unix() + //commit(false, commitInterruptNewHead) case <-timer.C: // If mining is running resubmit a new work cycle periodically to pull in @@ -671,7 +671,6 @@ func (w *worker) resultLoop() { log.Error("Failed writing block to chain", "err", err) continue } - w.chain.Genesis() log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealhash, "hash", hash, "elapsed", common.PrettyDuration(time.Since(task.createdAt))) @@ -1051,7 +1050,6 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) func (w *worker) commit(uncles []*types.Header, interval func(), update bool, start time.Time) error { // Deep copy receipts here to avoid interaction between different tasks. receipts := copyReceipts(w.current.receipts) - executionResults := copyExecutionResults(w.current.executionResults) s := w.current.state.Copy() block, err := w.engine.FinalizeAndAssemble(w.chain, w.current.header, s, w.current.txs, uncles, receipts) if err != nil { @@ -1062,7 +1060,7 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st interval() } select { - case w.taskCh <- &task{receipts: receipts, executionResults: executionResults, state: s, block: block, createdAt: time.Now()}: + case w.taskCh <- &task{receipts: receipts, executionResults: w.current.executionResults, state: s, block: block, createdAt: time.Now()}: w.unconfirmed.Shift(block.NumberU64() - 1) log.Info("Commit new mining work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()), "uncles", len(uncles), "txs", w.current.tcount, @@ -1089,15 +1087,6 @@ func copyReceipts(receipts []*types.Receipt) []*types.Receipt { return result } -func copyExecutionResults(executionResults []*types.ExecutionResult) []*types.ExecutionResult { - result := make([]*types.ExecutionResult, len(executionResults)) - for i, l := range executionResults { - cpy := *l - result[i] = &cpy - } - return result -} - // postSideBlock fires a side chain event, only use it for testing. func (w *worker) postSideBlock(event core.ChainSideEvent) { select { From dca013ee6f465db639d3970caed4dc00a251b96b Mon Sep 17 00:00:00 2001 From: maskpp <32827930+mask-pp@users.noreply.github.com> Date: Thu, 20 Jan 2022 12:01:49 +0800 Subject: [PATCH 16/37] Update eth/filters/api.go Co-authored-by: Haichen Shen --- eth/filters/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/filters/api.go b/eth/filters/api.go index b528d31bbb9c..c5a7d39882e6 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -278,7 +278,7 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc return rpcSub, nil } -// NewEvmTraces send evmTrace list when a new block is created. +// NewEvmTraces sends the EVM trace list when a new block is created. func (api *PublicFilterAPI) NewEvmTraces(ctx context.Context) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) if !supported { From a3ee4a602eb96acb34d5cc4d8e27469ae3fe73a7 Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 20 Jan 2022 12:20:28 +0800 Subject: [PATCH 17/37] Upgrade comments. --- core/blockchain.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/blockchain.go b/core/blockchain.go index fff221dbb23b..143227991888 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1187,7 +1187,6 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. return NonStatTy, errInsertionInterrupted } defer bc.chainmu.Unlock() - //rawdb.WriteEvmTraces(bc.db, block.Hash(), evmTraces) return bc.writeBlockWithState(block, receipts, logs, evmTraces, state, emitHeadEvent) } @@ -1646,6 +1645,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er // Write the block to the chain and get the status. substart = time.Now() + // EvmTraces is nil is safe because l2geth's p2p server is stoped and the code will not execute there. status, err := bc.writeBlockWithState(block, receipts, logs, nil, statedb, false) atomic.StoreUint32(&followupInterrupt, 1) if err != nil { From 53496e0847f1c9ba521a636ef827a345ab0a2a46 Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 20 Jan 2022 14:18:47 +0800 Subject: [PATCH 18/37] Delete useless code in test file --- core/rawdb/l2trace_test.go | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/core/rawdb/l2trace_test.go b/core/rawdb/l2trace_test.go index dd0f25ab66ba..9e4b2d812a7b 100644 --- a/core/rawdb/l2trace_test.go +++ b/core/rawdb/l2trace_test.go @@ -12,35 +12,6 @@ import ( "github.com/scroll-tech/go-ethereum/rlp" ) -// TODO reference code -/*func traceOps(db ethdb.Database, code []byte) (*types.ExecutionResult, error) { - newState, err := state.New(common.Hash{}, state.NewDatabase(db), nil) - if err != nil { - return nil, errors.Wrap(err, "failed to initialize new state") - } - toAddress := common.Address{0xff} - newState.SetCode(toAddress, code) - config := &runtime.Config{ - GasLimit: 1000000, - State: newState, - } - tracer := vm.NewStructLogger(&vm.LogConfig{EnableMemory: true}) - // Overwrite config with tracer - config.EVMConfig.Debug = true - config.EVMConfig.Tracer = tracer - - res, _, err := runtime.Call(toAddress, nil, config) - if err != nil { - return nil, errors.Wrap(err, "transaction fails") - } - return &types.ExecutionResult{ - Gas: 1, - Failed: false, - ReturnValue: fmt.Sprintf("%x", res), - StructLogs: vm.FormatLogs(tracer.StructLogs()), - }, nil -}*/ - func TestBlockEvmTracesStorage(t *testing.T) { db := NewMemoryDatabase() From 74085e9e77eca492c28a7522462d29c451a5f901 Mon Sep 17 00:00:00 2001 From: maskpp <32827930+mask-pp@users.noreply.github.com> Date: Thu, 20 Jan 2022 14:20:44 +0800 Subject: [PATCH 19/37] Update miner/worker.go Co-authored-by: Haichen Shen --- miner/worker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/worker.go b/miner/worker.go index 20e9e77b0064..e9d574bb2b07 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -98,7 +98,7 @@ type environment struct { // task contains all information for consensus engine sealing and result submitting. type task struct { receipts []*types.Receipt - executionResults []*types.ExecutionResult + blockResult *types.BlockResult state *state.StateDB block *types.Block createdAt time.Time From a111436dcf5ea4cc4c9329a9b299ae96fb2582ab Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 20 Jan 2022 15:28:19 +0800 Subject: [PATCH 20/37] Change the return result to BlockResult. --- core/blockchain.go | 10 ++++---- core/events.go | 8 +++---- core/rawdb/l2trace.go | 26 ++++++++++----------- core/rawdb/l2trace_test.go | 16 ++++++------- core/rawdb/schema.go | 8 +++---- core/types/l2trace.go | 24 ++++++++++++++++++++ eth/api.go | 6 ++--- eth/filters/api.go | 8 +++---- eth/filters/filter_system.go | 44 ++++++++++++++++++------------------ ethclient/ethclient.go | 12 +++++----- miner/worker.go | 4 ++-- 11 files changed, 95 insertions(+), 71 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 143227991888..2cfb1d8f6b15 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1182,17 +1182,17 @@ func (bc *BlockChain) writeKnownBlock(block *types.Block) error { } // WriteBlockWithState writes the block and all associated state to the database. -func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, evmTraces []*types.ExecutionResult, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) { +func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, blockResult *types.BlockResult, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) { if !bc.chainmu.TryLock() { return NonStatTy, errInsertionInterrupted } defer bc.chainmu.Unlock() - return bc.writeBlockWithState(block, receipts, logs, evmTraces, state, emitHeadEvent) + return bc.writeBlockWithState(block, receipts, logs, blockResult, state, emitHeadEvent) } // writeBlockWithState writes the block and all associated state to the database, // but is expects the chain mutex to be held. -func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, evmTraces []*types.ExecutionResult, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) { +func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, blockResult *types.BlockResult, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) { if bc.insertStopped() { return NonStatTy, errInsertionInterrupted } @@ -1215,7 +1215,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd) rawdb.WriteBlock(blockBatch, block) rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts) - rawdb.WriteEvmTraces(blockBatch, block.Hash(), evmTraces) + rawdb.WriteBlockResult(blockBatch, block.Hash(), blockResult) rawdb.WritePreimages(blockBatch, state.Preimages()) if err := blockBatch.Write(); err != nil { log.Crit("Failed to write block into disk", "err", err) @@ -1315,7 +1315,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. bc.futureBlocks.Remove(block.Hash()) if status == CanonStatTy { - bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs, Traces: evmTraces}) + bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs, BlockResult: blockResult}) if len(logs) > 0 { bc.logsFeed.Send(logs) } diff --git a/core/events.go b/core/events.go index 4f93cb0946fe..cce09dffd8ca 100644 --- a/core/events.go +++ b/core/events.go @@ -31,10 +31,10 @@ type NewMinedBlockEvent struct{ Block *types.Block } type RemovedLogsEvent struct{ Logs []*types.Log } type ChainEvent struct { - Block *types.Block - Hash common.Hash - Logs []*types.Log - Traces []*types.ExecutionResult + Block *types.Block + Hash common.Hash + Logs []*types.Log + BlockResult *types.BlockResult } type ChainSideEvent struct { diff --git a/core/rawdb/l2trace.go b/core/rawdb/l2trace.go index ab7aa7f8241e..c6ef93924df8 100644 --- a/core/rawdb/l2trace.go +++ b/core/rawdb/l2trace.go @@ -8,32 +8,32 @@ import ( "github.com/scroll-tech/go-ethereum/rlp" ) -// ReadEvmTraces retrieves all the evmTraces belonging to a block. -func ReadEvmTraces(db ethdb.Reader, hash common.Hash) []*types.ExecutionResult { - data, _ := db.Get(evmTracesKey(hash)) +// 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 evmTraces []*types.ExecutionResult - if err := rlp.DecodeBytes(data, &evmTraces); err != nil { + var blockResult types.BlockResult + if err := rlp.DecodeBytes(data, &blockResult); err != nil { log.Error("Failed to decode evmTraces", "err", err) return nil } - return evmTraces + return &blockResult } -// WriteEvmTraces stores evmTrace list into leveldb. -func WriteEvmTraces(db ethdb.KeyValueWriter, hash common.Hash, evmTraces []*types.ExecutionResult) { - bytes, err := rlp.EncodeToBytes(evmTraces) +// 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 evmTraces", "err", err) } - db.Put(evmTracesKey(hash), bytes) + db.Put(blockResultKey(hash), bytes) } -// DeleteEvmTraces removes all evmTraces with a block hash. -func DeleteEvmTraces(db ethdb.KeyValueWriter, hash common.Hash) { - if err := db.Delete(evmTracesKey(hash)); err != nil { +// 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 evmTraces", "err", err) } } diff --git a/core/rawdb/l2trace_test.go b/core/rawdb/l2trace_test.go index 9e4b2d812a7b..1ec4fae79557 100644 --- a/core/rawdb/l2trace_test.go +++ b/core/rawdb/l2trace_test.go @@ -317,19 +317,19 @@ func TestBlockEvmTracesStorage(t *testing.T) { evmTraces := []*types.ExecutionResult{evmTrace1, evmTrace2} hash := common.BytesToHash([]byte{0x03, 0x04}) - // Insert the evmTrace list into the database and check presence. - WriteEvmTraces(db, hash, evmTraces) - // Read evmTrace list from db. - if traces := ReadEvmTraces(db, hash); len(traces) == 0 { + // Insert the blockResult into the database and check presence. + WriteBlockResult(db, hash, &types.BlockResult{ExecutionResult: evmTraces}) + // Read blockResult from db. + if blockResult := ReadBlockResult(db, hash); len(blockResult.ExecutionResult) == 0 { t.Fatalf("No evmTraces returned") } else { - if err := checkEvmTracesRLP(traces, evmTraces); err != nil { + if err := checkEvmTracesRLP(blockResult.ExecutionResult, evmTraces); err != nil { t.Fatalf(err.Error()) } } - // Delete evmTrace list by blockHash. - DeleteEvmTraces(db, hash) - if traces := ReadEvmTraces(db, hash); len(traces) != 0 { + // Delete blockResult by blockHash. + DeleteBlockResult(db, hash) + if blockResult := ReadBlockResult(db, hash); blockResult != nil && len(blockResult.ExecutionResult) != 0 { t.Fatalf("The evmTrace list should be empty.") } } diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 25cfae7022cd..7efd2368c0a8 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -89,7 +89,7 @@ var ( SnapshotAccountPrefix = []byte("a") // SnapshotAccountPrefix + account hash -> account trie value SnapshotStoragePrefix = []byte("o") // SnapshotStoragePrefix + account hash + storage hash -> storage trie value CodePrefix = []byte("c") // CodePrefix + code hash -> account code - evmTracesPrefix = []byte("e") // evmTracesPrefix + hash -> evmTrace list + blockResultPrefix = []byte("e") // blockResultPrefix + hash -> blockResult PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage configPrefix = []byte("ethereum-config-") // config prefix for the db @@ -232,7 +232,7 @@ func configKey(hash common.Hash) []byte { return append(configPrefix, hash.Bytes()...) } -// evmTracesKey = evmTracesPrefix + hash -func evmTracesKey(hash common.Hash) []byte { - return append(evmTracesPrefix, hash.Bytes()...) +// blockResultKey = blockResultPrefix + hash +func blockResultKey(hash common.Hash) []byte { + return append(blockResultPrefix, hash.Bytes()...) } diff --git a/core/types/l2trace.go b/core/types/l2trace.go index fe7049654eee..c7c7d100d8fd 100644 --- a/core/types/l2trace.go +++ b/core/types/l2trace.go @@ -8,6 +8,30 @@ import ( "github.com/scroll-tech/go-ethereum/rlp" ) +// BlockResult returns block execute result for rollers. +type BlockResult struct { + ExecutionResult []*ExecutionResult `json:"executionResult"` +} + +type rlpBlockResult struct { + ExecutionResult []*ExecutionResult `json:"executionResult"` +} + +func (b *BlockResult) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, &rlpBlockResult{ + ExecutionResult: b.ExecutionResult, + }) +} + +func (b *BlockResult) DecodeRLP(s *rlp.Stream) error { + var dec rlpBlockResult + err := s.Decode(&dec) + if err == nil { + b.ExecutionResult = dec.ExecutionResult + } + return err +} + // ExecutionResult groups all structured logs emitted by the EVM // while replaying a transaction in debug mode as well as transaction // execution status, the amount of gas used and the return value diff --git a/eth/api.go b/eth/api.go index 13d4d463cf89..41dcb0683be4 100644 --- a/eth/api.go +++ b/eth/api.go @@ -618,7 +618,7 @@ func NewPublicTraceAPI(eth *Ethereum) *PublicTraceAPI { return &PublicTraceAPI{eth} } -// EvmTracesByHash returns the block's evmTrace list by blockHash. -func (api *PublicTraceAPI) EvmTracesByHash(blockHash common.Hash) ([]*types.ExecutionResult, error) { - return rawdb.ReadEvmTraces(api.e.chainDb, blockHash), nil +// BlockResultByHash returns the blockResult by blockHash. +func (api *PublicTraceAPI) BlockResultByHash(blockHash common.Hash) (*types.BlockResult, error) { + return rawdb.ReadBlockResult(api.e.chainDb, blockHash), nil } diff --git a/eth/filters/api.go b/eth/filters/api.go index c5a7d39882e6..3817a3bc8416 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -278,8 +278,8 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc return rpcSub, nil } -// NewEvmTraces sends the EVM trace list when a new block is created. -func (api *PublicFilterAPI) NewEvmTraces(ctx context.Context) (*rpc.Subscription, error) { +// NewBlockResult sends the EVM trace list when a new block is created. +func (api *PublicFilterAPI) NewBlockResult(ctx context.Context) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) if !supported { return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported @@ -288,8 +288,8 @@ func (api *PublicFilterAPI) NewEvmTraces(ctx context.Context) (*rpc.Subscription rpcSub := notifier.CreateSubscription() go func() { - evmTraces := make(chan []*types.ExecutionResult) - evmTracesSub := api.events.SubscribeEvmTraces(evmTraces) + evmTraces := make(chan *types.BlockResult) + evmTracesSub := api.events.SubscribeBlockResult(evmTraces) for { select { diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index c65d992fa3fc..2646d1fff5e1 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -52,8 +52,8 @@ const ( PendingTransactionsSubscription // BlocksSubscription queries hashes for blocks that are imported BlocksSubscription - // EvmTracesSubscription queries evmTrace list when new block created - EvmTracesSubscription + // BlockResultSubscription queries evmTrace list when new block created + BlockResultSubscription // LastSubscription keeps track of the last index LastIndexSubscription ) @@ -71,16 +71,16 @@ const ( ) type subscription struct { - id rpc.ID - typ Type - created time.Time - logsCrit ethereum.FilterQuery - logs chan []*types.Log - hashes chan []common.Hash - headers chan *types.Header - evmTraces chan []*types.ExecutionResult - installed chan struct{} // closed when the filter is installed - err chan error // closed when the filter is uninstalled + id rpc.ID + typ Type + created time.Time + logsCrit ethereum.FilterQuery + logs chan []*types.Log + hashes chan []common.Hash + headers chan *types.Header + blockResult chan *types.BlockResult + installed chan struct{} // closed when the filter is installed + err chan error // closed when the filter is uninstalled } // EventSystem creates subscriptions, processes events and broadcasts them to the @@ -293,15 +293,15 @@ func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscripti return es.subscribe(sub) } -// SubscribeEvmTraces creates a subscription that writes the evmTraces when a new block is created. -func (es *EventSystem) SubscribeEvmTraces(evmTraces chan []*types.ExecutionResult) *Subscription { +// SubscribeBlockResult creates a subscription that writes the evmTraces when a new block is created. +func (es *EventSystem) SubscribeBlockResult(blockResult chan *types.BlockResult) *Subscription { sub := &subscription{ - id: rpc.NewID(), - typ: EvmTracesSubscription, - created: time.Now(), - evmTraces: evmTraces, - installed: make(chan struct{}), - err: make(chan error), + id: rpc.NewID(), + typ: BlockResultSubscription, + created: time.Now(), + blockResult: blockResult, + installed: make(chan struct{}), + err: make(chan error), } return es.subscribe(sub) } @@ -371,8 +371,8 @@ func (es *EventSystem) handleChainEvent(filters filterIndex, ev core.ChainEvent) for _, f := range filters[BlocksSubscription] { f.headers <- ev.Block.Header() } - for _, f := range filters[EvmTracesSubscription] { - f.evmTraces <- ev.Traces + for _, f := range filters[BlockResultSubscription] { + f.blockResult <- ev.BlockResult } if es.lightMode && len(filters[LogsSubscription]) > 0 { es.lightFilterNewHead(ev.Block.Header(), func(header *types.Header, remove bool) { diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 7ec721f2e2ed..21e4c8b063c8 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -325,18 +325,18 @@ func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) return ec.c.EthSubscribe(ctx, ch, "newHeads") } -// EvmTracesByHash returns the evmTraces. -func (ec *Client) EvmTracesByHash(ctx context.Context, blockHash common.Hash) ([]*types.ExecutionResult, error) { +// BlockResultByHash returns the blockResult. +func (ec *Client) BlockResultByHash(ctx context.Context, blockHash common.Hash) ([]*types.ExecutionResult, error) { var traces []*types.ExecutionResult - if err := ec.c.CallContext(ctx, &traces, "eth_evmTracesByHash", blockHash); err != nil { + if err := ec.c.CallContext(ctx, &traces, "eth_blockResultByHash", blockHash); err != nil { return nil, err } return traces, nil } -// SubscribeNewEvmTraces subscribe to evmTraces when new block created. -func (ec *Client) SubscribeNewEvmTraces(ctx context.Context, ch chan<- []*types.ExecutionResult) (ethereum.Subscription, error) { - return ec.c.EthSubscribe(ctx, ch, "newEvmTraces") +// SubscribeNewBlockResult subscribe to blockResult when new block created. +func (ec *Client) SubscribeNewBlockResult(ctx context.Context, ch chan<- *types.BlockResult) (ethereum.Subscription, error) { + return ec.c.EthSubscribe(ctx, ch, "newBlockResult") } // State Access diff --git a/miner/worker.go b/miner/worker.go index e9d574bb2b07..878a323206b8 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -98,7 +98,7 @@ type environment struct { // task contains all information for consensus engine sealing and result submitting. type task struct { receipts []*types.Receipt - blockResult *types.BlockResult + executionResults []*types.ExecutionResult state *state.StateDB block *types.Block createdAt time.Time @@ -666,7 +666,7 @@ func (w *worker) resultLoop() { logs = append(logs, receipt.Logs...) } // Commit block and state to database. - _, err := w.chain.WriteBlockWithState(block, receipts, logs, evmTraces, task.state, true) + _, err := w.chain.WriteBlockWithState(block, receipts, logs, &types.BlockResult{ExecutionResult: evmTraces}, task.state, true) if err != nil { log.Error("Failed writing block to chain", "err", err) continue From 78d8393fca9abe433389765fb0223e67f5687337 Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 20 Jan 2022 15:34:15 +0800 Subject: [PATCH 21/37] Change return type. --- ethclient/ethclient.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 21e4c8b063c8..c6abcbed8418 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -326,12 +326,12 @@ func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) } // BlockResultByHash returns the blockResult. -func (ec *Client) BlockResultByHash(ctx context.Context, blockHash common.Hash) ([]*types.ExecutionResult, error) { - var traces []*types.ExecutionResult - if err := ec.c.CallContext(ctx, &traces, "eth_blockResultByHash", blockHash); err != nil { +func (ec *Client) BlockResultByHash(ctx context.Context, blockHash common.Hash) (*types.BlockResult, error) { + var blockResult types.BlockResult + if err := ec.c.CallContext(ctx, &blockResult, "eth_blockResultByHash", blockHash); err != nil { return nil, err } - return traces, nil + return &blockResult, nil } // SubscribeNewBlockResult subscribe to blockResult when new block created. From e6f8b78c30f607aca50aaa6a03c4ade721715ab6 Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 20 Jan 2022 20:35:13 +0800 Subject: [PATCH 22/37] Change blockResult to blockResults. --- core/rawdb/l2trace_test.go | 8 ++++---- core/types/l2trace.go | 8 ++++---- eth/filters/api.go | 16 +++++++-------- eth/filters/filter_system.go | 40 ++++++++++++++++++------------------ ethclient/ethclient.go | 6 +++--- miner/worker.go | 2 +- 6 files changed, 40 insertions(+), 40 deletions(-) diff --git a/core/rawdb/l2trace_test.go b/core/rawdb/l2trace_test.go index 1ec4fae79557..aa184ba658fc 100644 --- a/core/rawdb/l2trace_test.go +++ b/core/rawdb/l2trace_test.go @@ -318,18 +318,18 @@ func TestBlockEvmTracesStorage(t *testing.T) { 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{ExecutionResult: evmTraces}) + WriteBlockResult(db, hash, &types.BlockResult{ExecutionResults: evmTraces}) // Read blockResult from db. - if blockResult := ReadBlockResult(db, hash); len(blockResult.ExecutionResult) == 0 { + if blockResult := ReadBlockResult(db, hash); len(blockResult.ExecutionResults) == 0 { t.Fatalf("No evmTraces returned") } else { - if err := checkEvmTracesRLP(blockResult.ExecutionResult, evmTraces); err != nil { + 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.ExecutionResult) != 0 { + if blockResult := ReadBlockResult(db, hash); blockResult != nil && len(blockResult.ExecutionResults) != 0 { t.Fatalf("The evmTrace list should be empty.") } } diff --git a/core/types/l2trace.go b/core/types/l2trace.go index c7c7d100d8fd..a739fb7dda9b 100644 --- a/core/types/l2trace.go +++ b/core/types/l2trace.go @@ -10,16 +10,16 @@ import ( // BlockResult returns block execute result for rollers. type BlockResult struct { - ExecutionResult []*ExecutionResult `json:"executionResult"` + ExecutionResults []*ExecutionResult `json:"executionResults"` } type rlpBlockResult struct { - ExecutionResult []*ExecutionResult `json:"executionResult"` + ExecutionResults []*ExecutionResult `json:"executionResults"` } func (b *BlockResult) EncodeRLP(w io.Writer) error { return rlp.Encode(w, &rlpBlockResult{ - ExecutionResult: b.ExecutionResult, + ExecutionResults: b.ExecutionResults, }) } @@ -27,7 +27,7 @@ func (b *BlockResult) DecodeRLP(s *rlp.Stream) error { var dec rlpBlockResult err := s.Decode(&dec) if err == nil { - b.ExecutionResult = dec.ExecutionResult + b.ExecutionResults = dec.ExecutionResults } return err } diff --git a/eth/filters/api.go b/eth/filters/api.go index 3817a3bc8416..208b6a74f0a0 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -278,8 +278,8 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc return rpcSub, nil } -// NewBlockResult sends the EVM trace list when a new block is created. -func (api *PublicFilterAPI) NewBlockResult(ctx context.Context) (*rpc.Subscription, error) { +// NewBlockResults sends the blockResult when a new block is created. +func (api *PublicFilterAPI) NewBlockResults(ctx context.Context) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) if !supported { return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported @@ -288,18 +288,18 @@ func (api *PublicFilterAPI) NewBlockResult(ctx context.Context) (*rpc.Subscripti rpcSub := notifier.CreateSubscription() go func() { - evmTraces := make(chan *types.BlockResult) - evmTracesSub := api.events.SubscribeBlockResult(evmTraces) + blockResultsCh := make(chan *types.BlockResult) + blockResultsSub := api.events.SubscribeBlockResult(blockResultsCh) for { select { - case traces := <-evmTraces: - notifier.Notify(rpcSub.ID, traces) + case blockResult := <-blockResultsCh: + notifier.Notify(rpcSub.ID, blockResult) case <-rpcSub.Err(): - evmTracesSub.Unsubscribe() + blockResultsSub.Unsubscribe() return case <-notifier.Closed(): - evmTracesSub.Unsubscribe() + blockResultsSub.Unsubscribe() return } } diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index 2646d1fff5e1..fed24d73c49f 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -52,8 +52,8 @@ const ( PendingTransactionsSubscription // BlocksSubscription queries hashes for blocks that are imported BlocksSubscription - // BlockResultSubscription queries evmTrace list when new block created - BlockResultSubscription + // BlockResultsSubscription queries evmTrace list when new block created + BlockResultsSubscription // LastSubscription keeps track of the last index LastIndexSubscription ) @@ -71,16 +71,16 @@ const ( ) type subscription struct { - id rpc.ID - typ Type - created time.Time - logsCrit ethereum.FilterQuery - logs chan []*types.Log - hashes chan []common.Hash - headers chan *types.Header - blockResult chan *types.BlockResult - installed chan struct{} // closed when the filter is installed - err chan error // closed when the filter is uninstalled + id rpc.ID + typ Type + created time.Time + logsCrit ethereum.FilterQuery + logs chan []*types.Log + hashes chan []common.Hash + headers chan *types.Header + blockResults chan *types.BlockResult + installed chan struct{} // closed when the filter is installed + err chan error // closed when the filter is uninstalled } // EventSystem creates subscriptions, processes events and broadcasts them to the @@ -296,12 +296,12 @@ func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscripti // SubscribeBlockResult creates a subscription that writes the evmTraces when a new block is created. func (es *EventSystem) SubscribeBlockResult(blockResult chan *types.BlockResult) *Subscription { sub := &subscription{ - id: rpc.NewID(), - typ: BlockResultSubscription, - created: time.Now(), - blockResult: blockResult, - installed: make(chan struct{}), - err: make(chan error), + id: rpc.NewID(), + typ: BlockResultsSubscription, + created: time.Now(), + blockResults: blockResult, + installed: make(chan struct{}), + err: make(chan error), } return es.subscribe(sub) } @@ -371,8 +371,8 @@ func (es *EventSystem) handleChainEvent(filters filterIndex, ev core.ChainEvent) for _, f := range filters[BlocksSubscription] { f.headers <- ev.Block.Header() } - for _, f := range filters[BlockResultSubscription] { - f.blockResult <- ev.BlockResult + for _, f := range filters[BlockResultsSubscription] { + f.blockResults <- ev.BlockResult } if es.lightMode && len(filters[LogsSubscription]) > 0 { es.lightFilterNewHead(ev.Block.Header(), func(header *types.Header, remove bool) { diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index c6abcbed8418..bf5608578fd8 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -334,9 +334,9 @@ func (ec *Client) BlockResultByHash(ctx context.Context, blockHash common.Hash) return &blockResult, nil } -// SubscribeNewBlockResult subscribe to blockResult when new block created. -func (ec *Client) SubscribeNewBlockResult(ctx context.Context, ch chan<- *types.BlockResult) (ethereum.Subscription, error) { - return ec.c.EthSubscribe(ctx, ch, "newBlockResult") +// SubscribeNewBlockResults subscribe to blockResult when new block created. +func (ec *Client) SubscribeNewBlockResults(ctx context.Context, ch chan<- *types.BlockResult) (ethereum.Subscription, error) { + return ec.c.EthSubscribe(ctx, ch, "newBlockResults") } // State Access diff --git a/miner/worker.go b/miner/worker.go index 878a323206b8..36632b3ae1aa 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -666,7 +666,7 @@ func (w *worker) resultLoop() { logs = append(logs, receipt.Logs...) } // Commit block and state to database. - _, err := w.chain.WriteBlockWithState(block, receipts, logs, &types.BlockResult{ExecutionResult: evmTraces}, task.state, true) + _, err := w.chain.WriteBlockWithState(block, receipts, logs, &types.BlockResult{ExecutionResults: evmTraces}, task.state, true) if err != nil { log.Error("Failed writing block to chain", "err", err) continue From c3a52b642e8d3e317e49a15e2656bb4ca530df86 Mon Sep 17 00:00:00 2001 From: maskpp Date: Fri, 21 Jan 2022 11:15:29 +0800 Subject: [PATCH 23/37] Add ReturnValue. --- core/rawdb/l2trace_test.go | 4 ++-- core/state_processor.go | 7 ++++++- core/types/l2trace.go | 18 ++++++++++-------- core/types/receipt.go | 3 +++ miner/worker.go | 8 +++++--- 5 files changed, 26 insertions(+), 14 deletions(-) diff --git a/core/rawdb/l2trace_test.go b/core/rawdb/l2trace_test.go index aa184ba658fc..d9ccf91ffaf8 100644 --- a/core/rawdb/l2trace_test.go +++ b/core/rawdb/l2trace_test.go @@ -226,7 +226,7 @@ func TestBlockEvmTracesStorage(t *testing.T) { } ] }`) - evmTrace1 := &types.ExecutionResult{} + evmTrace1 := &types.ExecutionResult{ReturnValue: "0xaaa"} if err := json.Unmarshal(data1, evmTrace1); err != nil { t.Fatalf(err.Error()) } @@ -310,7 +310,7 @@ func TestBlockEvmTracesStorage(t *testing.T) { } ] }`) - evmTrace2 := &types.ExecutionResult{} + evmTrace2 := &types.ExecutionResult{ReturnValue: "0xbbb"} if err := json.Unmarshal(data2, evmTrace2); err != nil { t.Fatalf(err.Error()) } diff --git a/core/state_processor.go b/core/state_processor.go index f5898cbf8122..5d8d55726753 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -112,9 +112,14 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon } *usedGas += result.UsedGas + // If the result contains a revert reason, return it. + returnVal := result.Return() + if len(result.Revert()) > 0 { + returnVal = result.Revert() + } // Create a new receipt for the transaction, storing the intermediate root and gas used // by the tx. - receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas} + receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas, ReturnValue: returnVal} if result.Failed() { receipt.Status = types.ReceiptStatusFailed } else { diff --git a/core/types/l2trace.go b/core/types/l2trace.go index a739fb7dda9b..10ab6f7223f0 100644 --- a/core/types/l2trace.go +++ b/core/types/l2trace.go @@ -38,21 +38,23 @@ func (b *BlockResult) DecodeRLP(s *rlp.Stream) error { type ExecutionResult struct { Gas uint64 `json:"gas"` Failed bool `json:"failed"` - ReturnValue string `json:"returnValue"` + ReturnValue string `json:"returnValue,omitempty"` StructLogs []StructLogRes `json:"structLogs"` } type rlpExecutionResult struct { - Gas uint64 - Failed bool - StructLogs []StructLogRes + Gas uint64 + Failed bool + ReturnValue string `json:"returnValue,omitempty"` + StructLogs []StructLogRes } func (e *ExecutionResult) EncodeRLP(w io.Writer) error { return rlp.Encode(w, rlpExecutionResult{ - Gas: e.Gas, - Failed: e.Failed, - StructLogs: e.StructLogs, + Gas: e.Gas, + Failed: e.Failed, + ReturnValue: e.ReturnValue, + StructLogs: e.StructLogs, }) } @@ -60,7 +62,7 @@ func (e *ExecutionResult) DecodeRLP(s *rlp.Stream) error { var dec rlpExecutionResult err := s.Decode(&dec) if err == nil { - e.Gas, e.Failed, e.StructLogs = dec.Gas, dec.Failed, dec.StructLogs + e.Gas, e.Failed, e.ReturnValue, e.StructLogs = dec.Gas, dec.Failed, dec.ReturnValue, dec.StructLogs } return err } diff --git a/core/types/receipt.go b/core/types/receipt.go index 28cab6db0542..bf20cfbc65d8 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -70,6 +70,9 @@ type Receipt struct { BlockHash common.Hash `json:"blockHash,omitempty"` BlockNumber *big.Int `json:"blockNumber,omitempty"` TransactionIndex uint `json:"transactionIndex"` + + // The value of evm execution result. + ReturnValue []byte `json:"returnValue,omitempty"` } type receiptMarshaling struct { diff --git a/miner/worker.go b/miner/worker.go index 36632b3ae1aa..7b238405ff41 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -19,6 +19,7 @@ package miner import ( "bytes" "errors" + "fmt" "math/big" "sync" "sync/atomic" @@ -792,9 +793,10 @@ func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Addres w.current.txs = append(w.current.txs, tx) w.current.receipts = append(w.current.receipts, receipt) w.current.executionResults = append(w.current.executionResults, &types.ExecutionResult{ - Gas: receipt.GasUsed, - Failed: receipt.Status == types.ReceiptStatusSuccessful, - StructLogs: vm.FormatLogs(tracer.StructLogs()), + Gas: receipt.GasUsed, + Failed: receipt.Status == types.ReceiptStatusSuccessful, + ReturnValue: fmt.Sprintf("%x", receipt.ReturnValue), + StructLogs: vm.FormatLogs(tracer.StructLogs()), }) return receipt.Logs, nil From e613a6bd9069947525b9925f98ea111358c4a5fa Mon Sep 17 00:00:00 2001 From: maskpp <32827930+mask-pp@users.noreply.github.com> Date: Fri, 21 Jan 2022 15:26:15 +0800 Subject: [PATCH 24/37] Update core/rawdb/l2trace.go Co-authored-by: Haichen Shen --- core/rawdb/l2trace.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/rawdb/l2trace.go b/core/rawdb/l2trace.go index c6ef93924df8..26e516d29e99 100644 --- a/core/rawdb/l2trace.go +++ b/core/rawdb/l2trace.go @@ -16,7 +16,7 @@ func ReadBlockResult(db ethdb.Reader, hash common.Hash) *types.BlockResult { } var blockResult types.BlockResult if err := rlp.DecodeBytes(data, &blockResult); err != nil { - log.Error("Failed to decode evmTraces", "err", err) + log.Error("Failed to decode BlockResult", "err", err) return nil } return &blockResult From adcb40d992d2b4efd1eb55a36119bd04d2e1d4b0 Mon Sep 17 00:00:00 2001 From: maskpp <32827930+mask-pp@users.noreply.github.com> Date: Fri, 21 Jan 2022 15:26:23 +0800 Subject: [PATCH 25/37] Update core/rawdb/l2trace.go Co-authored-by: Haichen Shen --- core/rawdb/l2trace.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/rawdb/l2trace.go b/core/rawdb/l2trace.go index 26e516d29e99..24b59b7975cc 100644 --- a/core/rawdb/l2trace.go +++ b/core/rawdb/l2trace.go @@ -34,6 +34,6 @@ func WriteBlockResult(db ethdb.KeyValueWriter, hash common.Hash, blockResult *ty // 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 evmTraces", "err", err) + log.Crit("Failed to delete BlockResult", "err", err) } } From a0db670900dda8388e2e1e31aa14824d50d2b6bc Mon Sep 17 00:00:00 2001 From: maskpp <32827930+mask-pp@users.noreply.github.com> Date: Fri, 21 Jan 2022 15:26:47 +0800 Subject: [PATCH 26/37] Update core/types/l2trace.go Co-authored-by: Haichen Shen --- core/types/l2trace.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/types/l2trace.go b/core/types/l2trace.go index 10ab6f7223f0..620f33ddf2ac 100644 --- a/core/types/l2trace.go +++ b/core/types/l2trace.go @@ -8,7 +8,7 @@ import ( "github.com/scroll-tech/go-ethereum/rlp" ) -// BlockResult returns block execute result for rollers. +// BlockResult contains block execution traces and results required for rollers. type BlockResult struct { ExecutionResults []*ExecutionResult `json:"executionResults"` } From 3b8e1e14bbf9973efd163894ef56ad47147eba76 Mon Sep 17 00:00:00 2001 From: maskpp Date: Fri, 21 Jan 2022 15:31:24 +0800 Subject: [PATCH 27/37] Add indent to the comment and rm json encoding flag. --- core/types/l2trace.go | 2 +- miner/worker.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/types/l2trace.go b/core/types/l2trace.go index 620f33ddf2ac..1dbb5b669c30 100644 --- a/core/types/l2trace.go +++ b/core/types/l2trace.go @@ -45,7 +45,7 @@ type ExecutionResult struct { type rlpExecutionResult struct { Gas uint64 Failed bool - ReturnValue string `json:"returnValue,omitempty"` + ReturnValue string StructLogs []StructLogRes } diff --git a/miner/worker.go b/miner/worker.go index 7b238405ff41..e0e56f8f3f99 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -400,7 +400,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) { case head := <-w.chainHeadCh: clearPending(head.Block.NumberU64()) timestamp = time.Now().Unix() - //commit(false, commitInterruptNewHead) + // commit(false, commitInterruptNewHead) case <-timer.C: // If mining is running resubmit a new work cycle periodically to pull in From db3557c56e55cec65aef97b85ba2f424a0030b82 Mon Sep 17 00:00:00 2001 From: maskpp Date: Fri, 21 Jan 2022 15:33:56 +0800 Subject: [PATCH 28/37] Rm json encoding flag. --- core/types/l2trace.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/types/l2trace.go b/core/types/l2trace.go index 1dbb5b669c30..43758088a9fb 100644 --- a/core/types/l2trace.go +++ b/core/types/l2trace.go @@ -14,7 +14,7 @@ type BlockResult struct { } type rlpBlockResult struct { - ExecutionResults []*ExecutionResult `json:"executionResults"` + ExecutionResults []*ExecutionResult } func (b *BlockResult) EncodeRLP(w io.Writer) error { From ced2001a75f4d30930faa39286ea1b7b2ce0ba9f Mon Sep 17 00:00:00 2001 From: maskpp <32827930+mask-pp@users.noreply.github.com> Date: Fri, 21 Jan 2022 15:36:01 +0800 Subject: [PATCH 29/37] Update core/rawdb/l2trace.go Co-authored-by: Haichen Shen --- core/rawdb/l2trace.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/rawdb/l2trace.go b/core/rawdb/l2trace.go index 24b59b7975cc..ee82d02b4b02 100644 --- a/core/rawdb/l2trace.go +++ b/core/rawdb/l2trace.go @@ -26,7 +26,7 @@ func ReadBlockResult(db ethdb.Reader, hash common.Hash) *types.BlockResult { 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 evmTraces", "err", err) + log.Crit("Failed to RLP encode BlockResult", "err", err) } db.Put(blockResultKey(hash), bytes) } From e67813d379f0c9f95e5c070aa45fd4a9bf9955f7 Mon Sep 17 00:00:00 2001 From: maskpp Date: Fri, 21 Jan 2022 21:20:59 +0800 Subject: [PATCH 30/37] Rm json encoding flag. --- core/types/l2trace.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/core/types/l2trace.go b/core/types/l2trace.go index 43758088a9fb..4537a48cac03 100644 --- a/core/types/l2trace.go +++ b/core/types/l2trace.go @@ -82,15 +82,15 @@ type StructLogRes struct { } type rlpStructLogRes struct { - Pc uint64 `json:"pc"` - Op string `json:"op"` - Gas uint64 `json:"gas"` - GasCost uint64 `json:"gasCost"` - Depth uint `json:"depth"` - Error string `json:"error,omitempty"` - Stack []string `json:"stack,omitempty"` - Memory []string `json:"memory,omitempty"` - Storage []string `json:"storage,omitempty"` + Pc uint64 + Op string + Gas uint64 + GasCost uint64 + Depth uint + Error string + Stack []string + Memory []string + Storage []string } // EncodeRLP implements rlp.Encoder. From 36c0f14c5374fc1fda6b93e3fa36db9a6c89c6dc Mon Sep 17 00:00:00 2001 From: maskpp <32827930+mask-pp@users.noreply.github.com> Date: Fri, 21 Jan 2022 21:26:17 +0800 Subject: [PATCH 31/37] Update ethclient/ethclient.go Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> --- ethclient/ethclient.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index bf5608578fd8..c6abcbed8418 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -334,9 +334,9 @@ func (ec *Client) BlockResultByHash(ctx context.Context, blockHash common.Hash) return &blockResult, nil } -// SubscribeNewBlockResults subscribe to blockResult when new block created. -func (ec *Client) SubscribeNewBlockResults(ctx context.Context, ch chan<- *types.BlockResult) (ethereum.Subscription, error) { - return ec.c.EthSubscribe(ctx, ch, "newBlockResults") +// SubscribeNewBlockResult subscribe to blockResult when new block created. +func (ec *Client) SubscribeNewBlockResult(ctx context.Context, ch chan<- *types.BlockResult) (ethereum.Subscription, error) { + return ec.c.EthSubscribe(ctx, ch, "newBlockResult") } // State Access From e187a7f3fe155c6dfac4b29623014f022226acc1 Mon Sep 17 00:00:00 2001 From: maskpp <32827930+mask-pp@users.noreply.github.com> Date: Fri, 21 Jan 2022 21:26:47 +0800 Subject: [PATCH 32/37] Update eth/filters/api.go Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> --- eth/filters/api.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/eth/filters/api.go b/eth/filters/api.go index 208b6a74f0a0..341fb37e7b9c 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -278,8 +278,8 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc return rpcSub, nil } -// NewBlockResults sends the blockResult when a new block is created. -func (api *PublicFilterAPI) NewBlockResults(ctx context.Context) (*rpc.Subscription, error) { +// NewBlockResult sends the blockResult when a new block is created. +func (api *PublicFilterAPI) NewBlockResult(ctx context.Context) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) if !supported { return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported @@ -288,12 +288,12 @@ func (api *PublicFilterAPI) NewBlockResults(ctx context.Context) (*rpc.Subscript rpcSub := notifier.CreateSubscription() go func() { - blockResultsCh := make(chan *types.BlockResult) - blockResultsSub := api.events.SubscribeBlockResult(blockResultsCh) + blockResults := make(chan *types.BlockResult) + blockResultsSub := api.events.SubscribeBlockResult(blockResults) for { select { - case blockResult := <-blockResultsCh: + case blockResult := <-blockResults: notifier.Notify(rpcSub.ID, blockResult) case <-rpcSub.Err(): blockResultsSub.Unsubscribe() From ed57fe200c677432bac6c4e93829fb2992251c4f Mon Sep 17 00:00:00 2001 From: maskpp Date: Fri, 21 Jan 2022 21:28:17 +0800 Subject: [PATCH 33/37] Use as the blockResult prefix flag. --- core/rawdb/schema.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 7efd2368c0a8..eb9e2808ffb0 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -89,7 +89,7 @@ var ( SnapshotAccountPrefix = []byte("a") // SnapshotAccountPrefix + account hash -> account trie value SnapshotStoragePrefix = []byte("o") // SnapshotStoragePrefix + account hash + storage hash -> storage trie value CodePrefix = []byte("c") // CodePrefix + code hash -> account code - blockResultPrefix = []byte("e") // blockResultPrefix + hash -> blockResult + blockResultPrefix = []byte("T") // blockResultPrefix + hash -> blockResult PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage configPrefix = []byte("ethereum-config-") // config prefix for the db From fc06df698b6d84035f8ec0659bf206ba7d090c39 Mon Sep 17 00:00:00 2001 From: maskpp <32827930+mask-pp@users.noreply.github.com> Date: Sat, 22 Jan 2022 13:26:19 +0800 Subject: [PATCH 34/37] Update eth/filters/filter_system.go Co-authored-by: Haichen Shen --- eth/filters/filter_system.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index fed24d73c49f..c243c6d3d6df 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -293,7 +293,7 @@ func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscripti return es.subscribe(sub) } -// SubscribeBlockResult creates a subscription that writes the evmTraces when a new block is created. +// SubscribeBlockResult creates a subscription that writes the block trace when a new block is created. func (es *EventSystem) SubscribeBlockResult(blockResult chan *types.BlockResult) *Subscription { sub := &subscription{ id: rpc.NewID(), From 19f9e234bbb397479af8e5015c531a2a745acd14 Mon Sep 17 00:00:00 2001 From: maskpp <32827930+mask-pp@users.noreply.github.com> Date: Sat, 22 Jan 2022 13:26:40 +0800 Subject: [PATCH 35/37] Update eth/filters/filter_system.go Co-authored-by: Haichen Shen --- eth/filters/filter_system.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index c243c6d3d6df..c9ca0a6e110f 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -52,7 +52,7 @@ const ( PendingTransactionsSubscription // BlocksSubscription queries hashes for blocks that are imported BlocksSubscription - // BlockResultsSubscription queries evmTrace list when new block created + // BlockResultsSubscription queries for block execution traces BlockResultsSubscription // LastSubscription keeps track of the last index LastIndexSubscription From e5cacd089be3f2c9f55282b5f66911a876744a19 Mon Sep 17 00:00:00 2001 From: maskpp <32827930+mask-pp@users.noreply.github.com> Date: Sat, 22 Jan 2022 13:26:57 +0800 Subject: [PATCH 36/37] Update ethclient/ethclient.go Co-authored-by: Haichen Shen --- ethclient/ethclient.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index c6abcbed8418..040962dcc442 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -334,7 +334,7 @@ func (ec *Client) BlockResultByHash(ctx context.Context, blockHash common.Hash) return &blockResult, nil } -// SubscribeNewBlockResult subscribe to blockResult when new block created. +// SubscribeNewBlockResult subscribes to block execution trace when a new block is created. func (ec *Client) SubscribeNewBlockResult(ctx context.Context, ch chan<- *types.BlockResult) (ethereum.Subscription, error) { return ec.c.EthSubscribe(ctx, ch, "newBlockResult") } From 719ed61618f0c76b8f6c96c91204ecdc9e3a0e53 Mon Sep 17 00:00:00 2001 From: maskpp <32827930+mask-pp@users.noreply.github.com> Date: Sat, 22 Jan 2022 13:27:04 +0800 Subject: [PATCH 37/37] Update eth/filters/api.go Co-authored-by: Haichen Shen --- eth/filters/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/filters/api.go b/eth/filters/api.go index 341fb37e7b9c..52dbcca9d33c 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -278,7 +278,7 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc return rpcSub, nil } -// NewBlockResult sends the blockResult when a new block is created. +// NewBlockResult sends the block execution result when a new block is created. func (api *PublicFilterAPI) NewBlockResult(ctx context.Context) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) if !supported {