aboutsummaryrefslogtreecommitdiff
path: root/eth
diff options
context:
space:
mode:
Diffstat (limited to 'eth')
-rw-r--r--eth/api.go128
-rw-r--r--eth/api_backend.go107
-rw-r--r--eth/api_tracer.go90
-rw-r--r--eth/backend.go181
4 files changed, 308 insertions, 198 deletions
diff --git a/eth/api.go b/eth/api.go
index b64090e..92ac928 100644
--- a/eth/api.go
+++ b/eth/api.go
@@ -34,10 +34,10 @@ import (
"github.com/ava-labs/coreth/core/types"
"github.com/ava-labs/coreth/internal/ethapi"
"github.com/ava-labs/coreth/rpc"
- "github.com/ava-labs/go-ethereum/common"
- "github.com/ava-labs/go-ethereum/common/hexutil"
- "github.com/ava-labs/go-ethereum/rlp"
- "github.com/ava-labs/go-ethereum/trie"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/rlp"
+ "github.com/ethereum/go-ethereum/trie"
)
// PublicEthereumAPI provides an API to access Ethereum full node-related
@@ -166,8 +166,21 @@ func NewPrivateAdminAPI(eth *Ethereum) *PrivateAdminAPI {
return &PrivateAdminAPI{eth: eth}
}
-// ExportChain exports the current blockchain into a local file.
-func (api *PrivateAdminAPI) ExportChain(file string) (bool, error) {
+// ExportChain exports the current blockchain into a local file,
+// or a range of blocks if first and last are non-nil
+func (api *PrivateAdminAPI) ExportChain(file string, first *uint64, last *uint64) (bool, error) {
+ if first == nil && last != nil {
+ return false, errors.New("last cannot be specified without first")
+ }
+ if first != nil && last == nil {
+ head := api.eth.BlockChain().CurrentHeader().Number.Uint64()
+ last = &head
+ }
+ if _, err := os.Stat(file); err == nil {
+ // File already exists. Allowing overwrite could be a DoS vecotor,
+ // since the 'file' may point to arbitrary paths on the drive
+ return false, errors.New("location would overwrite an existing file")
+ }
// Make sure we can create the file to export into
out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
if err != nil {
@@ -182,7 +195,11 @@ func (api *PrivateAdminAPI) ExportChain(file string) (bool, error) {
}
// Export the blockchain
- if err := api.eth.BlockChain().Export(writer); err != nil {
+ if first != nil {
+ if err := api.eth.BlockChain().ExportN(writer, *first, *last); err != nil {
+ return false, err
+ }
+ } else if err := api.eth.BlockChain().Export(writer); err != nil {
return false, err
}
return true, nil
@@ -336,70 +353,52 @@ func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs,
return results, nil
}
-// AccountRangeResult returns a mapping from the hash of an account addresses
-// to its preimage. It will return the JSON null if no preimage is found.
-// Since a query can return a limited amount of results, a "next" field is
-// also present for paging.
-type AccountRangeResult struct {
- Accounts map[common.Hash]*common.Address `json:"accounts"`
- Next common.Hash `json:"next"`
-}
-
-func accountRange(st state.Trie, start *common.Hash, maxResults int) (AccountRangeResult, error) {
- if start == nil {
- start = &common.Hash{0}
- }
- it := trie.NewIterator(st.NodeIterator(start.Bytes()))
- result := AccountRangeResult{Accounts: make(map[common.Hash]*common.Address), Next: common.Hash{}}
-
- if maxResults > AccountRangeMaxResults {
- maxResults = AccountRangeMaxResults
- }
-
- for i := 0; i < maxResults && it.Next(); i++ {
- if preimage := st.GetKey(it.Key); preimage != nil {
- addr := &common.Address{}
- addr.SetBytes(preimage)
- result.Accounts[common.BytesToHash(it.Key)] = addr
- } else {
- result.Accounts[common.BytesToHash(it.Key)] = nil
- }
- }
-
- if it.Next() {
- result.Next = common.BytesToHash(it.Key)
- }
-
- return result, nil
-}
-
// AccountRangeMaxResults is the maximum number of results to be returned per call
const AccountRangeMaxResults = 256
-// AccountRange enumerates all accounts in the latest state
-func (api *PrivateDebugAPI) AccountRange(ctx context.Context, start *common.Hash, maxResults int) (AccountRangeResult, error) {
- var statedb *state.StateDB
+// AccountRange enumerates all accounts in the given block and start point in paging request
+func (api *PublicDebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start []byte, maxResults int, nocode, nostorage, incompletes bool) (state.IteratorDump, error) {
+ var stateDb *state.StateDB
var err error
- block := api.eth.blockchain.CurrentBlock()
- if len(block.Transactions()) == 0 {
- statedb, err = api.computeStateDB(block, defaultTraceReexec)
- if err != nil {
- return AccountRangeResult{}, err
+ if number, ok := blockNrOrHash.Number(); ok {
+ if number == rpc.PendingBlockNumber {
+ // If we're dumping the pending state, we need to request
+ // both the pending block as well as the pending state from
+ // the miner and operate on those
+ _, stateDb = api.eth.miner.Pending()
+ } else {
+ var block *types.Block
+ if number == rpc.LatestBlockNumber {
+ block = api.eth.blockchain.CurrentBlock()
+ } else if blockNr == rpc.AcceptedBlockNumber {
+ block = api.eth.AcceptedBlock()
+ } else {
+ block = api.eth.blockchain.GetBlockByNumber(uint64(number))
+ }
+ if block == nil {
+ return state.IteratorDump{}, fmt.Errorf("block #%d not found", number)
+ }
+ stateDb, err = api.eth.BlockChain().StateAt(block.Root())
+ if err != nil {
+ return state.IteratorDump{}, err
+ }
}
- } else {
- _, _, statedb, err = api.computeTxEnv(block.Hash(), len(block.Transactions())-1, 0)
+ } else if hash, ok := blockNrOrHash.Hash(); ok {
+ block := api.eth.blockchain.GetBlockByHash(hash)
+ if block == nil {
+ return state.IteratorDump{}, fmt.Errorf("block %s not found", hash.Hex())
+ }
+ stateDb, err = api.eth.BlockChain().StateAt(block.Root())
if err != nil {
- return AccountRangeResult{}, err
+ return state.IteratorDump{}, err
}
}
- trie, err := statedb.Database().OpenTrie(block.Header().Root)
- if err != nil {
- return AccountRangeResult{}, err
+ if maxResults > AccountRangeMaxResults || maxResults <= 0 {
+ maxResults = AccountRangeMaxResults
}
-
- return accountRange(trie, start, maxResults)
+ return stateDb.IteratorDump(nocode, nostorage, incompletes, start, maxResults), nil
}
// StorageRangeResult is the result of a debug_storageRangeAt API call.
@@ -416,8 +415,13 @@ type storageEntry struct {
}
// StorageRangeAt returns the storage at the given block height and transaction index.
-func (api *PrivateDebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) {
- _, _, statedb, err := api.computeTxEnv(blockHash, txIndex, 0)
+func (api *PrivateDebugAPI) StorageRangeAt(blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) {
+ // Retrieve the block
+ block := api.eth.blockchain.GetBlockByHash(blockHash)
+ if block == nil {
+ return StorageRangeResult{}, fmt.Errorf("block %#x not found", blockHash)
+ }
+ _, _, statedb, err := api.computeTxEnv(block, txIndex, 0)
if err != nil {
return StorageRangeResult{}, err
}
diff --git a/eth/api_backend.go b/eth/api_backend.go
index d4061f8..65c3be4 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -22,20 +22,21 @@ import (
"math/big"
"github.com/ava-labs/coreth/accounts"
+ "github.com/ava-labs/coreth/consensus"
"github.com/ava-labs/coreth/core"
"github.com/ava-labs/coreth/core/rawdb"
"github.com/ava-labs/coreth/core/state"
"github.com/ava-labs/coreth/core/types"
"github.com/ava-labs/coreth/core/vm"
"github.com/ava-labs/coreth/eth/gasprice"
+ "github.com/ava-labs/coreth/miner"
"github.com/ava-labs/coreth/params"
"github.com/ava-labs/coreth/rpc"
- "github.com/ava-labs/go-ethereum/common"
- "github.com/ava-labs/go-ethereum/common/math"
- "github.com/ava-labs/go-ethereum/core/bloombits"
- "github.com/ava-labs/go-ethereum/eth/downloader"
- "github.com/ava-labs/go-ethereum/ethdb"
- "github.com/ava-labs/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/bloombits"
+ "github.com/ethereum/go-ethereum/eth/downloader"
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/event"
)
// EthAPIBackend implements ethapi.Backend for full nodes
@@ -79,6 +80,23 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb
return b.eth.blockchain.GetHeaderByNumber(uint64(number)), nil
}
+func (b *EthAPIBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) {
+ if blockNr, ok := blockNrOrHash.Number(); ok {
+ return b.HeaderByNumber(ctx, blockNr)
+ }
+ if hash, ok := blockNrOrHash.Hash(); ok {
+ header := b.eth.blockchain.GetHeaderByHash(hash)
+ if header == nil {
+ return nil, errors.New("header for hash not found")
+ }
+ if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash {
+ return nil, errors.New("hash is not currently canonical")
+ }
+ return header, nil
+ }
+ return nil, errors.New("invalid arguments; neither block nor hash specified")
+}
+
func (b *EthAPIBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
return b.eth.blockchain.GetHeaderByHash(hash), nil
}
@@ -103,6 +121,27 @@ func (b *EthAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*typ
return b.eth.blockchain.GetBlockByHash(hash), nil
}
+func (b *EthAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) {
+ if blockNr, ok := blockNrOrHash.Number(); ok {
+ return b.BlockByNumber(ctx, blockNr)
+ }
+ if hash, ok := blockNrOrHash.Hash(); ok {
+ header := b.eth.blockchain.GetHeaderByHash(hash)
+ if header == nil {
+ return nil, errors.New("header for hash not found")
+ }
+ if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash {
+ return nil, errors.New("hash is not currently canonical")
+ }
+ block := b.eth.blockchain.GetBlock(hash, header.Number.Uint64())
+ if block == nil {
+ return nil, errors.New("header found, but block body is missing")
+ }
+ return block, nil
+ }
+ return nil, errors.New("invalid arguments; neither block nor hash specified")
+}
+
func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
// Pending state is only known by the miner
if number == rpc.PendingBlockNumber {
@@ -121,6 +160,27 @@ func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.B
return stateDb, header, err
}
+func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
+ if blockNr, ok := blockNrOrHash.Number(); ok {
+ return b.StateAndHeaderByNumber(ctx, blockNr)
+ }
+ if hash, ok := blockNrOrHash.Hash(); ok {
+ header, err := b.HeaderByHash(ctx, hash)
+ if err != nil {
+ return nil, nil, err
+ }
+ if header == nil {
+ return nil, nil, errors.New("header for hash not found")
+ }
+ if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash {
+ return nil, nil, errors.New("hash is not currently canonical")
+ }
+ stateDb, err := b.eth.BlockChain().StateAt(header.Root)
+ return stateDb, header, err
+ }
+ return nil, nil, errors.New("invalid arguments; neither block nor hash specified")
+}
+
func (b *EthAPIBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
return b.eth.blockchain.GetReceiptsByHash(hash), nil
}
@@ -137,12 +197,11 @@ func (b *EthAPIBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*typ
return logs, nil
}
-func (b *EthAPIBackend) GetTd(blockHash common.Hash) *big.Int {
- return b.eth.blockchain.GetTdByHash(blockHash)
+func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
+ return b.eth.blockchain.GetTdByHash(hash)
}
func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header) (*vm.EVM, func() error, error) {
- state.SetBalance(msg.From(), math.MaxBig256)
vmError := func() error { return nil }
context := core.NewEVMContext(msg, header, b.eth.BlockChain(), nil)
@@ -153,6 +212,10 @@ func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEven
return b.eth.BlockChain().SubscribeRemovedLogsEvent(ch)
}
+func (b *EthAPIBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription {
+ return b.eth.miner.SubscribePendingLogs(ch)
+}
+
func (b *EthAPIBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
return b.eth.BlockChain().SubscribeChainEvent(ch)
}
@@ -211,6 +274,10 @@ func (b *EthAPIBackend) TxPoolContent() (map[common.Address]types.Transactions,
return b.eth.TxPool().Content()
}
+func (b *EthAPIBackend) TxPool() *core.TxPool {
+ return b.eth.TxPool()
+}
+
func (b *EthAPIBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
return b.eth.TxPool().SubscribeNewTxsEvent(ch)
}
@@ -243,10 +310,14 @@ func (b *EthAPIBackend) ExtRPCEnabled() bool {
return b.extRPCEnabled
}
-func (b *EthAPIBackend) RPCGasCap() *big.Int {
+func (b *EthAPIBackend) RPCGasCap() uint64 {
return b.eth.config.RPCGasCap
}
+func (b *EthAPIBackend) RPCTxFeeCap() float64 {
+ return b.eth.config.RPCTxFeeCap
+}
+
func (b *EthAPIBackend) BloomStatus() (uint64, uint64) {
sections, _, _ := b.eth.bloomIndexer.Sections()
return params.BloomBitsBlocks, sections
@@ -257,3 +328,19 @@ func (b *EthAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma
go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests)
}
}
+
+func (b *EthAPIBackend) Engine() consensus.Engine {
+ return b.eth.engine
+}
+
+func (b *EthAPIBackend) CurrentHeader() *types.Header {
+ return b.eth.blockchain.CurrentHeader()
+}
+
+func (b *EthAPIBackend) Miner() *miner.Miner {
+ return b.eth.Miner()
+}
+
+func (b *EthAPIBackend) StartMining(threads int) error {
+ return b.eth.StartMining(threads)
+}
diff --git a/eth/api_tracer.go b/eth/api_tracer.go
index c8a5307..c044dcc 100644
--- a/eth/api_tracer.go
+++ b/eth/api_tracer.go
@@ -36,11 +36,11 @@ import (
"github.com/ava-labs/coreth/eth/tracers"
"github.com/ava-labs/coreth/internal/ethapi"
"github.com/ava-labs/coreth/rpc"
- "github.com/ava-labs/go-ethereum/common"
- "github.com/ava-labs/go-ethereum/common/hexutil"
- "github.com/ava-labs/go-ethereum/log"
- "github.com/ava-labs/go-ethereum/rlp"
- "github.com/ava-labs/go-ethereum/trie"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/rlp"
+ "github.com/ethereum/go-ethereum/trie"
)
const (
@@ -151,7 +151,7 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl
// Ensure we have a valid starting state before doing any work
origin := start.NumberU64()
- database := state.NewDatabaseWithCache(api.eth.ChainDb(), 16) // Chain tracing will probably start at genesis
+ database := state.NewDatabaseWithCache(api.eth.ChainDb(), 16, "") // Chain tracing will probably start at genesis
if number := start.NumberU64(); number > 0 {
start = api.eth.blockchain.GetBlock(start.ParentHash(), start.NumberU64()-1)
@@ -159,7 +159,7 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl
return nil, fmt.Errorf("parent block #%d not found", number-1)
}
}
- statedb, err := state.New(start.Root(), database)
+ statedb, err := state.New(start.Root(), database, nil)
if err != nil {
// If the starting state is missing, allow some number of blocks to be reexecuted
reexec := defaultTraceReexec
@@ -172,7 +172,7 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl
if start == nil {
break
}
- if statedb, err = state.New(start.Root(), database); err == nil {
+ if statedb, err = state.New(start.Root(), database, nil); err == nil {
break
}
}
@@ -407,7 +407,7 @@ func (api *PrivateDebugAPI) TraceBlockFromFile(ctx context.Context, file string,
return api.TraceBlock(ctx, blob, config)
}
-// TraceBadBlockByHash returns the structured logs created during the execution of
+// TraceBadBlock returns the structured logs created during the execution of
// EVM against a block pulled from the pool of bad ones and returns them as a JSON
// object.
func (api *PrivateDebugAPI) TraceBadBlock(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
@@ -508,7 +508,7 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block,
vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil)
vmenv := vm.NewEVM(vmctx, statedb, api.eth.blockchain.Config(), vm.Config{})
- if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
+ if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
failed = err
break
}
@@ -602,7 +602,7 @@ func (api *PrivateDebugAPI) standardTraceBlockToFile(ctx context.Context, block
}
// Execute the transaction and flush any traces to disk
vmenv := vm.NewEVM(vmctx, statedb, api.eth.blockchain.Config(), vmConf)
- _, _, _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
+ _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
if writer != nil {
writer.Flush()
}
@@ -647,14 +647,14 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (*
}
// Otherwise try to reexec blocks until we find a state or reach our limit
origin := block.NumberU64()
- database := state.NewDatabaseWithCache(api.eth.ChainDb(), 16)
+ database := state.NewDatabaseWithCache(api.eth.ChainDb(), 16, "")
for i := uint64(0); i < reexec; i++ {
block = api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
if block == nil {
break
}
- if statedb, err = state.New(block.Root(), database); err == nil {
+ if statedb, err = state.New(block.Root(), database, nil); err == nil {
break
}
}
@@ -717,7 +717,12 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha
if config != nil && config.Reexec != nil {
reexec = *config.Reexec
}
- msg, vmctx, statedb, err := api.computeTxEnv(blockHash, int(index), reexec)
+ // Retrieve the block
+ block := api.eth.blockchain.GetBlockByHash(blockHash)
+ if block == nil {
+ return nil, fmt.Errorf("block %#x not found", blockHash)
+ }
+ msg, vmctx, statedb, err := api.computeTxEnv(block, int(index), reexec)
if err != nil {
return nil, err
}
@@ -725,6 +730,40 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha
return api.traceTx(ctx, msg, vmctx, statedb, config)
}
+// 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 *PrivateDebugAPI) TraceCall(ctx context.Context, args ethapi.CallArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceConfig) (interface{}, error) {
+ // First try to retrieve the state
+ statedb, header, err := api.eth.APIBackend.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
+ if err != nil {
+ // Try to retrieve the specified block
+ var block *types.Block
+ if hash, ok := blockNrOrHash.Hash(); ok {
+ block = api.eth.blockchain.GetBlockByHash(hash)
+ } else if number, ok := blockNrOrHash.Number(); ok {
+ block = api.eth.blockchain.GetBlockByNumber(uint64(number))
+ }
+ if block == nil {
+ return nil, fmt.Errorf("block %v not found: %v", blockNrOrHash, err)
+ }
+ // try to recompute the state
+ reexec := defaultTraceReexec
+ if config != nil && config.Reexec != nil {
+ reexec = *config.Reexec
+ }
+ _, _, statedb, err = api.computeTxEnv(block, 0, reexec)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ // Execute the trace
+ msg := args.ToMessage(api.eth.APIBackend.RPCGasCap())
+ vmctx := core.NewEVMContext(msg, header, api.eth.blockchain, nil)
+ return api.traceTx(ctx, msg, vmctx, statedb, config)
+}
+
// 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.
@@ -764,17 +803,22 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v
// Run the transaction with tracing enabled.
vmenv := vm.NewEVM(vmctx, statedb, api.eth.blockchain.Config(), vm.Config{Debug: true, Tracer: tracer})
- ret, gas, failed, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
+ result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
if err != nil {
return nil, fmt.Errorf("tracing failed: %v", err)
}
// Depending on the tracer type, format and return the output
switch tracer := tracer.(type) {
case *vm.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 &ethapi.ExecutionResult{
- Gas: gas,
- Failed: failed,
- ReturnValue: fmt.Sprintf("%x", ret),
+ Gas: result.UsedGas,
+ Failed: result.Failed(),
+ ReturnValue: returnVal,
StructLogs: ethapi.FormatLogs(tracer.StructLogs()),
}, nil
@@ -787,12 +831,8 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v
}
// computeTxEnv returns the execution environment of a certain transaction.
-func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, reexec uint64) (core.Message, vm.Context, *state.StateDB, error) {
+func (api *PrivateDebugAPI) computeTxEnv(block *types.Block, txIndex int, reexec uint64) (core.Message, vm.Context, *state.StateDB, error) {
// Create the parent state database
- block := api.eth.blockchain.GetBlockByHash(blockHash)
- if block == nil {
- return nil, vm.Context{}, nil, fmt.Errorf("block %#x not found", blockHash)
- }
parent := api.eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
if parent == nil {
return nil, vm.Context{}, nil, fmt.Errorf("parent %#x not found", block.ParentHash())
@@ -818,12 +858,12 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree
}
// Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewEVM(context, statedb, api.eth.blockchain.Config(), vm.Config{})
- if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
+ if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
return nil, vm.Context{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
}
// Ensure any modifications are committed to the state
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
}
- return nil, vm.Context{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, blockHash)
+ return nil, vm.Context{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
}
diff --git a/eth/backend.go b/eth/backend.go
index 056f8cb..9222181 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -41,27 +41,18 @@ import (
"github.com/ava-labs/coreth/node"
"github.com/ava-labs/coreth/params"
"github.com/ava-labs/coreth/rpc"
- "github.com/ava-labs/go-ethereum/accounts/abi/bind"
- "github.com/ava-labs/go-ethereum/common"
- "github.com/ava-labs/go-ethereum/common/hexutil"
- "github.com/ava-labs/go-ethereum/core/bloombits"
- "github.com/ava-labs/go-ethereum/eth/downloader"
- "github.com/ava-labs/go-ethereum/ethdb"
- "github.com/ava-labs/go-ethereum/event"
- "github.com/ava-labs/go-ethereum/log"
- "github.com/ava-labs/go-ethereum/p2p"
- "github.com/ava-labs/go-ethereum/rlp"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/core/bloombits"
+ "github.com/ethereum/go-ethereum/eth/downloader"
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/rlp"
)
-type LesServer interface {
- Start(srvr *p2p.Server)
- Stop()
- APIs() []rpc.API
- Protocols() []p2p.Protocol
- SetBloomBitsIndexer(bbIndexer *core.ChainIndexer)
- SetContractBackend(bind.ContractBackend)
-}
-
type BackendCallbacks struct {
OnQueryAcceptedBlock func() *types.Block
}
@@ -70,16 +61,11 @@ type BackendCallbacks struct {
type Ethereum struct {
config *Config
- // Channel for shutting down the service
- shutdownChan chan bool
-
- server *p2p.Server
-
// Handlers
txPool *core.TxPool
blockchain *core.BlockChain
//protocolManager *ProtocolManager
- lesServer LesServer
+ dialCandidates enode.Iterator
// DB interfaces
chainDb ethdb.Database // Block chain database
@@ -88,8 +74,9 @@ type Ethereum struct {
engine consensus.Engine
accountManager *accounts.Manager
- bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
- bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports
+ bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests
+ bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports
+ closeBloomHandler chan struct{}
APIBackend *EthAPIBackend
@@ -100,28 +87,17 @@ type Ethereum struct {
networkID uint64
netRPCService *ethapi.PublicNetAPI
+ p2pServer *p2p.Server
+
lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase)
txSubmitChan chan struct{}
bcb *BackendCallbacks
}
-func (s *Ethereum) AddLesServer(ls LesServer) {
- s.lesServer = ls
- ls.SetBloomBitsIndexer(s.bloomIndexer)
-}
-
-// SetClient sets a rpc client which connecting to our local node.
-func (s *Ethereum) SetContractBackend(backend bind.ContractBackend) {
- // Pass the rpc client to les server if it is enabled.
- if s.lesServer != nil {
- s.lesServer.SetContractBackend(backend)
- }
-}
-
// New creates a new Ethereum object (including the
// initialisation of the common Ethereum object)
-func New(ctx *node.ServiceContext, config *Config,
+func New(stack *node.Node, config *Config,
cb *dummy.ConsensusCallbacks,
mcb *miner.MinerCallbacks,
bcb *BackendCallbacks,
@@ -138,7 +114,12 @@ func New(ctx *node.ServiceContext, config *Config,
config.Miner.GasPrice = new(big.Int).Set(DefaultConfig.Miner.GasPrice)
}
if config.NoPruning && config.TrieDirtyCache > 0 {
- config.TrieCleanCache += config.TrieDirtyCache
+ if config.SnapshotCache > 0 {
+ config.TrieCleanCache += config.TrieDirtyCache * 3 / 5
+ config.SnapshotCache += config.TrieDirtyCache * 2 / 5
+ } else {
+ config.TrieCleanCache += config.TrieDirtyCache
+ }
config.TrieDirtyCache = 0
}
log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024)
@@ -151,26 +132,27 @@ func New(ctx *node.ServiceContext, config *Config,
return nil, err
}
}
- chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideIstanbul)
+ chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
return nil, genesisErr
}
log.Info("Initialised chain configuration", "config", chainConfig)
eth := &Ethereum{
- config: config,
- chainDb: chainDb,
- eventMux: ctx.EventMux,
- accountManager: ctx.AccountManager,
- engine: CreateConsensusEngine(ctx, chainConfig, &config.Ethash, config.Miner.Notify, config.Miner.Noverify, chainDb, cb),
- shutdownChan: make(chan bool),
- networkID: config.NetworkId,
- gasPrice: config.Miner.GasPrice,
- etherbase: config.Miner.Etherbase,
- bloomRequests: make(chan chan *bloombits.Retrieval),
- bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms),
- txSubmitChan: make(chan struct{}, 1),
- bcb: bcb,
+ config: config,
+ chainDb: chainDb,
+ eventMux: stack.EventMux(),
+ accountManager: stack.AccountManager(),
+ engine: CreateConsensusEngine(stack, chainConfig, &config.Ethash, config.Miner.Notify, config.Miner.Noverify, chainDb, cb),
+ closeBloomHandler: make(chan struct{}),
+ networkID: config.NetworkId,
+ gasPrice: config.Miner.GasPrice,
+ etherbase: config.Miner.Etherbase,
+ bloomRequests: make(chan chan *bloombits.Retrieval),
+ bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms),
+ p2pServer: stack.Server(),
+ txSubmitChan: make(chan struct{}, 1),
+ bcb: bcb,
}
bcVersion := rawdb.ReadDatabaseVersion(chainDb)
@@ -196,13 +178,16 @@ func New(ctx *node.ServiceContext, config *Config,
}
cacheConfig = &core.CacheConfig{
TrieCleanLimit: config.TrieCleanCache,
+ TrieCleanJournal: stack.ResolvePath(config.TrieCleanCacheJournal),
+ TrieCleanRejournal: config.TrieCleanCacheRejournal,
TrieCleanNoPrefetch: config.NoPrefetch,
TrieDirtyLimit: config.TrieDirtyCache,
TrieDirtyDisabled: config.NoPruning,
TrieTimeLimit: config.TrieTimeout,
+ SnapshotLimit: config.SnapshotCache,
}
)
- eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, config.ManualCanonical)
+ eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit, config.ManualCanonical)
if err != nil {
return nil, err
}
@@ -215,12 +200,12 @@ func New(ctx *node.ServiceContext, config *Config,
eth.bloomIndexer.Start(eth.blockchain)
if config.TxPool.Journal != "" {
- config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal)
+ config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal)
}
eth.txPool = core.NewTxPool(config.TxPool, chainConfig, eth.blockchain)
//// Permit the downloader to use the trie cache allowance during fast sync
- //cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit
+ //cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit
//checkpoint := config.Checkpoint
//if checkpoint == nil {
// checkpoint = params.TrustedCheckpoints[genesisHash]
@@ -231,13 +216,25 @@ func New(ctx *node.ServiceContext, config *Config,
eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock, mcb)
eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData))
- eth.APIBackend = &EthAPIBackend{ctx.ExtRPCEnabled(), eth, nil}
+ eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), eth, nil}
gpoParams := config.GPO
if gpoParams.Default == nil {
gpoParams.Default = config.Miner.GasPrice
}
eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams)
+ eth.dialCandidates, err = eth.setupDiscovery(&stack.Config().P2P)
+ if err != nil {
+ return nil, err
+ }
+
+ // Start the RPC service
+ eth.netRPCService = ethapi.NewPublicNetAPI(eth.p2pServer, eth.NetVersion())
+
+ // Register the backend on the node
+ stack.RegisterAPIs(eth.APIs())
+ stack.RegisterProtocols(eth.Protocols())
+ stack.RegisterLifecycle(eth)
return eth, nil
}
@@ -259,7 +256,7 @@ func makeExtraData(extra []byte) []byte {
}
// CreateConsensusEngine creates the required type of consensus engine instance for an Ethereum service
-func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database, cb *dummy.ConsensusCallbacks) consensus.Engine {
+func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database, cb *dummy.ConsensusCallbacks) consensus.Engine {
return dummy.NewDummyEngine(cb)
}
@@ -268,18 +265,9 @@ func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainCo
func (s *Ethereum) APIs() []rpc.API {
apis := ethapi.GetAPIs(s.APIBackend)
- // Append any APIs exposed explicitly by the les server
- if s.lesServer != nil {
- apis = append(apis, s.lesServer.APIs()...)
- }
// Append any APIs exposed explicitly by the consensus engine
apis = append(apis, s.engine.APIs(s.BlockChain())...)
- // Append any APIs exposed explicitly by the les server
- if s.lesServer != nil {
- apis = append(apis, s.lesServer.APIs()...)
- }
-
// Append all the local APIs and return
return append(apis, []rpc.API{
{
@@ -487,77 +475,68 @@ func (s *Ethereum) NetVersion() uint64 { return s.networkID }
func (s *Ethereum) Downloader() *downloader.Downloader { return nil } // s.protocolManager.downloader }
func (s *Ethereum) Synced() bool { return true } // atomic.LoadUint32(&s.protocolManager.acceptTxs) == 1 }
func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning }
+func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer }
-// Protocols implements node.Service, returning all the currently configured
+// Protocols returns all the currently configured
// network protocols to start.
func (s *Ethereum) Protocols() []p2p.Protocol {
protos := make([]p2p.Protocol, len(ProtocolVersions))
//for i, vsn := range ProtocolVersions {
// protos[i] = s.protocolManager.makeProtocol(vsn)
// protos[i].Attributes = []enr.Entry{s.currentEthEntry()}
- //}
- //if s.lesServer != nil {
- // protos = append(protos, s.lesServer.Protocols()...)
+ // protos[i].DialCandidates = s.dialCandidates
//}
return protos
}
-// Start implements node.Service, starting all internal goroutines needed by the
+// Start implements node.Lifecycle, starting all internal goroutines needed by the
// Ethereum protocol implementation.
-func (s *Ethereum) Start(srvr *p2p.Server) error {
- //s.startEthEntryUpdate(srvr.LocalNode())
+func (s *Ethereum) Start() error {
+ //s.startEthEntryUpdate(s.p2pServer.LocalNode())
// Start the bloom bits servicing goroutines
s.startBloomHandlers(params.BloomBitsBlocks)
- // Start the RPC service
- s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.NetVersion())
-
// Figure out a max peers count based on the server limits
- maxPeers := srvr.MaxPeers
+ maxPeers := s.p2pServer.MaxPeers
if s.config.LightServ > 0 {
- if s.config.LightPeers >= srvr.MaxPeers {
- return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, srvr.MaxPeers)
+ if s.config.LightPeers >= s.p2pServer.MaxPeers {
+ return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, s.p2pServer.MaxPeers)
}
maxPeers -= s.config.LightPeers
}
// Start the networking layer and the light server if requested
//s.protocolManager.Start(maxPeers)
- //if s.lesServer != nil {
- // s.lesServer.Start(srvr)
- //}
return nil
}
-// Stop implements node.Service, terminating all internal goroutines used by the
+// Stop implements node.Lifecycle, terminating all internal goroutines used by the
// Ethereum protocol.
func (s *Ethereum) Stop() error {
- s.bloomIndexer.Close()
- s.blockchain.Stop()
- s.engine.Close()
+ // Stop all the peer-related stuff first.
//s.protocolManager.Stop()
- //if s.lesServer != nil {
- // s.lesServer.Stop()
- //}
+
+ // Then stop everything else.
+ s.bloomIndexer.Close()
+ close(s.closeBloomHandler)
s.txPool.Stop()
s.miner.Stop()
- s.eventMux.Stop()
-
+ s.blockchain.Stop()
+ s.engine.Close()
s.chainDb.Close()
- close(s.shutdownChan)
+ s.eventMux.Stop()
return nil
}
func (s *Ethereum) StopPart() error {
s.bloomIndexer.Close()
- s.blockchain.Stop()
- s.engine.Close()
+ close(s.closeBloomHandler)
s.txPool.Stop()
s.miner.Stop()
- s.eventMux.Stop()
-
+ s.blockchain.Stop()
+ s.engine.Close()
s.chainDb.Close()
- close(s.shutdownChan)
+ s.eventMux.Stop()
return nil
}