mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-21 19:20:39 +00:00
Rpcdaemon as lib (#940)
* share config object * create default config and logger * move db connection to common func * move server start to cli package * clear * clear * rename cli to rpc * use unified SetupLogger func * make all root flag persistent * use common flags in different packages * use common flags in different packages * move TraceTx method to eth package * use native slice flags * create package "turbo" * disable geth api * disable geth api * move more data types to turbo/adapter package * add support for customApiList * run more * run more * run more * dog-food * move DoCall * move DoCall * fix tests * fix test
This commit is contained in:
parent
eb46dd68df
commit
1dcc2b141a
@ -32,8 +32,7 @@ import (
|
||||
"github.com/ledgerwatch/turbo-geth/crypto"
|
||||
"github.com/ledgerwatch/turbo-geth/internal/flags"
|
||||
"github.com/ledgerwatch/turbo-geth/log"
|
||||
|
||||
cli "github.com/urfave/cli"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -142,10 +142,12 @@ func makeFullNode(ctx *cli.Context) (*node.Node, *eth.Ethereum) {
|
||||
if ctx.GlobalIsSet(utils.GraphQLEnabledFlag.Name) {
|
||||
utils.RegisterGraphQLService(stack, backend.APIBackend, cfg.Node)
|
||||
}
|
||||
|
||||
// TurboGeth - moved all API's to RPCDaemon service
|
||||
// Add the Ethereum Stats daemon if requested.
|
||||
if cfg.Ethstats.URL != "" {
|
||||
utils.RegisterEthStatsService(stack, backend.APIBackend, cfg.Ethstats.URL)
|
||||
}
|
||||
//if cfg.Ethstats.URL != "" {
|
||||
// utils.RegisterEthStatsService(stack, backend.APIBackend, cfg.Ethstats.URL)
|
||||
//}
|
||||
return stack, backend
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0"
|
||||
ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 ethash:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0"
|
||||
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
|
||||
)
|
||||
|
||||
|
@ -241,7 +241,7 @@ func init() {
|
||||
// See config.go
|
||||
dumpConfigCommand,
|
||||
// See retesteth.go
|
||||
retestethCommand,
|
||||
//retestethCommand,
|
||||
// See cmd/utils/flags_legacy.go
|
||||
utils.ShowDeprecated,
|
||||
}
|
||||
|
@ -16,11 +16,11 @@
|
||||
|
||||
package main
|
||||
|
||||
/* Retesteth tool is deprecated
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"os"
|
||||
"os/signal"
|
||||
@ -29,8 +29,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/urfave/cli"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/utils"
|
||||
@ -383,7 +381,7 @@ func (api *RetestethAPI) SetChainParams(_ context.Context, chainParams ChainPara
|
||||
ParentHash: chainParams.Genesis.ParentHash,
|
||||
Alloc: accounts,
|
||||
}
|
||||
chainConfig, genesisHash, _, err := core.SetupGenesisBlock(ethDb, genesis, false /* history */, false /* overwrite */)
|
||||
chainConfig, genesisHash, _, err := core.SetupGenesisBlock(ethDb, genesis, false, false)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -834,20 +832,7 @@ func splitAndTrim(input string) []string {
|
||||
}
|
||||
|
||||
func retesteth(ctx *cli.Context) error {
|
||||
var (
|
||||
ostream log.Handler
|
||||
glogger *log.GlogHandler
|
||||
)
|
||||
|
||||
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
||||
output := io.Writer(os.Stderr)
|
||||
if usecolor {
|
||||
output = colorable.NewColorableStderr()
|
||||
}
|
||||
ostream = log.StreamHandler(output, log.TerminalFormat(usecolor))
|
||||
glogger = log.NewGlogHandler(ostream)
|
||||
log.Root().SetHandler(glogger)
|
||||
glogger.Verbosity(log.LvlInfo)
|
||||
log.SetupDefaultTerminalLogger(log.LvlInfo, "", "")
|
||||
|
||||
log.Info("Welcome to retesteth!")
|
||||
// register signer API with server
|
||||
@ -923,3 +908,4 @@ func retesteth(ctx *cli.Context) error {
|
||||
log.Info("Exiting...", "signal", sig)
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
@ -146,3 +147,4 @@ func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]inter
|
||||
|
||||
return fields, nil
|
||||
}
|
||||
*/
|
||||
|
@ -7,7 +7,6 @@ import (
|
||||
"encoding/binary"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
@ -42,8 +41,6 @@ import (
|
||||
"github.com/ledgerwatch/turbo-geth/params"
|
||||
"github.com/ledgerwatch/turbo-geth/rlp"
|
||||
"github.com/ledgerwatch/turbo-geth/trie"
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/wcharczuk/go-chart"
|
||||
"github.com/wcharczuk/go-chart/util"
|
||||
)
|
||||
@ -1685,21 +1682,7 @@ func supply(chaindata string) error {
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
var (
|
||||
ostream log.Handler
|
||||
glogger *log.GlogHandler
|
||||
)
|
||||
|
||||
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
||||
output := io.Writer(os.Stderr)
|
||||
if usecolor {
|
||||
output = colorable.NewColorableStderr()
|
||||
}
|
||||
ostream = log.StreamHandler(output, log.TerminalFormat(usecolor))
|
||||
glogger = log.NewGlogHandler(ostream)
|
||||
log.Root().SetHandler(glogger)
|
||||
|
||||
glogger.Verbosity(log.Lvl(*verbosity))
|
||||
log.SetupDefaultTerminalLogger(log.Lvl(*verbosity), "", "")
|
||||
|
||||
if *cpuprofile != "" {
|
||||
f, err := os.Create(*cpuprofile)
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/utils"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/common/dbutils"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
@ -32,7 +33,7 @@ var cmdCompareBucket = &cobra.Command{
|
||||
Use: "compare_bucket",
|
||||
Short: "compare bucket to the same bucket in '--reference_chaindata'",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := rootContext()
|
||||
ctx := utils.RootContext()
|
||||
if referenceChaindata == "" {
|
||||
referenceChaindata = chaindata + "-copy"
|
||||
}
|
||||
@ -49,7 +50,7 @@ var cmdCompareStates = &cobra.Command{
|
||||
Use: "compare_states",
|
||||
Short: "compare state buckets to buckets in '--reference_chaindata'",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := rootContext()
|
||||
ctx := utils.RootContext()
|
||||
if referenceChaindata == "" {
|
||||
referenceChaindata = chaindata + "-copy"
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package commands
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/utils"
|
||||
"os"
|
||||
"path"
|
||||
"sync"
|
||||
@ -24,7 +25,7 @@ var cmdResetState = &cobra.Command{
|
||||
Use: "reset_state",
|
||||
Short: "Reset StateStages (5,6,7,8,9,10) and buckets",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := rootContext()
|
||||
ctx := utils.RootContext()
|
||||
err := resetState(ctx)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
@ -44,7 +45,7 @@ var cmdClearUnwindStack = &cobra.Command{
|
||||
Use: "clear_unwind_stack",
|
||||
Short: "Clear unwind stack",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := rootContext()
|
||||
ctx := utils.RootContext()
|
||||
err := clearUnwindStack(ctx)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
|
@ -1,16 +1,9 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/utils"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
"github.com/ledgerwatch/turbo-geth/internal/debug"
|
||||
"github.com/ledgerwatch/turbo-geth/log"
|
||||
"github.com/ledgerwatch/turbo-geth/migrations"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -19,10 +12,6 @@ var rootCmd = &cobra.Command{
|
||||
Use: "integration",
|
||||
Short: "long and heavy integration tests for turbo-geth",
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
if err := debug.SetupCobra(cmd); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if len(chaindata) > 0 {
|
||||
db := ethdb.MustOpen(chaindata)
|
||||
defer db.Close()
|
||||
@ -31,36 +20,9 @@ var rootCmd = &cobra.Command{
|
||||
}
|
||||
}
|
||||
},
|
||||
PersistentPostRun: func(cmd *cobra.Command, args []string) {
|
||||
debug.Exit()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
utils.CobraFlags(rootCmd, append(debug.Flags, utils.MetricsEnabledFlag, utils.MetricsEnabledExpensiveFlag, utils.MetricsHTTPFlag, utils.MetricsPortFlag))
|
||||
}
|
||||
|
||||
func rootContext() context.Context {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
|
||||
defer signal.Stop(ch)
|
||||
|
||||
select {
|
||||
case <-ch:
|
||||
log.Info("Got interrupt, shutting down...")
|
||||
case <-ctx.Done():
|
||||
}
|
||||
|
||||
cancel()
|
||||
}()
|
||||
return ctx
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
if err := rootCmd.ExecuteContext(rootContext()); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
func RootCommand() *cobra.Command {
|
||||
utils.CobraFlags(rootCmd, append(debug.Flags, utils.MetricFlags...))
|
||||
return rootCmd
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/utils"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
@ -20,7 +21,7 @@ var cmdStageSenders = &cobra.Command{
|
||||
Use: "stage_senders",
|
||||
Short: "",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := rootContext()
|
||||
ctx := utils.RootContext()
|
||||
if err := stageSenders(ctx); err != nil {
|
||||
log.Error("Error", "err", err)
|
||||
return err
|
||||
@ -33,7 +34,7 @@ var cmdStageExec = &cobra.Command{
|
||||
Use: "stage_exec",
|
||||
Short: "",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := rootContext()
|
||||
ctx := utils.RootContext()
|
||||
if err := stageExec(ctx); err != nil {
|
||||
log.Error("Error", "err", err)
|
||||
return err
|
||||
@ -46,7 +47,7 @@ var cmdStageIHash = &cobra.Command{
|
||||
Use: "stage_ih",
|
||||
Short: "",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := rootContext()
|
||||
ctx := utils.RootContext()
|
||||
if err := stageIHash(ctx); err != nil {
|
||||
log.Error("Error", "err", err)
|
||||
return err
|
||||
@ -59,7 +60,7 @@ var cmdStageHashState = &cobra.Command{
|
||||
Use: "stage_hash_state",
|
||||
Short: "",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := rootContext()
|
||||
ctx := utils.RootContext()
|
||||
if err := stageHashState(ctx); err != nil {
|
||||
log.Error("Error", "err", err)
|
||||
return err
|
||||
@ -72,7 +73,7 @@ var cmdStageHistory = &cobra.Command{
|
||||
Use: "stage_history",
|
||||
Short: "",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := rootContext()
|
||||
ctx := utils.RootContext()
|
||||
if err := stageHistory(ctx); err != nil {
|
||||
log.Error("Error", "err", err)
|
||||
return err
|
||||
@ -85,7 +86,7 @@ var cmdStageTxLookup = &cobra.Command{
|
||||
Use: "stage_tx_lookup",
|
||||
Short: "",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := rootContext()
|
||||
ctx := utils.RootContext()
|
||||
if err := stageTxLookup(ctx); err != nil {
|
||||
log.Error("Error", "err", err)
|
||||
return err
|
||||
@ -97,7 +98,7 @@ var cmdPrintStages = &cobra.Command{
|
||||
Use: "print_stages",
|
||||
Short: "",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := rootContext()
|
||||
ctx := utils.RootContext()
|
||||
if err := printAllStages(ctx); err != nil {
|
||||
log.Error("Error", "err", err)
|
||||
return err
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/utils"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/common/changeset"
|
||||
@ -26,7 +27,7 @@ var stateStags = &cobra.Command{
|
||||
`,
|
||||
Example: "go run ./cmd/integration state_stages --chaindata=... --verbosity=3 --unwind=100 --unwind_every=100000 --block=2000000",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := rootContext()
|
||||
ctx := utils.RootContext()
|
||||
if err := syncBySmallSteps(ctx, chaindata); err != nil {
|
||||
log.Error("Error", "err", err)
|
||||
return err
|
||||
|
@ -1,8 +1,21 @@
|
||||
package main
|
||||
|
||||
import "github.com/ledgerwatch/turbo-geth/cmd/integration/commands"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/integration/commands"
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/utils"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
commands.Execute()
|
||||
}
|
||||
rootCmd := commands.RootCommand()
|
||||
if err := utils.SetupCobra(rootCmd); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer utils.StopDebug()
|
||||
|
||||
if err := rootCmd.ExecuteContext(utils.RootContext()); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,7 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/restapi/rest"
|
||||
"github.com/ledgerwatch/turbo-geth/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -32,27 +25,6 @@ var rootCmd = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
if err := rootCmd.ExecuteContext(rootContext()); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func rootContext() context.Context {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
|
||||
defer signal.Stop(ch)
|
||||
|
||||
select {
|
||||
case <-ch:
|
||||
log.Info("Got interrupt, shutting down...")
|
||||
case <-ctx.Done():
|
||||
}
|
||||
|
||||
cancel()
|
||||
}()
|
||||
return ctx
|
||||
func RootCommand() *cobra.Command {
|
||||
return rootCmd
|
||||
}
|
||||
|
@ -1,30 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/restapi/commands"
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/utils"
|
||||
"github.com/ledgerwatch/turbo-geth/log"
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
ostream log.Handler
|
||||
glogger *log.GlogHandler
|
||||
)
|
||||
log.SetupDefaultTerminalLogger(log.LvlInfo, "", "")
|
||||
|
||||
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
||||
output := io.Writer(os.Stderr)
|
||||
if usecolor {
|
||||
output = colorable.NewColorableStderr()
|
||||
if err := commands.RootCommand().ExecuteContext(utils.RootContext()); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
ostream = log.StreamHandler(output, log.TerminalFormat(usecolor))
|
||||
glogger = log.NewGlogHandler(ostream)
|
||||
log.Root().SetHandler(glogger)
|
||||
glogger.Verbosity(log.LvlInfo)
|
||||
|
||||
commands.Execute()
|
||||
}
|
||||
|
97
cmd/rpcdaemon/cli/config.go
Normal file
97
cmd/rpcdaemon/cli/config.go
Normal file
@ -0,0 +1,97 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/utils"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
"github.com/ledgerwatch/turbo-geth/internal/debug"
|
||||
"github.com/ledgerwatch/turbo-geth/log"
|
||||
"github.com/ledgerwatch/turbo-geth/node"
|
||||
"github.com/ledgerwatch/turbo-geth/rpc"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type Flags struct {
|
||||
PrivateApiAddr string
|
||||
Chaindata string
|
||||
HttpListenAddress string
|
||||
HttpPort int
|
||||
HttpCORSDomain []string
|
||||
HttpVirtualHost []string
|
||||
API []string
|
||||
Gascap uint64
|
||||
}
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "rpcdaemon",
|
||||
Short: "rpcdaemon is JSON RPC server that connects to turbo-geth node for remote DB access",
|
||||
}
|
||||
|
||||
func RootCommand() (*cobra.Command, *Flags) {
|
||||
utils.CobraFlags(rootCmd, append(debug.Flags, utils.MetricFlags...))
|
||||
|
||||
cfg := &Flags{}
|
||||
rootCmd.PersistentFlags().StringVar(&cfg.PrivateApiAddr, "private.api.addr", "127.0.0.1:9090", "private api network address, for example: 127.0.0.1:9090, empty string means not to start the listener. do not expose to public network. serves remote database interface")
|
||||
rootCmd.PersistentFlags().StringVar(&cfg.Chaindata, "chaindata", "", "path to the database")
|
||||
rootCmd.PersistentFlags().StringVar(&cfg.HttpListenAddress, "http.addr", node.DefaultHTTPHost, "HTTP-RPC server listening interface")
|
||||
rootCmd.PersistentFlags().IntVar(&cfg.HttpPort, "http.port", node.DefaultHTTPPort, "HTTP-RPC server listening port")
|
||||
rootCmd.PersistentFlags().StringSliceVar(&cfg.HttpCORSDomain, "http.corsdomain", []string{}, "Comma separated list of domains from which to accept cross origin requests (browser enforced)")
|
||||
rootCmd.PersistentFlags().StringSliceVar(&cfg.HttpVirtualHost, "http.vhosts", node.DefaultConfig.HTTPVirtualHosts, "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.")
|
||||
rootCmd.PersistentFlags().StringSliceVar(&cfg.API, "http.api", []string{"eth"}, "API's offered over the HTTP-RPC interface")
|
||||
rootCmd.PersistentFlags().Uint64Var(&cfg.Gascap, "rpc.gascap", 0, "Sets a cap on gas that can be used in eth_call/estimateGas")
|
||||
|
||||
return rootCmd, cfg
|
||||
}
|
||||
|
||||
func OpenDB(cfg Flags) (ethdb.KV, ethdb.Backend, error) {
|
||||
var db ethdb.KV
|
||||
var txPool ethdb.Backend
|
||||
var err error
|
||||
if cfg.PrivateApiAddr != "" {
|
||||
db, txPool, err = ethdb.NewRemote().Path(cfg.PrivateApiAddr).Open()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("could not connect to remoteDb: %w", err)
|
||||
}
|
||||
} else if cfg.Chaindata != "" {
|
||||
if database, errOpen := ethdb.Open(cfg.Chaindata); errOpen == nil {
|
||||
db = database.KV()
|
||||
} else {
|
||||
err = errOpen
|
||||
}
|
||||
} else {
|
||||
return nil, nil, fmt.Errorf("either remote db or bolt db must be specified")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("could not connect to remoteDb: %w", err)
|
||||
}
|
||||
|
||||
return db, txPool, err
|
||||
}
|
||||
|
||||
func StartRpcServer(ctx context.Context, cfg Flags, rpcAPI []rpc.API) {
|
||||
// register apis and create handler stack
|
||||
httpEndpoint := fmt.Sprintf("%s:%d", cfg.HttpListenAddress, cfg.HttpPort)
|
||||
srv := rpc.NewServer()
|
||||
if err := node.RegisterApisFromWhitelist(rpcAPI, cfg.API, srv, false); err != nil {
|
||||
log.Error("Could not start register RPC apis", "error", err)
|
||||
return
|
||||
}
|
||||
handler := node.NewHTTPHandlerStack(srv, cfg.HttpCORSDomain, cfg.HttpVirtualHost)
|
||||
|
||||
listener, _, err := node.StartHTTPEndpoint(httpEndpoint, rpc.DefaultHTTPTimeouts, handler)
|
||||
if err != nil {
|
||||
log.Error("Could not start RPC api", "error", err)
|
||||
return
|
||||
}
|
||||
extapiURL := fmt.Sprintf("http://%s", httpEndpoint)
|
||||
log.Info("HTTP endpoint opened", "url", extapiURL)
|
||||
|
||||
defer func() {
|
||||
listener.Close()
|
||||
log.Info("HTTP endpoint closed", "url", httpEndpoint)
|
||||
}()
|
||||
sig := <-ctx.Done()
|
||||
log.Info("Exiting...", "signal", sig)
|
||||
}
|
@ -4,28 +4,23 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/common/hexutil"
|
||||
"github.com/ledgerwatch/turbo-geth/core"
|
||||
"github.com/ledgerwatch/turbo-geth/core/rawdb"
|
||||
"github.com/ledgerwatch/turbo-geth/core/state"
|
||||
"github.com/ledgerwatch/turbo-geth/core/types"
|
||||
"github.com/ledgerwatch/turbo-geth/core/vm"
|
||||
"github.com/ledgerwatch/turbo-geth/internal/ethapi"
|
||||
"github.com/ledgerwatch/turbo-geth/log"
|
||||
"github.com/ledgerwatch/turbo-geth/params"
|
||||
"github.com/ledgerwatch/turbo-geth/rpc"
|
||||
"github.com/ledgerwatch/turbo-geth/turbo/rpchelper"
|
||||
"github.com/ledgerwatch/turbo-geth/turbo/transactions"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
const callTimeout = 5 * time.Second
|
||||
|
||||
func (api *APIImpl) Call(ctx context.Context, args ethapi.CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *map[common.Address]ethapi.Account) (hexutil.Bytes, error) {
|
||||
result, err := api.doCall(ctx, args, blockNrOrHash, overrides)
|
||||
result, err := transactions.DoCall(ctx, args, api.db, api.dbReader, blockNrOrHash, overrides, api.GasCap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -38,136 +33,13 @@ func (api *APIImpl) Call(ctx context.Context, args ethapi.CallArgs, blockNrOrHas
|
||||
return result.Return(), result.Err
|
||||
}
|
||||
|
||||
func (api *APIImpl) doCall(ctx context.Context, args ethapi.CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *map[common.Address]ethapi.Account) (*core.ExecutionResult, error) {
|
||||
// todo: Pending state is only known by the miner
|
||||
/*
|
||||
if blockNrOrHash.BlockNumber != nil && *blockNrOrHash.BlockNumber == rpc.PendingBlockNumber {
|
||||
block, state, _ := b.eth.miner.Pending()
|
||||
return state, block.Header(), nil
|
||||
}
|
||||
*/
|
||||
|
||||
blockNumber, hash, err := GetBlockNumber(blockNrOrHash, api.dbReader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds := state.NewPlainDBState(api.db, blockNumber)
|
||||
state := state.New(ds)
|
||||
if state == nil {
|
||||
return nil, fmt.Errorf("can't get the state for %d", blockNumber)
|
||||
}
|
||||
|
||||
header := rawdb.ReadHeader(api.dbReader, hash, blockNumber)
|
||||
if header == nil {
|
||||
return nil, fmt.Errorf("block %d(%x) not found", blockNumber, hash)
|
||||
}
|
||||
|
||||
// Override the fields of specified contracts before execution.
|
||||
if overrides != nil {
|
||||
for addr, account := range *overrides {
|
||||
// Override account nonce.
|
||||
if account.Nonce != nil {
|
||||
state.SetNonce(addr, uint64(*account.Nonce))
|
||||
}
|
||||
// Override account(contract) code.
|
||||
if account.Code != nil {
|
||||
state.SetCode(addr, *account.Code)
|
||||
}
|
||||
// Override account balance.
|
||||
if account.Balance != nil {
|
||||
balance, _ := uint256.FromBig((*big.Int)(*account.Balance))
|
||||
state.SetBalance(addr, balance)
|
||||
}
|
||||
if account.State != nil && account.StateDiff != nil {
|
||||
return nil, fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
|
||||
}
|
||||
// Replace entire state if caller requires.
|
||||
if account.State != nil {
|
||||
state.SetStorage(addr, *account.State)
|
||||
}
|
||||
// Apply state diff into specified accounts.
|
||||
if account.StateDiff != nil {
|
||||
for key, value := range *account.StateDiff {
|
||||
key := key
|
||||
state.SetState(addr, &key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setup context so it may be cancelled the call has completed
|
||||
// or, in case of unmetered gas, setup a context with a timeout.
|
||||
var cancel context.CancelFunc
|
||||
if callTimeout > 0 {
|
||||
ctx, cancel = context.WithTimeout(ctx, callTimeout)
|
||||
} else {
|
||||
ctx, cancel = context.WithCancel(ctx)
|
||||
}
|
||||
|
||||
// Make sure the context is cancelled when the call has completed
|
||||
// this makes sure resources are cleaned up.
|
||||
defer cancel()
|
||||
|
||||
// Get a new instance of the EVM.
|
||||
msg := args.ToMessage(cfg.gascap)
|
||||
|
||||
evmCtx := GetEvmContext(msg, header, blockNrOrHash.RequireCanonical, api.dbReader)
|
||||
|
||||
evm := vm.NewEVM(evmCtx, state, params.MainnetChainConfig, vm.Config{})
|
||||
|
||||
// Wait for the context to be done and cancel the evm. Even if the
|
||||
// EVM has finished, cancelling may be done (repeatedly)
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
evm.Cancel()
|
||||
}()
|
||||
|
||||
gp := new(core.GasPool).AddGas(msg.Gas())
|
||||
result, err := core.ApplyMessage(evm, msg, gp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the timer caused an abort, return an appropriate error message
|
||||
if evm.Cancelled() {
|
||||
return nil, fmt.Errorf("execution aborted (timeout = %v)", callTimeout)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func GetEvmContext(msg core.Message, header *types.Header, requireCanonical bool, dbReader rawdb.DatabaseReader) vm.Context {
|
||||
return vm.Context{
|
||||
CanTransfer: core.CanTransfer,
|
||||
Transfer: core.Transfer,
|
||||
GetHash: getHashGetter(requireCanonical, dbReader),
|
||||
Origin: msg.From(),
|
||||
Coinbase: header.Coinbase,
|
||||
BlockNumber: new(big.Int).Set(header.Number),
|
||||
Time: new(big.Int).SetUint64(header.Time),
|
||||
Difficulty: new(big.Int).Set(header.Difficulty),
|
||||
GasLimit: header.GasLimit,
|
||||
GasPrice: msg.GasPrice().ToBig(),
|
||||
}
|
||||
}
|
||||
|
||||
func getHashGetter(requireCanonical bool, dbReader rawdb.DatabaseReader) func(uint64) common.Hash {
|
||||
return func(n uint64) common.Hash {
|
||||
hash, err := GetHashByNumber(n, requireCanonical, dbReader)
|
||||
if err != nil {
|
||||
log.Debug("can't get block hash by number", "number", n, "only-canonical", requireCanonical)
|
||||
}
|
||||
return hash
|
||||
}
|
||||
}
|
||||
|
||||
// EstimateGas returns an estimate of the amount of gas needed to execute the
|
||||
// given transaction against the current pending block.
|
||||
func (api *APIImpl) EstimateGas(ctx context.Context, args ethapi.CallArgs) (hexutil.Uint64, error) {
|
||||
//fixme: blockNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
|
||||
hash := rawdb.ReadHeadBlockHash(api.dbReader)
|
||||
|
||||
return api.DoEstimateGas(ctx, args, rpc.BlockNumberOrHash{BlockHash: &hash}, big.NewInt(0).SetUint64(cfg.gascap))
|
||||
return api.DoEstimateGas(ctx, args, rpc.BlockNumberOrHash{BlockHash: &hash}, big.NewInt(0).SetUint64(api.GasCap))
|
||||
}
|
||||
|
||||
func (api *APIImpl) DoEstimateGas(ctx context.Context, args ethapi.CallArgs, blockNrOrHash rpc.BlockNumberOrHash, gasCap *big.Int) (hexutil.Uint64, error) {
|
||||
@ -182,7 +54,7 @@ func (api *APIImpl) DoEstimateGas(ctx context.Context, args ethapi.CallArgs, blo
|
||||
args.From = new(common.Address)
|
||||
}
|
||||
|
||||
blockNumber, hash, err := GetBlockNumber(blockNrOrHash, api.dbReader)
|
||||
blockNumber, hash, err := rpchelper.GetBlockNumber(blockNrOrHash, api.dbReader)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -233,7 +105,7 @@ func (api *APIImpl) DoEstimateGas(ctx context.Context, args ethapi.CallArgs, blo
|
||||
executable := func(gas uint64) (bool, *core.ExecutionResult, error) {
|
||||
args.Gas = (*hexutil.Uint64)(&gas)
|
||||
|
||||
result, err := api.doCall(ctx, args, blockNrOrHash, nil)
|
||||
result, err := transactions.DoCall(ctx, args, api.db, api.dbReader, blockNrOrHash, nil, api.GasCap)
|
||||
if err != nil {
|
||||
if errors.Is(err, core.ErrIntrinsicGas) {
|
||||
// Special case, raise gas limit
|
||||
|
@ -3,100 +3,14 @@ package commands
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/consensus"
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/rpcdaemon/cli"
|
||||
"github.com/ledgerwatch/turbo-geth/core/rawdb"
|
||||
"github.com/ledgerwatch/turbo-geth/core/state"
|
||||
"github.com/ledgerwatch/turbo-geth/core/types"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
"github.com/ledgerwatch/turbo-geth/internal/ethapi"
|
||||
"github.com/ledgerwatch/turbo-geth/log"
|
||||
"github.com/ledgerwatch/turbo-geth/node"
|
||||
"github.com/ledgerwatch/turbo-geth/params"
|
||||
"github.com/ledgerwatch/turbo-geth/rpc"
|
||||
"github.com/ledgerwatch/turbo-geth/turbo/adapter/ethapi"
|
||||
)
|
||||
|
||||
// splitAndTrim splits input separated by a comma
|
||||
// and trims excessive white space from the substrings.
|
||||
func splitAndTrim(input string) []string {
|
||||
result := strings.Split(input, ",")
|
||||
for i, r := range result {
|
||||
result[i] = strings.TrimSpace(r)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
type chainContext struct {
|
||||
db rawdb.DatabaseReader
|
||||
}
|
||||
|
||||
func NewChainContext(db rawdb.DatabaseReader) *chainContext {
|
||||
return &chainContext{
|
||||
db: db,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type powEngine struct {
|
||||
}
|
||||
|
||||
func (c *powEngine) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, seal bool) error {
|
||||
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (func(), <-chan error) {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) VerifySeal(chain consensus.ChainHeaderReader, header *types.Header) error {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) Finalize(chainConfig *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs []*types.Transaction, uncles []*types.Header) {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) FinalizeAndAssemble(chainConfig *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs []*types.Transaction,
|
||||
uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) Seal(_ consensus.Cancel, chain consensus.ChainHeaderReader, block *types.Block, results chan<- consensus.ResultWithContext, stop <-chan struct{}) error {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) SealHash(header *types.Header) common.Hash {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) APIs(chain consensus.ChainHeaderReader) []rpc.API {
|
||||
panic("must not be called")
|
||||
}
|
||||
|
||||
func (c *powEngine) Close() error {
|
||||
panic("must not be called")
|
||||
}
|
||||
|
||||
func (c *powEngine) Author(header *types.Header) (common.Address, error) {
|
||||
return header.Coinbase, nil
|
||||
}
|
||||
|
||||
func (c *chainContext) GetHeader(hash common.Hash, number uint64) *types.Header {
|
||||
return rawdb.ReadHeader(c.db, hash, number)
|
||||
}
|
||||
|
||||
func (c *chainContext) Engine() consensus.Engine {
|
||||
return &powEngine{}
|
||||
}
|
||||
|
||||
// GetBlockByNumber see https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbynumber
|
||||
// see internal/ethapi.PublicBlockChainAPI.GetBlockByNumber
|
||||
func (api *APIImpl) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
|
||||
@ -108,7 +22,7 @@ func (api *APIImpl) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber
|
||||
}
|
||||
|
||||
additionalFields["totalDifficulty"] = rawdb.ReadTd(api.dbReader, block.Hash(), uint64(number.Int64()))
|
||||
response, err := api.rpcMarshalBlock(block, true, fullTx, additionalFields)
|
||||
response, err := ethapi.RPCMarshalBlock(block, true, fullTx, additionalFields)
|
||||
|
||||
if err == nil && number == rpc.PendingBlockNumber {
|
||||
// Pending blocks need to nil out a few fields
|
||||
@ -119,30 +33,15 @@ func (api *APIImpl) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber
|
||||
return response, err
|
||||
}
|
||||
|
||||
// rpcMarshalBlock reimplementation of ethapi.rpcMarshalBlock
|
||||
func (api *APIImpl) rpcMarshalBlock(b *types.Block, inclTx bool, fullTx bool, additional map[string]interface{}) (map[string]interface{}, error) {
|
||||
fields, err := ethapi.RPCMarshalBlock(b, inclTx, fullTx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for k, v := range additional {
|
||||
fields[k] = v
|
||||
}
|
||||
|
||||
return fields, err
|
||||
}
|
||||
|
||||
func GetAPI(db ethdb.KV, eth ethdb.Backend, enabledApis []string) []rpc.API {
|
||||
func APIList(db ethdb.KV, eth ethdb.Backend, cfg cli.Flags, customApiList []rpc.API) []rpc.API {
|
||||
var rpcAPI []rpc.API
|
||||
|
||||
dbReader := ethdb.NewObjectDatabase(db)
|
||||
chainContext := NewChainContext(dbReader)
|
||||
apiImpl := NewAPI(db, dbReader, chainContext, eth)
|
||||
apiImpl := NewAPI(db, dbReader, eth, cfg.Gascap)
|
||||
netImpl := NewNetAPIImpl(eth)
|
||||
dbgAPIImpl := NewPrivateDebugAPI(db, dbReader, chainContext)
|
||||
dbgAPIImpl := NewPrivateDebugAPI(db, dbReader)
|
||||
|
||||
for _, enabledAPI := range enabledApis {
|
||||
for _, enabledAPI := range cfg.API {
|
||||
switch enabledAPI {
|
||||
case "eth":
|
||||
rpcAPI = append(rpcAPI, rpc.API{
|
||||
@ -167,67 +66,10 @@ func GetAPI(db ethdb.KV, eth ethdb.Backend, enabledApis []string) []rpc.API {
|
||||
})
|
||||
|
||||
default:
|
||||
log.Error("Unrecognised", "api", enabledAPI)
|
||||
// TODO: enable validation after checking customApiList
|
||||
//log.Error("Unrecognised", "api", enabledAPI)
|
||||
}
|
||||
}
|
||||
return rpcAPI
|
||||
}
|
||||
|
||||
func daemon(cmd *cobra.Command, cfg Config) {
|
||||
vhosts := splitAndTrim(cfg.httpVirtualHost)
|
||||
cors := splitAndTrim(cfg.httpCORSDomain)
|
||||
enabledApis := splitAndTrim(cfg.API)
|
||||
|
||||
var db ethdb.KV
|
||||
var txPool ethdb.Backend
|
||||
var err error
|
||||
if cfg.privateApiAddr != "" {
|
||||
db, txPool, err = ethdb.NewRemote().Path(cfg.privateApiAddr).Open()
|
||||
if err != nil {
|
||||
log.Error("Could not connect to remoteDb", "error", err)
|
||||
return
|
||||
}
|
||||
} else if cfg.chaindata != "" {
|
||||
if database, errOpen := ethdb.Open(cfg.chaindata); errOpen == nil {
|
||||
db = database.KV()
|
||||
} else {
|
||||
err = errOpen
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("either remote db or bolt db must be specified")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Error("Could not connect to remoteDb", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
var rpcAPI = GetAPI(db, txPool, enabledApis)
|
||||
|
||||
httpEndpoint := fmt.Sprintf("%s:%d", cfg.httpListenAddress, cfg.httpPort)
|
||||
|
||||
// register apis and create handler stack
|
||||
srv := rpc.NewServer()
|
||||
err = node.RegisterApisFromWhitelist(rpcAPI, enabledApis, srv, false)
|
||||
if err != nil {
|
||||
log.Error("Could not start register RPC apis", "error", err)
|
||||
return
|
||||
}
|
||||
handler := node.NewHTTPHandlerStack(srv, cors, vhosts)
|
||||
|
||||
listener, _, err := node.StartHTTPEndpoint(httpEndpoint, rpc.DefaultHTTPTimeouts, handler)
|
||||
if err != nil {
|
||||
log.Error("Could not start RPC api", "error", err)
|
||||
return
|
||||
}
|
||||
extapiURL := fmt.Sprintf("http://%s", httpEndpoint)
|
||||
log.Info("HTTP endpoint opened", "url", extapiURL)
|
||||
|
||||
defer func() {
|
||||
listener.Close()
|
||||
log.Info("HTTP endpoint closed", "url", httpEndpoint)
|
||||
}()
|
||||
|
||||
sig := <-cmd.Context().Done()
|
||||
log.Info("Exiting...", "signal", sig)
|
||||
|
||||
return append(rpcAPI, customApiList...)
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ import (
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
"github.com/ledgerwatch/turbo-geth/params"
|
||||
"github.com/ledgerwatch/turbo-geth/rpc"
|
||||
"github.com/ledgerwatch/turbo-geth/turbo/adapter"
|
||||
"github.com/ledgerwatch/turbo-geth/turbo/transactions"
|
||||
)
|
||||
|
||||
// PrivateDebugAPI
|
||||
@ -33,17 +35,18 @@ type PrivateDebugAPIImpl struct {
|
||||
}
|
||||
|
||||
// NewPrivateDebugAPI returns PrivateDebugAPIImpl instance
|
||||
func NewPrivateDebugAPI(db ethdb.KV, dbReader ethdb.Getter, chainContext core.ChainContext) *PrivateDebugAPIImpl {
|
||||
func NewPrivateDebugAPI(db ethdb.KV, dbReader ethdb.Getter) *PrivateDebugAPIImpl {
|
||||
return &PrivateDebugAPIImpl{
|
||||
db: db,
|
||||
dbReader: dbReader,
|
||||
chainContext: chainContext,
|
||||
db: db,
|
||||
dbReader: dbReader,
|
||||
}
|
||||
}
|
||||
|
||||
// StorageRangeAt re-implementation of eth/api.go:StorageRangeAt
|
||||
func (api *PrivateDebugAPIImpl) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex uint64, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) {
|
||||
_, _, _, stateReader, err := ComputeTxEnv(ctx, &blockGetter{api.dbReader}, params.MainnetChainConfig, &chainContext{db: api.dbReader}, api.db, blockHash, txIndex)
|
||||
bc := adapter.NewBlockGetter(api.dbReader)
|
||||
cc := adapter.NewChainContext(api.dbReader)
|
||||
_, _, _, stateReader, err := transactions.ComputeTxEnv(ctx, bc, params.MainnetChainConfig, cc, api.db, blockHash, txIndex)
|
||||
if err != nil {
|
||||
return StorageRangeResult{}, err
|
||||
}
|
||||
|
@ -2,11 +2,9 @@ package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/common/hexutil"
|
||||
"github.com/ledgerwatch/turbo-geth/core"
|
||||
"github.com/ledgerwatch/turbo-geth/core/rawdb"
|
||||
"github.com/ledgerwatch/turbo-geth/core/types"
|
||||
"github.com/ledgerwatch/turbo-geth/eth/stagedsync/stages"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
@ -33,15 +31,16 @@ type APIImpl struct {
|
||||
ethBackend ethdb.Backend
|
||||
dbReader ethdb.Getter
|
||||
chainContext core.ChainContext
|
||||
GasCap uint64
|
||||
}
|
||||
|
||||
// NewAPI returns APIImpl instance
|
||||
func NewAPI(db ethdb.KV, dbReader ethdb.Getter, chainContext core.ChainContext, eth ethdb.Backend) *APIImpl {
|
||||
func NewAPI(db ethdb.KV, dbReader ethdb.Getter, eth ethdb.Backend, gascap uint64) *APIImpl {
|
||||
return &APIImpl{
|
||||
db: db,
|
||||
dbReader: dbReader,
|
||||
chainContext: chainContext,
|
||||
ethBackend: eth,
|
||||
db: db,
|
||||
dbReader: dbReader,
|
||||
ethBackend: eth,
|
||||
GasCap: gascap,
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,16 +51,3 @@ func (api *APIImpl) BlockNumber(ctx context.Context) (hexutil.Uint64, error) {
|
||||
}
|
||||
return hexutil.Uint64(execution), nil
|
||||
}
|
||||
|
||||
type blockGetter struct {
|
||||
dbReader rawdb.DatabaseReader
|
||||
}
|
||||
|
||||
func (g *blockGetter) GetBlockByHash(hash common.Hash) *types.Block {
|
||||
return rawdb.ReadBlockByHash(g.dbReader, hash)
|
||||
|
||||
}
|
||||
|
||||
func (g *blockGetter) GetBlock(hash common.Hash, number uint64) *types.Block {
|
||||
return rawdb.ReadBlock(g.dbReader, hash, number)
|
||||
}
|
||||
|
@ -3,67 +3,23 @@ package commands
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/ledgerwatch/turbo-geth/turbo/rpchelper"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/common/hexutil"
|
||||
"github.com/ledgerwatch/turbo-geth/core/rawdb"
|
||||
"github.com/ledgerwatch/turbo-geth/core/types/accounts"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
"github.com/ledgerwatch/turbo-geth/rpc"
|
||||
)
|
||||
|
||||
func (api *APIImpl) GetBalance(_ context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) {
|
||||
blockNumber, _, err := GetBlockNumber(blockNrOrHash, api.dbReader)
|
||||
blockNumber, _, err := rpchelper.GetBlockNumber(blockNrOrHash, api.dbReader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
acc, err := GetAccount(api.db, blockNumber, address)
|
||||
acc, err := rpchelper.GetAccount(api.db, blockNumber, address)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cant get a balance for account %q for block %v", address.String(), blockNumber)
|
||||
}
|
||||
|
||||
return (*hexutil.Big)(acc.Balance.ToBig()), nil
|
||||
}
|
||||
|
||||
func GetBlockNumber(blockNrOrHash rpc.BlockNumberOrHash, dbReader rawdb.DatabaseReader) (uint64, common.Hash, error) {
|
||||
var blockNumber uint64
|
||||
var err error
|
||||
|
||||
hash, ok := blockNrOrHash.Hash()
|
||||
if !ok {
|
||||
blockNumber = uint64(blockNrOrHash.BlockNumber.Int64())
|
||||
hash, err = GetHashByNumber(blockNumber, blockNrOrHash.RequireCanonical, dbReader)
|
||||
if err != nil {
|
||||
return 0, common.Hash{}, err
|
||||
}
|
||||
} else {
|
||||
block := rawdb.ReadBlockByHash(dbReader, hash)
|
||||
if block == nil {
|
||||
return 0, common.Hash{}, fmt.Errorf("block %x not found", hash)
|
||||
}
|
||||
blockNumber = block.NumberU64()
|
||||
|
||||
if blockNrOrHash.RequireCanonical && rawdb.ReadCanonicalHash(dbReader, blockNumber) != hash {
|
||||
return 0, common.Hash{}, fmt.Errorf("hash %q is not currently canonical", hash.String())
|
||||
}
|
||||
}
|
||||
return blockNumber, hash, nil
|
||||
}
|
||||
|
||||
func GetAccount(chainKV ethdb.KV, blockNumber uint64, address common.Address) (*accounts.Account, error) {
|
||||
reader := NewStateReader(chainKV, blockNumber)
|
||||
return reader.ReadAccountData(address)
|
||||
}
|
||||
|
||||
func GetHashByNumber(blockNumber uint64, requireCanonical bool, dbReader rawdb.DatabaseReader) (common.Hash, error) {
|
||||
if requireCanonical {
|
||||
return rawdb.ReadCanonicalHash(dbReader, blockNumber), nil
|
||||
}
|
||||
|
||||
block := rawdb.ReadBlockByNumber(dbReader, blockNumber)
|
||||
if block == nil {
|
||||
return common.Hash{}, fmt.Errorf("block %d not found", blockNumber)
|
||||
}
|
||||
return block.Hash(), nil
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package commands
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/ledgerwatch/turbo-geth/turbo/adapter"
|
||||
"github.com/ledgerwatch/turbo-geth/turbo/transactions"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/common/hexutil"
|
||||
@ -25,14 +27,14 @@ func GetReceipts(ctx context.Context, db rawdb.DatabaseReader, cfg *params.Chain
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
bc := &blockGetter{db}
|
||||
_, _, ibs, dbstate, err := ComputeTxEnv(ctx, bc, params.MainnetChainConfig, &chainContext{db: db}, db.(ethdb.HasKV).KV(), hash, 0)
|
||||
cc := adapter.NewChainContext(db)
|
||||
bc := adapter.NewBlockGetter(db)
|
||||
_, _, ibs, dbstate, err := transactions.ComputeTxEnv(ctx, bc, params.MainnetChainConfig, cc, db.(ethdb.HasKV).KV(), hash, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var receipts types.Receipts
|
||||
cc := &chainContext{db}
|
||||
gp := new(core.GasPool).AddGas(block.GasLimit())
|
||||
var usedGas = new(uint64)
|
||||
for i, tx := range block.Transactions() {
|
||||
|
@ -1,130 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/log"
|
||||
"github.com/ledgerwatch/turbo-geth/node"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
privateApiAddr string
|
||||
chaindata string
|
||||
httpListenAddress string
|
||||
httpPort int
|
||||
httpCORSDomain string
|
||||
httpVirtualHost string
|
||||
API string
|
||||
gascap uint64
|
||||
}
|
||||
|
||||
var (
|
||||
cpuprofile string
|
||||
cpuProfileFile io.WriteCloser
|
||||
|
||||
memprofile string
|
||||
cfg Config
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.PersistentFlags().StringVar(&cpuprofile, "pprof.cpuprofile", "", "write cpu profile `file`")
|
||||
rootCmd.PersistentFlags().StringVar(&memprofile, "memprofile", "", "write memory profile `file`")
|
||||
rootCmd.Flags().StringVar(&cfg.privateApiAddr, "private.api.addr", "", "private api network address, for example: 127.0.0.1:9090, empty string means not to start the listener. do not expose to public network. serves remote database interface")
|
||||
rootCmd.Flags().StringVar(&cfg.chaindata, "chaindata", "", "path to the database")
|
||||
rootCmd.Flags().StringVar(&cfg.httpListenAddress, "http.addr", node.DefaultHTTPHost, "HTTP-RPC server listening interface")
|
||||
rootCmd.Flags().IntVar(&cfg.httpPort, "http.port", node.DefaultHTTPPort, "HTTP-RPC server listening port")
|
||||
rootCmd.Flags().StringVar(&cfg.httpCORSDomain, "http.corsdomain", "", "Comma separated list of domains from which to accept cross origin requests (browser enforced)")
|
||||
rootCmd.Flags().StringVar(&cfg.httpVirtualHost, "http.vhosts", strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","), "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.")
|
||||
rootCmd.Flags().StringVar(&cfg.API, "http.api", "", "API's offered over the HTTP-RPC interface")
|
||||
|
||||
rootCmd.Flags().Uint64Var(&cfg.gascap, "rpc.gascap", 0, "Sets a cap on gas that can be used in eth_call/estimateGas")
|
||||
}
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "rpcdaemon",
|
||||
Short: "rpcdaemon is JSON RPC server that connects to turbo-geth node for remote DB access",
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
startProfilingIfNeeded()
|
||||
|
||||
},
|
||||
PersistentPostRun: func(cmd *cobra.Command, args []string) {
|
||||
stopProfilingIfNeeded()
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
daemon(cmd, cfg)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
if err := rootCmd.ExecuteContext(rootContext()); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func rootContext() context.Context {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
|
||||
defer signal.Stop(ch)
|
||||
|
||||
select {
|
||||
case <-ch:
|
||||
log.Info("Got interrupt, shutting down...")
|
||||
case <-ctx.Done():
|
||||
}
|
||||
|
||||
cancel()
|
||||
}()
|
||||
return ctx
|
||||
}
|
||||
|
||||
func startProfilingIfNeeded() {
|
||||
if cpuprofile != "" {
|
||||
fmt.Println("starting CPU profiling")
|
||||
cpuProfileFile, err := os.Create(cpuprofile)
|
||||
if err != nil {
|
||||
log.Error("could not create CPU profile", "error", err)
|
||||
return
|
||||
}
|
||||
if err := pprof.StartCPUProfile(cpuProfileFile); err != nil {
|
||||
log.Error("could not start CPU profile", "error", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func stopProfilingIfNeeded() {
|
||||
if cpuprofile != "" {
|
||||
fmt.Println("stopping CPU profiling")
|
||||
pprof.StopCPUProfile()
|
||||
}
|
||||
|
||||
if cpuProfileFile != nil {
|
||||
cpuProfileFile.Close()
|
||||
}
|
||||
if memprofile != "" {
|
||||
f, err := os.Create(memprofile)
|
||||
if err != nil {
|
||||
log.Error("could not create mem profile", "error", err)
|
||||
return
|
||||
}
|
||||
runtime.GC() // get up-to-date statistics
|
||||
if err := pprof.WriteHeapProfile(f); err != nil {
|
||||
log.Error("could not write memory profile", "error", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/turbo/adapter"
|
||||
)
|
||||
|
||||
// StorageRangeResult is the result of a debug_storageRangeAt API call.
|
||||
@ -21,7 +21,7 @@ type StorageEntry struct {
|
||||
Value common.Hash `json:"value"`
|
||||
}
|
||||
|
||||
func StorageRangeAt(stateReader *StateReader, contractAddress common.Address, start []byte, maxResult int) (StorageRangeResult, error) {
|
||||
func StorageRangeAt(stateReader *adapter.StateReader, contractAddress common.Address, start []byte, maxResult int) (StorageRangeResult, error) {
|
||||
//account, err := stateReader.ReadAccountData(contractAddress)
|
||||
//if err != nil {
|
||||
// return StorageRangeResult{}, fmt.Errorf("error reading account %x: %v", contractAddress, err)
|
||||
|
@ -2,27 +2,13 @@ package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/core"
|
||||
"github.com/ledgerwatch/turbo-geth/core/rawdb"
|
||||
"github.com/ledgerwatch/turbo-geth/core/state"
|
||||
"github.com/ledgerwatch/turbo-geth/core/types"
|
||||
"github.com/ledgerwatch/turbo-geth/core/vm"
|
||||
"github.com/ledgerwatch/turbo-geth/eth"
|
||||
"github.com/ledgerwatch/turbo-geth/eth/tracers"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
"github.com/ledgerwatch/turbo-geth/internal/ethapi"
|
||||
"github.com/ledgerwatch/turbo-geth/params"
|
||||
)
|
||||
|
||||
const (
|
||||
// defaultTraceTimeout is the amount of time a single transaction can execute
|
||||
// by default before being forcefully aborted.
|
||||
defaultTraceTimeout = 5 * time.Second
|
||||
"github.com/ledgerwatch/turbo-geth/turbo/adapter"
|
||||
"github.com/ledgerwatch/turbo-geth/turbo/transactions"
|
||||
)
|
||||
|
||||
// TraceTransaction returns the structured logs created during the execution of EVM
|
||||
@ -33,136 +19,12 @@ func (api *PrivateDebugAPIImpl) TraceTransaction(ctx context.Context, hash commo
|
||||
if tx == nil {
|
||||
return nil, fmt.Errorf("transaction %#x not found", hash)
|
||||
}
|
||||
msg, vmctx, ibs, _, err := ComputeTxEnv(ctx, &blockGetter{api.dbReader}, params.MainnetChainConfig, &chainContext{db: api.dbReader}, api.db, blockHash, txIndex)
|
||||
getter := adapter.NewBlockGetter(api.dbReader)
|
||||
chainContext := adapter.NewChainContext(api.dbReader)
|
||||
msg, vmctx, ibs, _, err := transactions.ComputeTxEnv(ctx, getter, params.MainnetChainConfig, chainContext, api.db, blockHash, txIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Trace the transaction and return
|
||||
return api.traceTx(ctx, msg, vmctx, ibs, 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.
|
||||
func (api *PrivateDebugAPIImpl) traceTx(ctx context.Context, message core.Message, vmctx vm.Context, ibs vm.IntraBlockState,
|
||||
config *eth.TraceConfig) (interface{}, error) {
|
||||
// Assemble the structured logger or the JavaScript tracer
|
||||
var (
|
||||
tracer vm.Tracer
|
||||
err error
|
||||
)
|
||||
switch {
|
||||
case config != nil && config.Tracer != nil:
|
||||
// Define a meaningful timeout of a single transaction trace
|
||||
timeout := defaultTraceTimeout
|
||||
if config.Timeout != nil {
|
||||
if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Constuct the JavaScript tracer to execute with
|
||||
if tracer, err = tracers.New(*config.Tracer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Handle timeouts and RPC cancellations
|
||||
deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
|
||||
go func() {
|
||||
<-deadlineCtx.Done()
|
||||
tracer.(*tracers.Tracer).Stop(errors.New("execution timeout"))
|
||||
}()
|
||||
defer cancel()
|
||||
|
||||
case config == nil:
|
||||
tracer = vm.NewStructLogger(nil)
|
||||
|
||||
default:
|
||||
tracer = vm.NewStructLogger(config.LogConfig)
|
||||
}
|
||||
// Run the transaction with tracing enabled.
|
||||
vmenv := vm.NewEVM(vmctx, ibs, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer})
|
||||
|
||||
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:
|
||||
return ðapi.ExecutionResult{
|
||||
Gas: result.UsedGas,
|
||||
Failed: result.Failed(),
|
||||
ReturnValue: fmt.Sprintf("%x", result.Return()),
|
||||
StructLogs: ethapi.FormatLogs(tracer.StructLogs()),
|
||||
}, nil
|
||||
|
||||
case *tracers.Tracer:
|
||||
return tracer.GetResult()
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("bad tracer type %T", tracer))
|
||||
}
|
||||
}
|
||||
|
||||
// computeTxEnv returns the execution environment of a certain transaction.
|
||||
func ComputeTxEnv(ctx context.Context, blockGetter BlockGetter, cfg *params.ChainConfig, chain core.ChainContext, chainKV ethdb.KV, blockHash common.Hash, txIndex uint64) (core.Message, vm.Context, *state.IntraBlockState, *StateReader, error) {
|
||||
// Create the parent state database
|
||||
block := blockGetter.GetBlockByHash(blockHash)
|
||||
if block == nil {
|
||||
return nil, vm.Context{}, nil, nil, fmt.Errorf("block %x not found", blockHash)
|
||||
}
|
||||
parent := blockGetter.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||
if parent == nil {
|
||||
return nil, vm.Context{}, nil, nil, fmt.Errorf("parent %x not found", block.ParentHash())
|
||||
}
|
||||
|
||||
statedb, reader := ComputeIntraBlockState(chainKV, parent)
|
||||
|
||||
if txIndex == 0 && len(block.Transactions()) == 0 {
|
||||
return nil, vm.Context{}, statedb, reader, nil
|
||||
}
|
||||
// Recompute transactions up to the target index.
|
||||
signer := types.MakeSigner(cfg, block.Number())
|
||||
|
||||
for idx, tx := range block.Transactions() {
|
||||
select {
|
||||
default:
|
||||
case <-ctx.Done():
|
||||
return nil, vm.Context{}, nil, nil, ctx.Err()
|
||||
}
|
||||
statedb.Prepare(tx.Hash(), blockHash, idx)
|
||||
|
||||
// Assemble the transaction call message and return if the requested offset
|
||||
msg, _ := tx.AsMessage(signer)
|
||||
EVMcontext := core.NewEVMContext(msg, block.Header(), chain, nil)
|
||||
if idx == int(txIndex) {
|
||||
return msg, EVMcontext, statedb, reader, nil
|
||||
}
|
||||
// Not yet the searched for transaction, execute on top of the current state
|
||||
vmenv := vm.NewEVM(EVMcontext, statedb, cfg, vm.Config{})
|
||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
|
||||
return nil, vm.Context{}, nil, 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.FinalizeTx(vmenv.ChainConfig().WithEIPsFlags(context.Background(), block.Number()), reader)
|
||||
}
|
||||
return nil, vm.Context{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %x", txIndex, blockHash)
|
||||
}
|
||||
|
||||
// computeIntraBlockState retrieves the state database associated with a certain block.
|
||||
// If no state is locally available for the given block, a number of blocks are
|
||||
// attempted to be reexecuted to generate the desired state.
|
||||
func ComputeIntraBlockState(chainKV ethdb.KV, block *types.Block) (*state.IntraBlockState, *StateReader) {
|
||||
// If we have the state fully available, use that
|
||||
reader := NewStateReader(chainKV, block.NumberU64())
|
||||
statedb := state.New(reader)
|
||||
return statedb, reader
|
||||
}
|
||||
|
||||
type BlockGetter interface {
|
||||
// GetBlockByHash retrieves a block from the database by hash, caching it if found.
|
||||
GetBlockByHash(hash common.Hash) *types.Block
|
||||
// GetBlock retrieves a block from the database by hash and number,
|
||||
// caching it if found.
|
||||
GetBlock(hash common.Hash, number uint64) *types.Block
|
||||
return transactions.TraceTx(ctx, msg, vmctx, ibs, config)
|
||||
}
|
||||
|
@ -1,30 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/utils"
|
||||
"os"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/rpcdaemon/cli"
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/rpcdaemon/commands"
|
||||
"github.com/ledgerwatch/turbo-geth/log"
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
ostream log.Handler
|
||||
glogger *log.GlogHandler
|
||||
)
|
||||
|
||||
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
||||
output := io.Writer(os.Stderr)
|
||||
if usecolor {
|
||||
output = colorable.NewColorableStderr()
|
||||
cmd, cfg := cli.RootCommand()
|
||||
if err := utils.SetupCobra(cmd); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ostream = log.StreamHandler(output, log.TerminalFormat(usecolor))
|
||||
glogger = log.NewGlogHandler(ostream)
|
||||
log.Root().SetHandler(glogger)
|
||||
glogger.Verbosity(log.LvlInfo)
|
||||
defer utils.StopDebug()
|
||||
|
||||
commands.Execute()
|
||||
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
db, txPool, err := cli.OpenDB(*cfg)
|
||||
if err != nil {
|
||||
log.Error("Could not connect to remoteDb", "error", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
var rpcAPI = commands.APIList(db, txPool, *cfg, nil)
|
||||
cli.StartRpcServer(cmd.Context(), *cfg, rpcAPI)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := cmd.ExecuteContext(utils.RootContext()); err != nil {
|
||||
log.Error(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/rpcdaemon/cli"
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/rpcdaemon/commands"
|
||||
"github.com/ledgerwatch/turbo-geth/core"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
@ -8,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func New(db ethdb.HasKV, ethereum core.Backend, stack *node.Node) {
|
||||
apis := commands.GetAPI(db.KV(), core.NewEthBackend(ethereum), []string{"eth", "debug"})
|
||||
apis := commands.APIList(db.KV(), core.NewEthBackend(ethereum), cli.Flags{API: []string{"eth", "debug"}}, nil)
|
||||
|
||||
stack.RegisterAPIs(apis)
|
||||
}
|
||||
|
@ -8,6 +8,22 @@ Content-Type: application/json
|
||||
|
||||
###
|
||||
|
||||
# curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber", "params": ["0x1b4", true], "id":1}' localhost:8545
|
||||
POST localhost:8545
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_getBlockByNumber",
|
||||
"params": [
|
||||
"0x1b4",
|
||||
true
|
||||
],
|
||||
"id": 1
|
||||
}
|
||||
|
||||
###
|
||||
|
||||
POST localhost:8545
|
||||
Content-Type: application/json
|
||||
|
||||
|
@ -5,30 +5,14 @@ import (
|
||||
"fmt"
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/rpctest/rpctest"
|
||||
"github.com/ledgerwatch/turbo-geth/log"
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/spf13/cobra"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
ostream log.Handler
|
||||
glogger *log.GlogHandler
|
||||
)
|
||||
|
||||
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
||||
output := io.Writer(os.Stderr)
|
||||
if usecolor {
|
||||
output = colorable.NewColorableStderr()
|
||||
}
|
||||
ostream = log.StreamHandler(output, log.TerminalFormat(usecolor))
|
||||
glogger = log.NewGlogHandler(ostream)
|
||||
log.Root().SetHandler(glogger)
|
||||
glogger.Verbosity(log.LvlInfo)
|
||||
log.SetupDefaultTerminalLogger(log.Lvl(3), "", "")
|
||||
|
||||
var (
|
||||
needCompare bool
|
||||
|
@ -5,7 +5,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/signal"
|
||||
@ -22,8 +21,6 @@ import (
|
||||
"github.com/ledgerwatch/turbo-geth/log"
|
||||
"github.com/ledgerwatch/turbo-geth/p2p"
|
||||
"github.com/ledgerwatch/turbo-geth/p2p/enode"
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
@ -55,7 +52,7 @@ func init() {
|
||||
app.Flags = append(app.Flags, flags...)
|
||||
|
||||
app.Before = func(ctx *cli.Context) error {
|
||||
setupLogger(ctx)
|
||||
log.SetupDefaultTerminalLogger(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name)), "", "")
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
if err := debug.Setup(ctx); err != nil {
|
||||
return err
|
||||
@ -104,23 +101,6 @@ func rootContext() context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func setupLogger(cliCtx *cli.Context) {
|
||||
var (
|
||||
ostream log.Handler
|
||||
glogger *log.GlogHandler
|
||||
)
|
||||
|
||||
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
||||
output := io.Writer(os.Stderr)
|
||||
if usecolor {
|
||||
output = colorable.NewColorableStderr()
|
||||
}
|
||||
ostream = log.StreamHandler(output, log.TerminalFormat(usecolor))
|
||||
glogger = log.NewGlogHandler(ostream)
|
||||
log.Root().SetHandler(glogger)
|
||||
glogger.Verbosity(log.Lvl(cliCtx.GlobalInt(VerbosityFlag.Name)))
|
||||
}
|
||||
|
||||
func tester(cliCtx *cli.Context) error {
|
||||
ctx := rootContext()
|
||||
nodeToConnect, err := getTargetAddr(cliCtx)
|
||||
|
@ -21,6 +21,8 @@ import (
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/urfave/cli"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
@ -313,3 +315,35 @@ func ExportPreimages(db ethdb.Database, fn string) error {
|
||||
log.Info("Exported preimages", "file", fn)
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetupCobra(cmd *cobra.Command) error {
|
||||
return debug.SetupCobra(cmd)
|
||||
}
|
||||
|
||||
func StopDebug() {
|
||||
debug.Exit()
|
||||
}
|
||||
|
||||
func SetupUrfave(ctx *cli.Context) error {
|
||||
return debug.Setup(ctx)
|
||||
}
|
||||
|
||||
func RootContext() context.Context {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
defer cancel()
|
||||
|
||||
ch := make(chan os.Signal, 1)
|
||||
defer close(ch)
|
||||
|
||||
signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
|
||||
defer signal.Stop(ch)
|
||||
|
||||
select {
|
||||
case <-ch:
|
||||
log.Info("Got interrupt, shutting down...")
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}()
|
||||
return ctx
|
||||
}
|
||||
|
@ -50,7 +50,6 @@ import (
|
||||
"github.com/ledgerwatch/turbo-geth/eth/downloader"
|
||||
"github.com/ledgerwatch/turbo-geth/eth/gasprice"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
"github.com/ledgerwatch/turbo-geth/ethstats"
|
||||
"github.com/ledgerwatch/turbo-geth/graphql"
|
||||
"github.com/ledgerwatch/turbo-geth/internal/ethapi"
|
||||
"github.com/ledgerwatch/turbo-geth/internal/flags"
|
||||
@ -763,6 +762,8 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
var MetricFlags = []cli.Flag{MetricsEnabledFlag, MetricsEnabledExpensiveFlag, MetricsHTTPFlag, MetricsPortFlag}
|
||||
|
||||
// MakeDataDir retrieves the currently requested data directory, terminating
|
||||
// if none (or the empty string) is specified. If the node is starting a testnet,
|
||||
// then a subdirectory of the specified datadir will be used.
|
||||
@ -1744,11 +1745,11 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) *eth.Ethereum {
|
||||
|
||||
// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to
|
||||
// the given node.
|
||||
func RegisterEthStatsService(stack *node.Node, backend ethapi.Backend, url string) {
|
||||
if err := ethstats.New(stack, backend, backend.Engine(), url); err != nil {
|
||||
Fatalf("Failed to register the Ethereum Stats service: %v", err)
|
||||
}
|
||||
}
|
||||
//func RegisterEthStatsService(stack *node.Node, backend ethapi.Backend, url string) {
|
||||
// if err := ethstats.New(stack, backend, backend.Engine(), url); err != nil {
|
||||
// Fatalf("Failed to register the Ethereum Stats service: %v", err)
|
||||
// }
|
||||
//}
|
||||
|
||||
// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
|
||||
func RegisterGraphQLService(stack *node.Node, backend ethapi.Backend, cfg node.Config) {
|
||||
|
@ -178,9 +178,9 @@ func TestWelcome(t *testing.T) {
|
||||
if want := fmt.Sprintf("instance: %s", testInstance); !strings.Contains(output, want) {
|
||||
t.Fatalf("console output missing instance: have\n%s\nwant also %s", output, want)
|
||||
}
|
||||
if want := fmt.Sprintf("coinbase: %s", testAddress); !strings.Contains(output, want) {
|
||||
t.Fatalf("console output missing coinbase: have\n%s\nwant also %s", output, want)
|
||||
}
|
||||
//if want := fmt.Sprintf("coinbase: %s", testAddress); !strings.Contains(output, want) {
|
||||
// t.Fatalf("console output missing coinbase: have\n%s\nwant also %s", output, want)
|
||||
//}
|
||||
if want := "at block: 0"; !strings.Contains(output, want) {
|
||||
t.Fatalf("console output missing sync status: have\n%s\nwant also %s", output, want)
|
||||
}
|
||||
|
72
eth/api.go
72
eth/api.go
@ -17,31 +17,34 @@
|
||||
package eth
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/common/hexutil"
|
||||
"github.com/ledgerwatch/turbo-geth/core"
|
||||
"github.com/ledgerwatch/turbo-geth/core/rawdb"
|
||||
"github.com/ledgerwatch/turbo-geth/core/state"
|
||||
"github.com/ledgerwatch/turbo-geth/core/types"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
"github.com/ledgerwatch/turbo-geth/internal/ethapi"
|
||||
"github.com/ledgerwatch/turbo-geth/rlp"
|
||||
"github.com/ledgerwatch/turbo-geth/rpc"
|
||||
)
|
||||
|
||||
// BadBlockArgs represents the entries in the list returned when bad blocks are queried.
|
||||
type BadBlockArgs struct {
|
||||
Hash common.Hash `json:"hash"`
|
||||
Block map[string]interface{} `json:"block"`
|
||||
RLP string `json:"rlp"`
|
||||
}
|
||||
|
||||
// AccountRangeMaxResults is the maximum number of results to be returned per call
|
||||
const AccountRangeMaxResults = 256
|
||||
|
||||
/*
|
||||
|
||||
// StorageRangeResult is the result of a debug_storageRangeAt API call.
|
||||
type StorageRangeResult struct {
|
||||
Storage StorageMap `json:"storage"`
|
||||
NextKey *common.Hash `json:"nextKey"` // nil if Storage includes the last key in the trie.
|
||||
}
|
||||
|
||||
type StorageMap map[common.Hash]StorageEntry
|
||||
|
||||
type StorageEntry struct {
|
||||
Key *common.Hash `json:"key"`
|
||||
Value common.Hash `json:"value"`
|
||||
}
|
||||
|
||||
// PublicEthereumAPI provides an API to access Ethereum full node-related
|
||||
// information.
|
||||
type PublicEthereumAPI struct {
|
||||
@ -165,6 +168,7 @@ type PrivateAdminAPI struct {
|
||||
eth *Ethereum
|
||||
}
|
||||
|
||||
|
||||
// NewPrivateAdminAPI creates a new API definition for the full node private
|
||||
// admin methods of the Ethereum service.
|
||||
func NewPrivateAdminAPI(eth *Ethereum) *PrivateAdminAPI {
|
||||
@ -321,13 +325,6 @@ func (api *PrivateDebugAPI) Preimage(ctx context.Context, hash common.Hash) (hex
|
||||
return nil, errors.New("unknown preimage")
|
||||
}
|
||||
|
||||
// BadBlockArgs represents the entries in the list returned when bad blocks are queried.
|
||||
type BadBlockArgs struct {
|
||||
Hash common.Hash `json:"hash"`
|
||||
Block map[string]interface{} `json:"block"`
|
||||
RLP string `json:"rlp"`
|
||||
}
|
||||
|
||||
// GetBadBlocks returns a list of the last 'bad blocks' that the client has seen on the network
|
||||
// and returns them as a JSON list of block-hashes
|
||||
func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error) {
|
||||
@ -351,9 +348,6 @@ func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs,
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// AccountRangeMaxResults is the maximum number of results to be returned per call
|
||||
const AccountRangeMaxResults = 256
|
||||
|
||||
// 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 blockNumber uint64
|
||||
@ -382,19 +376,6 @@ func (api *PublicDebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, sta
|
||||
return dumper.IteratorDump(nocode, nostorage, incompletes, start, maxResults)
|
||||
}
|
||||
|
||||
// StorageRangeResult is the result of a debug_storageRangeAt API call.
|
||||
type StorageRangeResult struct {
|
||||
Storage StorageMap `json:"storage"`
|
||||
NextKey *common.Hash `json:"nextKey"` // nil if Storage includes the last key in the trie.
|
||||
}
|
||||
|
||||
type StorageMap map[common.Hash]StorageEntry
|
||||
|
||||
type StorageEntry struct {
|
||||
Key *common.Hash `json:"key"`
|
||||
Value common.Hash `json:"value"`
|
||||
}
|
||||
|
||||
// StorageRangeAt returns the storage at the given block height and transaction index.
|
||||
func (api *PrivateDebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex uint64, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) {
|
||||
_, _, _, dbstate, err := ComputeTxEnv(ctx, api.eth.blockchain, api.eth.blockchain.Config(), api.eth.blockchain, api.eth.ChainKV(), blockHash, txIndex)
|
||||
@ -496,3 +477,4 @@ func (api *PrivateDebugAPI) getModifiedAccounts(startBlock, endBlock *types.Bloc
|
||||
dirty, err := ethdb.GetModifiedAccounts(api.eth.blockchain.ChainDb(), startNum, endNum)
|
||||
return dirty, err
|
||||
}
|
||||
*/
|
||||
|
@ -14,12 +14,16 @@
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package eth
|
||||
package eth_test
|
||||
|
||||
/*
|
||||
TODO: revive this tests for RPCDaemon - https://github.com/ledgerwatch/turbo-geth/issues/939
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/ledgerwatch/turbo-geth/turbo/adapter"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
@ -27,11 +31,12 @@ import (
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/holiman/uint256"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/cmd/rpcdaemon/commands"
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/common/u256"
|
||||
"github.com/ledgerwatch/turbo-geth/core/state"
|
||||
"github.com/ledgerwatch/turbo-geth/crypto"
|
||||
"github.com/ledgerwatch/turbo-geth/eth"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
"github.com/ledgerwatch/turbo-geth/trie"
|
||||
)
|
||||
@ -70,7 +75,7 @@ func TestAccountRange(t *testing.T) {
|
||||
var (
|
||||
tds = state.NewTrieDbState(common.Hash{}, db, 0)
|
||||
sdb = state.New(tds)
|
||||
addrs = [AccountRangeMaxResults * 2]common.Address{}
|
||||
addrs = [eth.AccountRangeMaxResults * 2]common.Address{}
|
||||
m = map[common.Address]bool{}
|
||||
)
|
||||
|
||||
@ -97,10 +102,10 @@ func TestAccountRange(t *testing.T) {
|
||||
|
||||
trie := tds.Trie()
|
||||
|
||||
accountRangeTest(t, trie, db.KV(), 0, sdb, []byte{}, AccountRangeMaxResults/2, AccountRangeMaxResults/2)
|
||||
accountRangeTest(t, trie, db.KV(), 0, sdb, []byte{}, eth.AccountRangeMaxResults/2, eth.AccountRangeMaxResults/2)
|
||||
// test pagination
|
||||
firstResult := accountRangeTest(t, trie, db.KV(), 0, sdb, []byte{}, AccountRangeMaxResults, AccountRangeMaxResults)
|
||||
secondResult := accountRangeTest(t, trie, db.KV(), 0, sdb, firstResult.Next, AccountRangeMaxResults, AccountRangeMaxResults)
|
||||
firstResult := accountRangeTest(t, trie, db.KV(), 0, sdb, []byte{}, eth.AccountRangeMaxResults, eth.AccountRangeMaxResults)
|
||||
secondResult := accountRangeTest(t, trie, db.KV(), 0, sdb, firstResult.Next, eth.AccountRangeMaxResults, eth.AccountRangeMaxResults)
|
||||
|
||||
hList := make(resultHash, 0)
|
||||
for addr1 := range firstResult.Accounts {
|
||||
@ -117,8 +122,8 @@ func TestAccountRange(t *testing.T) {
|
||||
// Test to see if it's possible to recover from the middle of the previous
|
||||
// set and get an even split between the first and second sets.
|
||||
sort.Sort(hList)
|
||||
middleH := hList[AccountRangeMaxResults/2]
|
||||
middleResult := accountRangeTest(t, trie, db.KV(), 0, sdb, middleH, AccountRangeMaxResults, AccountRangeMaxResults)
|
||||
middleH := hList[eth.AccountRangeMaxResults/2]
|
||||
middleResult := accountRangeTest(t, trie, db.KV(), 0, sdb, middleH, eth.AccountRangeMaxResults, eth.AccountRangeMaxResults)
|
||||
missing, infirst, insecond := 0, 0, 0
|
||||
for h := range middleResult.Accounts {
|
||||
if _, ok := firstResult.Accounts[h]; ok {
|
||||
@ -132,11 +137,11 @@ func TestAccountRange(t *testing.T) {
|
||||
if missing != 0 {
|
||||
t.Fatalf("%d hashes in the 'middle' set were neither in the first not the second set", missing)
|
||||
}
|
||||
if infirst != AccountRangeMaxResults/2 {
|
||||
t.Fatalf("Imbalance in the number of first-test results: %d != %d", infirst, AccountRangeMaxResults/2)
|
||||
if infirst != eth.AccountRangeMaxResults/2 {
|
||||
t.Fatalf("Imbalance in the number of first-test results: %d != %d", infirst, eth.AccountRangeMaxResults/2)
|
||||
}
|
||||
if insecond != AccountRangeMaxResults/2 {
|
||||
t.Fatalf("Imbalance in the number of second-test results: %d != %d", insecond, AccountRangeMaxResults/2)
|
||||
if insecond != eth.AccountRangeMaxResults/2 {
|
||||
t.Fatalf("Imbalance in the number of second-test results: %d != %d", insecond, eth.AccountRangeMaxResults/2)
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,7 +156,7 @@ func TestEmptyAccountRange(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
results, err1 := state.NewDumper(db.KV(), 0).IteratorDump(true, true, true, (common.Hash{}).Bytes(), AccountRangeMaxResults)
|
||||
results, err1 := state.NewDumper(db.KV(), 0).IteratorDump(true, true, true, (common.Hash{}).Bytes(), eth.AccountRangeMaxResults)
|
||||
if err1 != nil {
|
||||
t.Fatal(err1)
|
||||
}
|
||||
@ -177,7 +182,7 @@ func TestStorageRangeAt(t *testing.T) {
|
||||
common.HexToHash("48078cfed56339ea54962e72c37c7f588fc4f8e5bc173827ba75cb10a63a96a5"),
|
||||
common.HexToHash("5723d2c3a83af9b735e3b7f21531e5623d183a9095a56604ead41f3582fdfb75"),
|
||||
}
|
||||
storage = StorageMap{
|
||||
storage = commands.StorageMap{
|
||||
keys[0]: {Key: &common.Hash{0x02}, Value: common.Hash{0x01}},
|
||||
keys[1]: {Key: &common.Hash{0x04}, Value: common.Hash{0x02}},
|
||||
keys[2]: {Key: &common.Hash{0x01}, Value: common.Hash{0x03}},
|
||||
@ -214,34 +219,35 @@ func TestStorageRangeAt(t *testing.T) {
|
||||
tests := []struct {
|
||||
start []byte
|
||||
limit int
|
||||
want StorageRangeResult
|
||||
want commands.StorageRangeResult
|
||||
}{
|
||||
{
|
||||
start: []byte{}, limit: 0,
|
||||
want: StorageRangeResult{StorageMap{}, &keys[0]},
|
||||
want: commands.StorageRangeResult{commands.StorageMap{}, &keys[0]},
|
||||
},
|
||||
{
|
||||
start: []byte{}, limit: 100,
|
||||
want: StorageRangeResult{storage, nil},
|
||||
want: commands.StorageRangeResult{storage, nil},
|
||||
},
|
||||
{
|
||||
start: []byte{}, limit: 2,
|
||||
want: StorageRangeResult{StorageMap{keys[0]: storage[keys[0]], keys[1]: storage[keys[1]]}, &keys[2]},
|
||||
want: commands.StorageRangeResult{commands.StorageMap{keys[0]: storage[keys[0]], keys[1]: storage[keys[1]]}, &keys[2]},
|
||||
},
|
||||
{
|
||||
start: []byte{0x00}, limit: 4,
|
||||
want: StorageRangeResult{storage, nil},
|
||||
want: commands.StorageRangeResult{storage, nil},
|
||||
},
|
||||
{
|
||||
start: []byte{0x40}, limit: 2,
|
||||
want: StorageRangeResult{StorageMap{keys[1]: storage[keys[1]], keys[2]: storage[keys[2]]}, &keys[3]},
|
||||
want: commands.StorageRangeResult{commands.StorageMap{keys[1]: storage[keys[1]], keys[2]: storage[keys[2]]}, &keys[3]},
|
||||
},
|
||||
}
|
||||
dbs := state.NewDbState(db.KV(), 1)
|
||||
|
||||
dbs := adapter.NewStateReader(db.KV(), 1)
|
||||
for i, test := range tests {
|
||||
test := test
|
||||
t.Run("test_"+strconv.Itoa(i), func(t *testing.T) {
|
||||
result, err := StorageRangeAt(dbs, addr, test.start, test.limit)
|
||||
result, err := commands.StorageRangeAt(dbs, addr, test.start, test.limit)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@ -252,3 +258,4 @@ func TestStorageRangeAt(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -17,43 +17,11 @@
|
||||
package eth
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/common/hexutil"
|
||||
"github.com/ledgerwatch/turbo-geth/core"
|
||||
"github.com/ledgerwatch/turbo-geth/core/rawdb"
|
||||
"github.com/ledgerwatch/turbo-geth/core/state"
|
||||
"github.com/ledgerwatch/turbo-geth/core/types"
|
||||
"github.com/ledgerwatch/turbo-geth/core/vm"
|
||||
"github.com/ledgerwatch/turbo-geth/eth/tracers"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
"github.com/ledgerwatch/turbo-geth/internal/ethapi"
|
||||
"github.com/ledgerwatch/turbo-geth/log"
|
||||
"github.com/ledgerwatch/turbo-geth/params"
|
||||
"github.com/ledgerwatch/turbo-geth/rlp"
|
||||
"github.com/ledgerwatch/turbo-geth/rpc"
|
||||
)
|
||||
|
||||
const (
|
||||
// defaultTraceTimeout is the amount of time a single transaction can execute
|
||||
// by default before being forcefully aborted.
|
||||
defaultTraceTimeout = 5 * time.Second
|
||||
|
||||
// defaultTraceReexec is the number of blocks the tracer is willing to go back
|
||||
// and reexecute to produce missing historical state necessary to run a specific
|
||||
// trace.
|
||||
defaultTraceReexec = uint64(128)
|
||||
)
|
||||
|
||||
// TraceConfig holds extra parameters to trace functions.
|
||||
@ -101,6 +69,20 @@ type txTraceTask struct {
|
||||
index int // Transaction offset in the block
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
const (
|
||||
// defaultTraceTimeout is the amount of time a single transaction can execute
|
||||
// by default before being forcefully aborted.
|
||||
defaultTraceTimeout = 5 * time.Second
|
||||
|
||||
// defaultTraceReexec is the number of blocks the tracer is willing to go back
|
||||
// and reexecute to produce missing historical state necessary to run a specific
|
||||
// trace.
|
||||
defaultTraceReexec = uint64(128)
|
||||
)
|
||||
|
||||
|
||||
// TraceChain returns the structured logs created during the execution of EVM
|
||||
// between two blocks (excluding start) and returns them as a JSON object.
|
||||
func (api *PrivateDebugAPI) TraceChain(ctx context.Context, start, end rpc.BlockNumber, config *TraceConfig) (*rpc.Subscription, error) {
|
||||
@ -518,12 +500,6 @@ func (api *PrivateDebugAPI) standardTraceBlockToFile(ctx context.Context, block
|
||||
if parent == nil {
|
||||
return nil, fmt.Errorf("parent %#x not found", block.ParentHash())
|
||||
}
|
||||
/*
|
||||
reexec := defaultTraceReexec
|
||||
if config != nil && config.Reexec != nil {
|
||||
reexec = *config.Reexec
|
||||
}
|
||||
*/
|
||||
statedb, dbstate := ComputeIntraBlockState(api.eth.ChainKV(), parent)
|
||||
// Retrieve the tracing configurations, or use default values
|
||||
var (
|
||||
@ -702,6 +678,8 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
type BlockGetter interface {
|
||||
// GetBlockByHash retrieves a block from the database by hash, caching it if found.
|
||||
GetBlockByHash(hash common.Hash) *types.Block
|
||||
@ -736,6 +714,7 @@ func ComputeTxEnv(ctx context.Context, blockGetter BlockGetter, cfg *params.Chai
|
||||
case <-ctx.Done():
|
||||
return nil, vm.Context{}, nil, nil, ctx.Err()
|
||||
}
|
||||
statedb.Prepare(tx.Hash(), blockHash, idx)
|
||||
|
||||
// Assemble the transaction call message and return if the requested offset
|
||||
msg, _ := tx.AsMessage(signer)
|
||||
@ -754,3 +733,4 @@ func ComputeTxEnv(ctx context.Context, blockGetter BlockGetter, cfg *params.Chai
|
||||
}
|
||||
return nil, vm.Context{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %x", txIndex, blockHash)
|
||||
}
|
||||
*/
|
||||
|
@ -371,45 +371,52 @@ func (s *Ethereum) APIs() []rpc.API {
|
||||
|
||||
// Append all the local APIs and return
|
||||
return append(apis, []rpc.API{
|
||||
//{
|
||||
// Namespace: "eth",
|
||||
// Version: "1.0",
|
||||
// Service: NewPublicEthereumAPI(s),
|
||||
// Public: true,
|
||||
//},
|
||||
//{
|
||||
// Namespace: "eth",
|
||||
// Version: "1.0",
|
||||
// Service: NewPublicMinerAPI(s),
|
||||
// Public: true,
|
||||
//},
|
||||
{
|
||||
Namespace: "eth",
|
||||
Version: "1.0",
|
||||
Service: NewPublicEthereumAPI(s),
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "eth",
|
||||
Version: "1.0",
|
||||
Service: NewPublicMinerAPI(s),
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "eth",
|
||||
Version: "1.0",
|
||||
Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux),
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "miner",
|
||||
Version: "1.0",
|
||||
Service: NewPrivateMinerAPI(s),
|
||||
Public: false,
|
||||
}, {
|
||||
},
|
||||
//{
|
||||
// Namespace: "miner",
|
||||
// Version: "1.0",
|
||||
// Service: NewPrivateMinerAPI(s),
|
||||
// Public: false,
|
||||
//},
|
||||
{
|
||||
Namespace: "eth",
|
||||
Version: "1.0",
|
||||
Service: filters.NewPublicFilterAPI(s.APIBackend, false),
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "admin",
|
||||
Version: "1.0",
|
||||
Service: NewPrivateAdminAPI(s),
|
||||
}, {
|
||||
Namespace: "debug",
|
||||
Version: "1.0",
|
||||
Service: NewPublicDebugAPI(s),
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "debug",
|
||||
Version: "1.0",
|
||||
Service: NewPrivateDebugAPI(s),
|
||||
}, {
|
||||
},
|
||||
//{
|
||||
// Namespace: "admin",
|
||||
// Version: "1.0",
|
||||
// Service: NewPrivateAdminAPI(s),
|
||||
//},
|
||||
//{
|
||||
// Namespace: "debug",
|
||||
// Version: "1.0",
|
||||
// Service: NewPublicDebugAPI(s),
|
||||
// Public: true,
|
||||
//}, {
|
||||
// Namespace: "debug",
|
||||
// Version: "1.0",
|
||||
// Service: NewPrivateDebugAPI(s),
|
||||
//},
|
||||
{
|
||||
Namespace: "net",
|
||||
Version: "1.0",
|
||||
Service: s.netRPCService,
|
||||
|
@ -1,11 +1,11 @@
|
||||
package stagedsync
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/eth/stagedsync/stages"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
// Package ethstats implements the network stats reporting service.
|
||||
package ethstats
|
||||
|
||||
/*
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
@ -767,3 +768,4 @@ func (s *Service) reportStats(conn *connWrapper) error {
|
||||
}
|
||||
return conn.WriteJSON(report)
|
||||
}
|
||||
*/
|
||||
|
1
go.mod
1
go.mod
@ -55,7 +55,6 @@ require (
|
||||
github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222
|
||||
github.com/petar/GoLLRB v0.0.0-20190514000832-33fb24c13b99
|
||||
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/prometheus/client_golang v1.7.1
|
||||
github.com/prometheus/tsdb v0.10.0
|
||||
github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00
|
||||
|
@ -18,7 +18,6 @@ package debug
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"os"
|
||||
@ -31,8 +30,6 @@ import (
|
||||
"github.com/ledgerwatch/turbo-geth/metrics"
|
||||
"github.com/ledgerwatch/turbo-geth/metrics/exp"
|
||||
|
||||
colorable "github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
@ -140,18 +137,9 @@ var (
|
||||
glogger *log.GlogHandler
|
||||
)
|
||||
|
||||
func init() {
|
||||
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
||||
output := io.Writer(os.Stderr)
|
||||
if usecolor {
|
||||
output = colorable.NewColorableStderr()
|
||||
}
|
||||
ostream = log.StreamHandler(output, log.TerminalFormat(usecolor))
|
||||
glogger = log.NewGlogHandler(ostream)
|
||||
}
|
||||
|
||||
func SetupCobra(cmd *cobra.Command) error {
|
||||
flags := cmd.Flags()
|
||||
flags := cmd.PersistentFlags()
|
||||
|
||||
dbg, err := flags.GetBool(debugFlag.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -160,7 +148,6 @@ func SetupCobra(cmd *cobra.Command) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vmodule, err := flags.GetString(vmoduleFlag.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -170,20 +157,8 @@ func SetupCobra(cmd *cobra.Command) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// logging
|
||||
ostream, glogger = log.SetupDefaultTerminalLogger(log.Lvl(lvl), vmodule, backtrace)
|
||||
log.PrintOrigins(dbg)
|
||||
glogger.Verbosity(log.Lvl(lvl))
|
||||
err = glogger.Vmodule(vmodule)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if backtrace != "" {
|
||||
err = glogger.BacktraceAt(backtrace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
log.Root().SetHandler(glogger)
|
||||
|
||||
memprofilerate, err := flags.GetInt(memprofilerateFlag.Name)
|
||||
if err != nil {
|
||||
@ -263,10 +238,11 @@ func SetupCobra(cmd *cobra.Command) error {
|
||||
func Setup(ctx *cli.Context) error {
|
||||
// logging
|
||||
log.PrintOrigins(ctx.GlobalBool(debugFlag.Name))
|
||||
glogger.Verbosity(log.Lvl(ctx.GlobalInt(verbosityFlag.Name)))
|
||||
glogger.Vmodule(ctx.GlobalString(vmoduleFlag.Name))
|
||||
glogger.BacktraceAt(ctx.GlobalString(backtraceAtFlag.Name))
|
||||
log.Root().SetHandler(glogger)
|
||||
ostream, glogger = log.SetupDefaultTerminalLogger(
|
||||
log.Lvl(ctx.GlobalInt(verbosityFlag.Name)),
|
||||
ctx.GlobalString(vmoduleFlag.Name),
|
||||
ctx.GlobalString(backtraceAtFlag.Name),
|
||||
)
|
||||
|
||||
// profiling, tracing
|
||||
if ctx.GlobalIsSet(legacyMemprofilerateFlag.Name) {
|
||||
|
@ -2,6 +2,8 @@ package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
@ -357,3 +359,45 @@ func (m muster) FileHandler(path string, fmtr Format) Handler {
|
||||
func (m muster) NetHandler(network, addr string, fmtr Format) Handler {
|
||||
return must(NetHandler(network, addr, fmtr))
|
||||
}
|
||||
|
||||
// verbosityPerModule sets the glog verbosity pattern.
|
||||
//
|
||||
// The syntax of the argument is a comma-separated list of pattern=N, where the
|
||||
// pattern is a literal file name or "glob" pattern matching and N is a V level:
|
||||
// pattern="gopher.go=3"
|
||||
// sets the V level to 3 in all Go files named "gopher.go"
|
||||
//
|
||||
// pattern="foo=3"
|
||||
// sets V to 3 in all files of any packages whose import path ends in "foo"
|
||||
//
|
||||
// pattern="foo/*=3"
|
||||
// sets V to 3 in all files of any packages whose import path contains "foo"
|
||||
//
|
||||
//
|
||||
//
|
||||
// backtraceAt sets the glog backtrace location. When set to a file and line
|
||||
// number holding a logging statement, a stack trace will be written to the Info
|
||||
// log whenever execution hits that statement.
|
||||
// Unlike verbosityPerModule, the ".go" must be present.
|
||||
//
|
||||
func SetupDefaultTerminalLogger(lvl Lvl, verbosityPerModule string, backtraceAt string) (ostream Handler, glogger *GlogHandler) {
|
||||
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
||||
output := io.Writer(os.Stderr)
|
||||
if usecolor {
|
||||
output = colorable.NewColorableStderr()
|
||||
}
|
||||
ostream = StreamHandler(output, TerminalFormat(usecolor))
|
||||
glogger = NewGlogHandler(ostream)
|
||||
Root().SetHandler(glogger)
|
||||
glogger.Verbosity(lvl)
|
||||
if err := glogger.Vmodule(verbosityPerModule); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if backtraceAt != "" {
|
||||
if err := glogger.BacktraceAt(backtraceAt); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
return ostream, glogger
|
||||
}
|
||||
|
@ -29,8 +29,6 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/accounts/keystore"
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/common/fdlimit"
|
||||
@ -193,7 +191,7 @@ func makeMiner(genesis *core.Genesis) (*node.Node, *eth.Ethereum, error) {
|
||||
err = stack.Start()
|
||||
return stack, ethBackend, err
|
||||
}); err != nil {
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("cannot register stress test miner. config %v", ethConfig))
|
||||
return nil, fmt.Errorf("cannot register stress test miner. config %v", ethConfig)
|
||||
}
|
||||
// Start the node and return if successful
|
||||
return stack, stack.Start()
|
||||
|
1
rpc/helpers.go
Normal file
1
rpc/helpers.go
Normal file
@ -0,0 +1 @@
|
||||
package rpc
|
@ -28,7 +28,6 @@ import (
|
||||
"github.com/ledgerwatch/turbo-geth/crypto"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
"github.com/ledgerwatch/turbo-geth/log"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -327,7 +326,7 @@ func (t *Trie) UpdateAccountCode(key []byte, code codeNode) error {
|
||||
|
||||
accNode, gotValue := t.getAccount(t.root, hex, 0)
|
||||
if accNode == nil || !gotValue {
|
||||
return errors.Wrapf(ethdb.ErrKeyNotFound, "account not found with key: %x", key)
|
||||
return fmt.Errorf("account not found with key: %x, %w", key, ethdb.ErrKeyNotFound)
|
||||
}
|
||||
|
||||
actualCodeHash := crypto.Keccak256(code)
|
||||
@ -356,7 +355,7 @@ func (t *Trie) UpdateAccountCodeSize(key []byte, codeSize int) error {
|
||||
|
||||
accNode, gotValue := t.getAccount(t.root, hex, 0)
|
||||
if accNode == nil || !gotValue {
|
||||
return errors.Wrapf(ethdb.ErrKeyNotFound, "account not found with key: %x", key)
|
||||
return fmt.Errorf("account not found with key: %x, %w", key, ethdb.ErrKeyNotFound)
|
||||
}
|
||||
|
||||
accNode.codeSize = codeSize
|
||||
|
24
turbo/adapter/block_getter.go
Normal file
24
turbo/adapter/block_getter.go
Normal file
@ -0,0 +1,24 @@
|
||||
package adapter
|
||||
|
||||
import (
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/core/rawdb"
|
||||
"github.com/ledgerwatch/turbo-geth/core/types"
|
||||
)
|
||||
|
||||
func NewBlockGetter(dbReader rawdb.DatabaseReader) *blockGetter {
|
||||
return &blockGetter{dbReader}
|
||||
}
|
||||
|
||||
type blockGetter struct {
|
||||
dbReader rawdb.DatabaseReader
|
||||
}
|
||||
|
||||
func (g *blockGetter) GetBlockByHash(hash common.Hash) *types.Block {
|
||||
return rawdb.ReadBlockByHash(g.dbReader, hash)
|
||||
|
||||
}
|
||||
|
||||
func (g *blockGetter) GetBlock(hash common.Hash, number uint64) *types.Block {
|
||||
return rawdb.ReadBlock(g.dbReader, hash, number)
|
||||
}
|
77
turbo/adapter/chain_context.go
Normal file
77
turbo/adapter/chain_context.go
Normal file
@ -0,0 +1,77 @@
|
||||
package adapter
|
||||
|
||||
import (
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/consensus"
|
||||
"github.com/ledgerwatch/turbo-geth/core/rawdb"
|
||||
"github.com/ledgerwatch/turbo-geth/core/state"
|
||||
"github.com/ledgerwatch/turbo-geth/core/types"
|
||||
"github.com/ledgerwatch/turbo-geth/params"
|
||||
"github.com/ledgerwatch/turbo-geth/rpc"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type chainContext struct {
|
||||
db rawdb.DatabaseReader
|
||||
}
|
||||
|
||||
func NewChainContext(db rawdb.DatabaseReader) *chainContext {
|
||||
return &chainContext{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
type powEngine struct {
|
||||
}
|
||||
|
||||
func (c *powEngine) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, seal bool) error {
|
||||
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (func(), <-chan error) {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) VerifySeal(chain consensus.ChainHeaderReader, header *types.Header) error {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) Finalize(chainConfig *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs []*types.Transaction, uncles []*types.Header) {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) FinalizeAndAssemble(chainConfig *params.ChainConfig, header *types.Header, state *state.IntraBlockState, txs []*types.Transaction,
|
||||
uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) Seal(_ consensus.Cancel, chain consensus.ChainHeaderReader, block *types.Block, results chan<- consensus.ResultWithContext, stop <-chan struct{}) error {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) SealHash(header *types.Header) common.Hash {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int {
|
||||
panic("must not be called")
|
||||
}
|
||||
func (c *powEngine) APIs(chain consensus.ChainHeaderReader) []rpc.API {
|
||||
panic("must not be called")
|
||||
}
|
||||
|
||||
func (c *powEngine) Close() error {
|
||||
panic("must not be called")
|
||||
}
|
||||
|
||||
func (c *powEngine) Author(header *types.Header) (common.Address, error) {
|
||||
return header.Coinbase, nil
|
||||
}
|
||||
|
||||
func (c *chainContext) GetHeader(hash common.Hash, number uint64) *types.Header {
|
||||
return rawdb.ReadHeader(c.db, hash, number)
|
||||
}
|
||||
|
||||
func (c *chainContext) Engine() consensus.Engine {
|
||||
return &powEngine{}
|
||||
}
|
50
turbo/adapter/ethapi/internal.go
Normal file
50
turbo/adapter/ethapi/internal.go
Normal file
@ -0,0 +1,50 @@
|
||||
package ethapi
|
||||
|
||||
// This file stores proxy-objects for `internal` package
|
||||
import (
|
||||
"github.com/ledgerwatch/turbo-geth/core"
|
||||
"github.com/ledgerwatch/turbo-geth/core/types"
|
||||
"github.com/ledgerwatch/turbo-geth/internal/ethapi"
|
||||
)
|
||||
|
||||
// This package provides copy-paste and proxy objects to "internal/ethapi" package
|
||||
|
||||
func NewRevertError(result *core.ExecutionResult) *RevertError {
|
||||
return &RevertError{ethapi.NewRevertError(result)}
|
||||
}
|
||||
|
||||
type RevertError struct {
|
||||
*ethapi.RevertError
|
||||
}
|
||||
|
||||
type CallArgs struct {
|
||||
*ethapi.CallArgs
|
||||
}
|
||||
|
||||
type ExecutionResult struct {
|
||||
*ethapi.ExecutionResult
|
||||
}
|
||||
|
||||
//nolint
|
||||
func RPCMarshalHeader(head *types.Header) map[string]interface{} {
|
||||
return ethapi.RPCMarshalHeader(head)
|
||||
}
|
||||
|
||||
//nolint
|
||||
func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool, additional map[string]interface{}) (map[string]interface{}, error) {
|
||||
fields, err := ethapi.RPCMarshalBlock(b, inclTx, fullTx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for k, v := range additional {
|
||||
fields[k] = v
|
||||
}
|
||||
|
||||
return fields, err
|
||||
}
|
||||
|
||||
//nolint
|
||||
type RPCTransaction struct {
|
||||
*ethapi.RPCTransaction
|
||||
}
|
@ -1,33 +1,22 @@
|
||||
package commands
|
||||
package adapter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/petar/GoLLRB/llrb"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/common/dbutils"
|
||||
"github.com/ledgerwatch/turbo-geth/core/state"
|
||||
"github.com/ledgerwatch/turbo-geth/core/types"
|
||||
"github.com/ledgerwatch/turbo-geth/core/types/accounts"
|
||||
"github.com/ledgerwatch/turbo-geth/crypto"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
"golang.org/x/net/context"
|
||||
"github.com/petar/GoLLRB/llrb"
|
||||
)
|
||||
|
||||
type storageItem struct {
|
||||
key, seckey common.Hash
|
||||
value uint256.Int
|
||||
}
|
||||
|
||||
func (a *storageItem) Less(b llrb.Item) bool {
|
||||
bi := b.(*storageItem)
|
||||
return bytes.Compare(a.key[:], bi.key[:]) < 0
|
||||
}
|
||||
|
||||
type StateReader struct {
|
||||
accountReads map[common.Address]struct{}
|
||||
storageReads map[common.Address]map[common.Hash]struct{}
|
||||
@ -238,3 +227,23 @@ func (r *StateReader) ForEachStorage(addr common.Address, start []byte, cb func(
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
type storageItem struct {
|
||||
key, seckey common.Hash
|
||||
value uint256.Int
|
||||
}
|
||||
|
||||
func (a *storageItem) Less(b llrb.Item) bool {
|
||||
bi := b.(*storageItem)
|
||||
return bytes.Compare(a.key[:], bi.key[:]) < 0
|
||||
}
|
||||
|
||||
// computeIntraBlockState retrieves the state database associated with a certain block.
|
||||
// If no state is locally available for the given block, a number of blocks are
|
||||
// attempted to be reexecuted to generate the desired state.
|
||||
func ComputeIntraBlockState(chainKV ethdb.KV, block *types.Block) (*state.IntraBlockState, *StateReader) {
|
||||
// If we have the state fully available, use that
|
||||
reader := NewStateReader(chainKV, block.NumberU64())
|
||||
statedb := state.New(reader)
|
||||
return statedb, reader
|
||||
}
|
53
turbo/rpchelper/helper.go
Normal file
53
turbo/rpchelper/helper.go
Normal file
@ -0,0 +1,53 @@
|
||||
package rpchelper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/core/rawdb"
|
||||
"github.com/ledgerwatch/turbo-geth/core/types/accounts"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
"github.com/ledgerwatch/turbo-geth/rpc"
|
||||
"github.com/ledgerwatch/turbo-geth/turbo/adapter"
|
||||
)
|
||||
|
||||
func GetBlockNumber(blockNrOrHash rpc.BlockNumberOrHash, dbReader rawdb.DatabaseReader) (uint64, common.Hash, error) {
|
||||
var blockNumber uint64
|
||||
var err error
|
||||
|
||||
hash, ok := blockNrOrHash.Hash()
|
||||
if !ok {
|
||||
blockNumber = uint64(blockNrOrHash.BlockNumber.Int64())
|
||||
hash, err = GetHashByNumber(blockNumber, blockNrOrHash.RequireCanonical, dbReader)
|
||||
if err != nil {
|
||||
return 0, common.Hash{}, err
|
||||
}
|
||||
} else {
|
||||
block := rawdb.ReadBlockByHash(dbReader, hash)
|
||||
if block == nil {
|
||||
return 0, common.Hash{}, fmt.Errorf("block %x not found", hash)
|
||||
}
|
||||
blockNumber = block.NumberU64()
|
||||
|
||||
if blockNrOrHash.RequireCanonical && rawdb.ReadCanonicalHash(dbReader, blockNumber) != hash {
|
||||
return 0, common.Hash{}, fmt.Errorf("hash %q is not currently canonical", hash.String())
|
||||
}
|
||||
}
|
||||
return blockNumber, hash, nil
|
||||
}
|
||||
|
||||
func GetAccount(chainKV ethdb.KV, blockNumber uint64, address common.Address) (*accounts.Account, error) {
|
||||
reader := adapter.NewStateReader(chainKV, blockNumber)
|
||||
return reader.ReadAccountData(address)
|
||||
}
|
||||
|
||||
func GetHashByNumber(blockNumber uint64, requireCanonical bool, dbReader rawdb.DatabaseReader) (common.Hash, error) {
|
||||
if requireCanonical {
|
||||
return rawdb.ReadCanonicalHash(dbReader, blockNumber), nil
|
||||
}
|
||||
|
||||
block := rawdb.ReadBlockByNumber(dbReader, blockNumber)
|
||||
if block == nil {
|
||||
return common.Hash{}, fmt.Errorf("block %d not found", blockNumber)
|
||||
}
|
||||
return block.Hash(), nil
|
||||
}
|
146
turbo/transactions/call.go
Normal file
146
turbo/transactions/call.go
Normal file
@ -0,0 +1,146 @@
|
||||
package transactions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/core"
|
||||
"github.com/ledgerwatch/turbo-geth/core/rawdb"
|
||||
"github.com/ledgerwatch/turbo-geth/core/state"
|
||||
"github.com/ledgerwatch/turbo-geth/core/types"
|
||||
"github.com/ledgerwatch/turbo-geth/core/vm"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
"github.com/ledgerwatch/turbo-geth/internal/ethapi"
|
||||
"github.com/ledgerwatch/turbo-geth/log"
|
||||
"github.com/ledgerwatch/turbo-geth/params"
|
||||
"github.com/ledgerwatch/turbo-geth/rpc"
|
||||
"github.com/ledgerwatch/turbo-geth/turbo/rpchelper"
|
||||
"math/big"
|
||||
"time"
|
||||
)
|
||||
|
||||
const callTimeout = 5 * time.Second
|
||||
|
||||
func DoCall(ctx context.Context, args ethapi.CallArgs, kv ethdb.KV, dbReader rawdb.DatabaseReader, blockNrOrHash rpc.BlockNumberOrHash, overrides *map[common.Address]ethapi.Account, GasCap uint64) (*core.ExecutionResult, error) {
|
||||
// todo: Pending state is only known by the miner
|
||||
/*
|
||||
if blockNrOrHash.BlockNumber != nil && *blockNrOrHash.BlockNumber == rpc.PendingBlockNumber {
|
||||
block, state, _ := b.eth.miner.Pending()
|
||||
return state, block.Header(), nil
|
||||
}
|
||||
*/
|
||||
|
||||
blockNumber, hash, err := rpchelper.GetBlockNumber(blockNrOrHash, dbReader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds := state.NewPlainDBState(kv, blockNumber)
|
||||
state := state.New(ds)
|
||||
if state == nil {
|
||||
return nil, fmt.Errorf("can't get the state for %d", blockNumber)
|
||||
}
|
||||
|
||||
header := rawdb.ReadHeader(dbReader, hash, blockNumber)
|
||||
if header == nil {
|
||||
return nil, fmt.Errorf("block %d(%x) not found", blockNumber, hash)
|
||||
}
|
||||
|
||||
// Override the fields of specified contracts before execution.
|
||||
if overrides != nil {
|
||||
for addr, account := range *overrides {
|
||||
// Override account nonce.
|
||||
if account.Nonce != nil {
|
||||
state.SetNonce(addr, uint64(*account.Nonce))
|
||||
}
|
||||
// Override account(contract) code.
|
||||
if account.Code != nil {
|
||||
state.SetCode(addr, *account.Code)
|
||||
}
|
||||
// Override account balance.
|
||||
if account.Balance != nil {
|
||||
balance, _ := uint256.FromBig((*big.Int)(*account.Balance))
|
||||
state.SetBalance(addr, balance)
|
||||
}
|
||||
if account.State != nil && account.StateDiff != nil {
|
||||
return nil, fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
|
||||
}
|
||||
// Replace entire state if caller requires.
|
||||
if account.State != nil {
|
||||
state.SetStorage(addr, *account.State)
|
||||
}
|
||||
// Apply state diff into specified accounts.
|
||||
if account.StateDiff != nil {
|
||||
for key, value := range *account.StateDiff {
|
||||
key := key
|
||||
state.SetState(addr, &key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setup context so it may be cancelled the call has completed
|
||||
// or, in case of unmetered gas, setup a context with a timeout.
|
||||
var cancel context.CancelFunc
|
||||
if callTimeout > 0 {
|
||||
ctx, cancel = context.WithTimeout(ctx, callTimeout)
|
||||
} else {
|
||||
ctx, cancel = context.WithCancel(ctx)
|
||||
}
|
||||
|
||||
// Make sure the context is cancelled when the call has completed
|
||||
// this makes sure resources are cleaned up.
|
||||
defer cancel()
|
||||
|
||||
// Get a new instance of the EVM.
|
||||
msg := args.ToMessage(GasCap)
|
||||
|
||||
evmCtx := GetEvmContext(msg, header, blockNrOrHash.RequireCanonical, dbReader)
|
||||
|
||||
evm := vm.NewEVM(evmCtx, state, params.MainnetChainConfig, vm.Config{})
|
||||
|
||||
// Wait for the context to be done and cancel the evm. Even if the
|
||||
// EVM has finished, cancelling may be done (repeatedly)
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
evm.Cancel()
|
||||
}()
|
||||
|
||||
gp := new(core.GasPool).AddGas(msg.Gas())
|
||||
result, err := core.ApplyMessage(evm, msg, gp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the timer caused an abort, return an appropriate error message
|
||||
if evm.Cancelled() {
|
||||
return nil, fmt.Errorf("execution aborted (timeout = %v)", callTimeout)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func GetEvmContext(msg core.Message, header *types.Header, requireCanonical bool, dbReader rawdb.DatabaseReader) vm.Context {
|
||||
return vm.Context{
|
||||
CanTransfer: core.CanTransfer,
|
||||
Transfer: core.Transfer,
|
||||
GetHash: getHashGetter(requireCanonical, dbReader),
|
||||
Origin: msg.From(),
|
||||
Coinbase: header.Coinbase,
|
||||
BlockNumber: new(big.Int).Set(header.Number),
|
||||
Time: new(big.Int).SetUint64(header.Time),
|
||||
Difficulty: new(big.Int).Set(header.Difficulty),
|
||||
GasLimit: header.GasLimit,
|
||||
GasPrice: msg.GasPrice().ToBig(),
|
||||
}
|
||||
}
|
||||
|
||||
func getHashGetter(requireCanonical bool, dbReader rawdb.DatabaseReader) func(uint64) common.Hash {
|
||||
return func(n uint64) common.Hash {
|
||||
hash, err := rpchelper.GetHashByNumber(n, requireCanonical, dbReader)
|
||||
if err != nil {
|
||||
log.Debug("can't get block hash by number", "number", n, "only-canonical", requireCanonical)
|
||||
}
|
||||
return hash
|
||||
}
|
||||
}
|
141
turbo/transactions/tracing.go
Normal file
141
turbo/transactions/tracing.go
Normal file
@ -0,0 +1,141 @@
|
||||
package transactions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/core"
|
||||
"github.com/ledgerwatch/turbo-geth/core/state"
|
||||
"github.com/ledgerwatch/turbo-geth/core/types"
|
||||
"github.com/ledgerwatch/turbo-geth/core/vm"
|
||||
"github.com/ledgerwatch/turbo-geth/eth"
|
||||
"github.com/ledgerwatch/turbo-geth/eth/tracers"
|
||||
"github.com/ledgerwatch/turbo-geth/ethdb"
|
||||
"github.com/ledgerwatch/turbo-geth/internal/ethapi"
|
||||
"github.com/ledgerwatch/turbo-geth/params"
|
||||
state2 "github.com/ledgerwatch/turbo-geth/turbo/adapter"
|
||||
)
|
||||
|
||||
const (
|
||||
// defaultTraceTimeout is the amount of time a single transaction can execute
|
||||
// by default before being forcefully aborted.
|
||||
defaultTraceTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
type BlockGetter interface {
|
||||
// GetBlockByHash retrieves a block from the database by hash, caching it if found.
|
||||
GetBlockByHash(hash common.Hash) *types.Block
|
||||
// GetBlock retrieves a block from the database by hash and number,
|
||||
// caching it if found.
|
||||
GetBlock(hash common.Hash, number uint64) *types.Block
|
||||
}
|
||||
|
||||
// computeTxEnv returns the execution environment of a certain transaction.
|
||||
func ComputeTxEnv(ctx context.Context, blockGetter BlockGetter, cfg *params.ChainConfig, chain core.ChainContext, chainKV ethdb.KV, blockHash common.Hash, txIndex uint64) (core.Message, vm.Context, *state.IntraBlockState, *state2.StateReader, error) {
|
||||
// Create the parent state database
|
||||
block := blockGetter.GetBlockByHash(blockHash)
|
||||
if block == nil {
|
||||
return nil, vm.Context{}, nil, nil, fmt.Errorf("block %x not found", blockHash)
|
||||
}
|
||||
parent := blockGetter.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||
if parent == nil {
|
||||
return nil, vm.Context{}, nil, nil, fmt.Errorf("parent %x not found", block.ParentHash())
|
||||
}
|
||||
|
||||
statedb, reader := state2.ComputeIntraBlockState(chainKV, parent)
|
||||
|
||||
if txIndex == 0 && len(block.Transactions()) == 0 {
|
||||
return nil, vm.Context{}, statedb, reader, nil
|
||||
}
|
||||
// Recompute transactions up to the target index.
|
||||
signer := types.MakeSigner(cfg, block.Number())
|
||||
|
||||
for idx, tx := range block.Transactions() {
|
||||
select {
|
||||
default:
|
||||
case <-ctx.Done():
|
||||
return nil, vm.Context{}, nil, nil, ctx.Err()
|
||||
}
|
||||
statedb.Prepare(tx.Hash(), blockHash, idx)
|
||||
|
||||
// Assemble the transaction call message and return if the requested offset
|
||||
msg, _ := tx.AsMessage(signer)
|
||||
EVMcontext := core.NewEVMContext(msg, block.Header(), chain, nil)
|
||||
if idx == int(txIndex) {
|
||||
return msg, EVMcontext, statedb, reader, nil
|
||||
}
|
||||
// Not yet the searched for transaction, execute on top of the current state
|
||||
vmenv := vm.NewEVM(EVMcontext, statedb, cfg, vm.Config{})
|
||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
|
||||
return nil, vm.Context{}, nil, 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.FinalizeTx(vmenv.ChainConfig().WithEIPsFlags(context.Background(), block.Number()), reader)
|
||||
}
|
||||
return nil, vm.Context{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %x", txIndex, blockHash)
|
||||
}
|
||||
|
||||
// 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 TraceTx(ctx context.Context, message core.Message, vmctx vm.Context, ibs vm.IntraBlockState, config *eth.TraceConfig) (interface{}, error) {
|
||||
// Assemble the structured logger or the JavaScript tracer
|
||||
var (
|
||||
tracer vm.Tracer
|
||||
err error
|
||||
)
|
||||
switch {
|
||||
case config != nil && config.Tracer != nil:
|
||||
// Define a meaningful timeout of a single transaction trace
|
||||
timeout := defaultTraceTimeout
|
||||
if config.Timeout != nil {
|
||||
if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Constuct the JavaScript tracer to execute with
|
||||
if tracer, err = tracers.New(*config.Tracer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Handle timeouts and RPC cancellations
|
||||
deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
|
||||
go func() {
|
||||
<-deadlineCtx.Done()
|
||||
tracer.(*tracers.Tracer).Stop(errors.New("execution timeout"))
|
||||
}()
|
||||
defer cancel()
|
||||
|
||||
case config == nil:
|
||||
tracer = vm.NewStructLogger(nil)
|
||||
|
||||
default:
|
||||
tracer = vm.NewStructLogger(config.LogConfig)
|
||||
}
|
||||
// Run the transaction with tracing enabled.
|
||||
vmenv := vm.NewEVM(vmctx, ibs, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer})
|
||||
|
||||
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:
|
||||
return ðapi.ExecutionResult{
|
||||
Gas: result.UsedGas,
|
||||
Failed: result.Failed(),
|
||||
ReturnValue: fmt.Sprintf("%x", result.Return()),
|
||||
StructLogs: ethapi.FormatLogs(tracer.StructLogs()),
|
||||
}, nil
|
||||
|
||||
case *tracers.Tracer:
|
||||
return tracer.GetResult()
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("bad tracer type %T", tracer))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user