diff --git a/core/store/ledgerstore/ledger_store.go b/core/store/ledgerstore/ledger_store.go
index a2fdaede7..f29a071d3 100644
--- a/core/store/ledgerstore/ledger_store.go
+++ b/core/store/ledgerstore/ledger_store.go
@@ -16,6 +16,7 @@
* along with The ontology. If not, see .
*/
//Storage of ledger
+
package ledgerstore
import (
@@ -1447,7 +1448,15 @@ func (this *LedgerStoreImp) PreExecuteContract(tx *types.Transaction) (*sstate.P
return this.PreExecuteContractWithParam(tx, param)
}
+func (this *LedgerStoreImp) TraceEip155Tx(msg types3.Message, tracer evm2.Tracer) (*types5.ExecutionResult, error) {
+ return this.executeEip155Tx(msg, evm2.Config{Debug: true, Tracer: tracer})
+}
+
func (this *LedgerStoreImp) PreExecuteEip155Tx(msg types3.Message) (*types5.ExecutionResult, error) {
+ return this.executeEip155Tx(msg, evm2.Config{})
+}
+
+func (this *LedgerStoreImp) executeEip155Tx(msg types3.Message, conf evm2.Config) (*types5.ExecutionResult, error) {
height := this.GetCurrentBlockHeight()
// use previous block time to make it predictable for easy test
blockTime := uint32(time.Now().Unix())
@@ -1466,7 +1475,7 @@ func (this *LedgerStoreImp) PreExecuteEip155Tx(msg types3.Message) (*types5.Exec
blockContext := evm.NewEVMBlockContext(height, blockTime, this)
cache := this.GetCacheDB()
statedb := storage.NewStateDB(cache, common2.Hash{}, common2.Hash(ctx.BlockHash), ong.OngBalanceHandle{})
- vmenv := evm2.NewEVM(blockContext, txContext, statedb, config, evm2.Config{})
+ vmenv := evm2.NewEVM(blockContext, txContext, statedb, config, conf)
res, err := evm.ApplyMessage(vmenv, msg, common2.Address(utils.GovernanceContractAddress))
return res, err
}
diff --git a/core/store/store.go b/core/store/store.go
index c04acdec1..e2449c187 100644
--- a/core/store/store.go
+++ b/core/store/store.go
@@ -32,6 +32,7 @@ import (
types3 "github.com/ontio/ontology/smartcontract/service/evm/types"
cstates "github.com/ontio/ontology/smartcontract/states"
"github.com/ontio/ontology/smartcontract/storage"
+ "github.com/ontio/ontology/vm/evm"
)
type ExecuteResult struct {
@@ -78,6 +79,7 @@ type LedgerStore interface {
PreExecuteContract(tx *types.Transaction) (*cstates.PreExecResult, error)
PreExecuteContractBatch(txes []*types.Transaction, atomic bool) ([]*cstates.PreExecResult, uint32, error)
PreExecuteEip155Tx(msg types2.Message) (*types3.ExecutionResult, error)
+ TraceEip155Tx(msg types2.Message, tracer evm.Tracer) (*types3.ExecutionResult, error)
GetEventNotifyByTx(tx common.Uint256) (*event.ExecuteNotify, error)
GetEventNotifyByBlock(height uint32) ([]*event.ExecuteNotify, error)
GetEthCode(hash common2.Hash) ([]byte, error)
diff --git a/http/ethrpc/debug/tracer.go b/http/ethrpc/debug/tracer.go
new file mode 100644
index 000000000..2d9c371c9
--- /dev/null
+++ b/http/ethrpc/debug/tracer.go
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2018 The ontology Authors
+ * This file is part of The ontology library.
+ *
+ * The ontology is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The ontology is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with The ontology. If not, see .
+ */
+
+package debug
+
+import (
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/rpc"
+ "github.com/ontio/ontology/core/ledger"
+ "github.com/ontio/ontology/http/ethrpc/eth"
+ types2 "github.com/ontio/ontology/http/ethrpc/types"
+ "github.com/ontio/ontology/vm/evm"
+ "github.com/ontio/ontology/vm/evm/tracers"
+)
+
+// DebugAPI is the collection of tracing APIs exposed over the private debugging endpoint.
+type DebugAPI struct {
+}
+
+// NewDebugAPI creates a new DebugAPI definition for the tracing methods of the Ethereum service.
+func NewDebugAPI() *DebugAPI {
+ return &DebugAPI{}
+}
+
+// TraceConfig holds extra parameters to trace functions.
+type TraceConfig struct {
+ *evm.LogConfig
+ Tracer *string
+ Timeout *string
+ Reexec *uint64
+}
+
+// TraceCallConfig is the config for traceCall DebugAPI. It holds one more
+// field to override the state for tracing.
+type TraceCallConfig struct {
+ *evm.LogConfig
+ Tracer *string
+ Timeout *string
+ Reexec *uint64
+ //StateOverrides *ethapi.StateOverride
+}
+
+// TraceCall lets you trace a given eth_call. It collects the structured logs
+// created during the execution of EVM if the given transaction was added on
+// top of the provided block and returns them as a JSON object.
+// You can provide -2 as a block number to trace on top of the pending block.
+func (api *DebugAPI) TraceCall(args types2.CallArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
+ // Execute the trace
+ msg := args.AsMessage(eth.RPCGasCap)
+
+ var traceConfig *TraceConfig
+ if config != nil {
+ traceConfig = &TraceConfig{
+ LogConfig: config.LogConfig,
+ Tracer: config.Tracer,
+ Timeout: config.Timeout,
+ Reexec: config.Reexec,
+ }
+ }
+ return api.traceTx(msg, traceConfig)
+}
+
+// traceTx configures a new tracer according to the provided configuration, and
+// executes the given message in the provided environment. The return value will
+// be tracer dependent.
+func (api *DebugAPI) traceTx(message types.Message, config *TraceConfig) (interface{}, error) {
+ // Assemble the structured logger or the JavaScript tracer
+ var (
+ tracer evm.Tracer
+ err error
+ )
+ switch {
+ case config == nil:
+ tracer = evm.NewStructLogger(nil)
+ case config.Tracer != nil:
+ switch *config.Tracer {
+ case "callTracer":
+ tracer = tracers.NewCallTracer()
+ default:
+ return nil, fmt.Errorf("unkown tracer type: %s", *config.Tracer)
+ }
+ default:
+ tracer = evm.NewStructLogger(config.LogConfig)
+ }
+
+ result, err := ledger.DefLedger.TraceEip155Tx(message, nil)
+ if err != nil {
+ return nil, fmt.Errorf("tracing failed: %w", err)
+ }
+
+ // Depending on the tracer type, format and return the output.
+ switch tracer := tracer.(type) {
+ case *evm.StructLogger:
+ // If the result contains a revert reason, return it.
+ returnVal := fmt.Sprintf("%x", result.Return())
+ if len(result.Revert()) > 0 {
+ returnVal = fmt.Sprintf("%x", result.Revert())
+ }
+ return &ExecutionResult{
+ Gas: result.UsedGas,
+ Failed: result.Failed(),
+ ReturnValue: returnVal,
+ StructLogs: FormatLogs(tracer.StructLogs()),
+ }, nil
+
+ case *tracers.CallTracer:
+ return tracer.GetResult()
+
+ default:
+ panic(fmt.Sprintf("bad tracer type %T", tracer))
+ }
+}
diff --git a/http/ethrpc/debug/types.go b/http/ethrpc/debug/types.go
new file mode 100644
index 000000000..630eddcf8
--- /dev/null
+++ b/http/ethrpc/debug/types.go
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 The ontology Authors
+ * This file is part of The ontology library.
+ *
+ * The ontology is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The ontology is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with The ontology. If not, see .
+ */
+
+package debug
+
+import (
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/common/math"
+ "github.com/ontio/ontology/vm/evm"
+)
+
+// 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"`
+}
+
+// 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 error `json:"error,omitempty"`
+ Stack *[]string `json:"stack,omitempty"`
+ Memory *[]string `json:"memory,omitempty"`
+ Storage *map[string]string `json:"storage,omitempty"`
+}
+
+// FormatLogs formats EVM returned structured logs for json output
+func FormatLogs(logs []evm.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.Err,
+ }
+ if trace.Stack != nil {
+ stack := make([]string, len(trace.Stack))
+ for i, stackValue := range trace.Stack {
+ stack[i] = fmt.Sprintf("%x", math.PaddedBigBytes(stackValue, 32))
+ }
+ 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/http/ethrpc/rpc_server.go b/http/ethrpc/rpc_server.go
index d2771a04a..32880c526 100644
--- a/http/ethrpc/rpc_server.go
+++ b/http/ethrpc/rpc_server.go
@@ -28,6 +28,7 @@ import (
"github.com/ontio/ontology/core/store/ledgerstore"
"github.com/ontio/ontology/http/base/actor"
backend2 "github.com/ontio/ontology/http/ethrpc/backend"
+ "github.com/ontio/ontology/http/ethrpc/debug"
"github.com/ontio/ontology/http/ethrpc/eth"
filters2 "github.com/ontio/ontology/http/ethrpc/filters"
"github.com/ontio/ontology/http/ethrpc/net"
@@ -68,6 +69,9 @@ func StartEthServer(txpool *tp.TXPoolServer) error {
if err := server.RegisterName("web3", web3.NewAPI()); err != nil {
return err
}
+ if err := server.RegisterName("debug", debug.NewDebugAPI()); err != nil {
+ return err
+ }
// add cors wrapper
wrappedCORSHandler := node.NewHTTPHandlerStack(server, cors, vhosts)