diff --git a/cmd/prometheus/dashboards/erigon.json b/cmd/prometheus/dashboards/erigon.json index 2dfe84dd4c613abfd2db40ceb0fa0b9c6000b275..4b0562176fa8f5adc12927a36215c4c64fcf1d00 100644 --- a/cmd/prometheus/dashboards/erigon.json +++ b/cmd/prometheus/dashboards/erigon.json @@ -22,7 +22,7 @@ "gnetId": null, "graphTooltip": 0, "id": 1, - "iteration": 1632101487032, + "iteration": 1632801657282, "links": [], "panels": [ { @@ -3008,7 +3008,7 @@ "type": "timeseries" }, { - "collapsed": true, + "collapsed": false, "datasource": null, "gridPos": { "h": 1, @@ -3016,6 +3016,191 @@ "x": 0, "y": 79 }, + "id": 183, + "panels": [], + "title": "RPC", + "type": "row" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 80 + }, + "id": 185, + "options": { + "legend": { + "calcs": [ + "mean", + "last" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "exemplar": true, + "expr": "rpc_duration_seconds{quantile=\"$quantile\",instance=~\"$instance\"}", + "interval": "", + "legendFormat": "rpc_duration_seconds: {{ method }} {{ instance }}", + "refId": "A" + } + ], + "title": "Timings", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 80 + }, + "id": 184, + "options": { + "legend": { + "calcs": [ + "mean", + "last" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "exemplar": true, + "expr": "sum(delta(cache_total{result=\"hit\",name=\"rpc\",instance=~\"$instance\"}[1m]))/sum(delta(cache_total{name=\"rpc\",instance=~\"$instance\"}[1m])) ", + "hide": false, + "interval": "", + "legendFormat": "hit rate: {{ instance }} ", + "refId": "A" + } + ], + "title": "Cache hit-rate", + "type": "timeseries" + }, + { + "collapsed": true, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 88 + }, "id": 146, "panels": [ { @@ -3713,7 +3898,7 @@ "h": 1, "w": 24, "x": 0, - "y": 80 + "y": 89 }, "id": 75, "panels": [], @@ -3777,7 +3962,7 @@ "h": 6, "w": 12, "x": 0, - "y": 81 + "y": 90 }, "id": 96, "links": [], @@ -3880,7 +4065,7 @@ "h": 6, "w": 12, "x": 12, - "y": 81 + "y": 90 }, "id": 77, "links": [], @@ -3938,7 +4123,7 @@ "h": 1, "w": 24, "x": 0, - "y": 87 + "y": 96 }, "id": 4, "panels": [], @@ -3982,7 +4167,7 @@ "h": 3, "w": 4, "x": 0, - "y": 88 + "y": 97 }, "id": 108, "interval": null, @@ -4061,7 +4246,7 @@ "h": 3, "w": 4, "x": 4, - "y": 88 + "y": 97 }, "id": 111, "interval": null, @@ -4141,7 +4326,7 @@ "h": 3, "w": 4, "x": 8, - "y": 88 + "y": 97 }, "id": 109, "interval": null, @@ -4221,7 +4406,7 @@ "h": 3, "w": 4, "x": 12, - "y": 88 + "y": 97 }, "id": 113, "interval": null, @@ -4300,7 +4485,7 @@ "h": 3, "w": 4, "x": 16, - "y": 88 + "y": 97 }, "id": 114, "interval": null, @@ -4379,7 +4564,7 @@ "h": 3, "w": 4, "x": 20, - "y": 88 + "y": 97 }, "id": 115, "interval": null, @@ -4479,7 +4664,7 @@ "h": 6, "w": 12, "x": 0, - "y": 91 + "y": 100 }, "id": 110, "links": [], @@ -4583,7 +4768,7 @@ "h": 6, "w": 12, "x": 12, - "y": 91 + "y": 100 }, "id": 116, "links": [], @@ -4687,7 +4872,7 @@ "h": 7, "w": 24, "x": 0, - "y": 97 + "y": 106 }, "id": 117, "links": [], @@ -4815,7 +5000,7 @@ "h": 1, "w": 24, "x": 0, - "y": 104 + "y": 113 }, "id": 138, "panels": [ @@ -4980,9 +5165,15 @@ { "allValue": null, "current": { - "selected": false, - "text": "All", - "value": "$__all" + "selected": true, + "text": [ + "turbogeth16c.weblogix.it:6060", + "turbogeth16c.weblogix.it:6061" + ], + "value": [ + "turbogeth16c.weblogix.it:6060", + "turbogeth16c.weblogix.it:6061" + ] }, "datasource": "Prometheus", "definition": "go_goroutines", @@ -5087,7 +5278,7 @@ ] }, "time": { - "from": "now-12h", + "from": "now-2m", "to": "now" }, "timepicker": { @@ -5117,5 +5308,5 @@ "timezone": "", "title": "Erigon Prometheus", "uid": "FPpjH6Hik", - "version": 40 + "version": 45 } \ No newline at end of file diff --git a/cmd/rpcdaemon/cli/config.go b/cmd/rpcdaemon/cli/config.go index e3433dd28cdce6950a25612992b22725b1c9dd83..cea4c8269c01099c2690efd96b8c53a511f17d72 100644 --- a/cmd/rpcdaemon/cli/config.go +++ b/cmd/rpcdaemon/cli/config.go @@ -3,7 +3,9 @@ package cli import ( "context" "encoding/binary" + "errors" "fmt" + "io" "net/http" "path" "time" @@ -12,6 +14,7 @@ import ( "github.com/ledgerwatch/erigon-lib/gointerfaces/grpcutil" "github.com/ledgerwatch/erigon-lib/gointerfaces/remote" "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon-lib/kv/kvcache" kv2 "github.com/ledgerwatch/erigon-lib/kv/mdbx" "github.com/ledgerwatch/erigon-lib/kv/remotedb" "github.com/ledgerwatch/erigon-lib/kv/remotedbserver" @@ -24,6 +27,9 @@ import ( "github.com/ledgerwatch/erigon/rpc" "github.com/ledgerwatch/log/v3" "github.com/spf13/cobra" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) type Flags struct { @@ -51,6 +57,7 @@ type Flags struct { TraceCompatibility bool // Bug for bug compatibility for trace_ routines with OpenEthereum TxPoolV2 bool TxPoolApiAddr string + StateCache kvcache.CoherentConfig } var rootCmd = &cobra.Command{ @@ -124,15 +131,66 @@ func RootCommand() (*cobra.Command, *Flags) { return nil } + cfg.StateCache.MetricsLabel = "rpc" + return rootCmd, cfg } -func checkDbCompatibility(db kv.RoDB) error { +type StateChangesClient interface { + StateChanges(ctx context.Context, in *remote.StateChangeRequest, opts ...grpc.CallOption) (remote.KV_StateChangesClient, error) +} + +func subscribeToStateChangesLoop(ctx context.Context, client StateChangesClient, cache kvcache.Cache) { + go func() { + for { + select { + case <-ctx.Done(): + return + default: + } + if err := subscribeToStateChanges(ctx, client, cache); err != nil { + if s, ok := status.FromError(err); ok && retryLater(s.Code()) { + time.Sleep(time.Second) + continue + } + if errors.Is(err, io.EOF) || errors.Is(err, context.Canceled) { + continue + } + log.Warn("[txpool.handleStateChanges]", "err", err) + } + } + }() +} + +func retryLater(code codes.Code) bool { + return code == codes.Unavailable || code == codes.Canceled || code == codes.ResourceExhausted +} + +func subscribeToStateChanges(ctx context.Context, client StateChangesClient, cache kvcache.Cache) error { + streamCtx, cancel := context.WithCancel(ctx) + defer cancel() + stream, err := client.StateChanges(streamCtx, &remote.StateChangeRequest{WithStorage: true, WithTransactions: false}, grpc.WaitForReady(true)) + if err != nil { + return err + } + for req, err := stream.Recv(); ; req, err = stream.Recv() { + if err != nil { + return err + } + if req == nil { + return nil + } + + cache.OnNewBlock(req) + } +} + +func checkDbCompatibility(ctx context.Context, db kv.RoDB) error { // DB schema version compatibility check var version []byte var compatErr error var compatTx kv.Tx - if compatTx, compatErr = db.BeginRo(context.Background()); compatErr != nil { + if compatTx, compatErr = db.BeginRo(ctx); compatErr != nil { return fmt.Errorf("open Ro Tx for DB schema compability check: %w", compatErr) } defer compatTx.Rollback() @@ -164,9 +222,9 @@ func checkDbCompatibility(db kv.RoDB) error { return nil } -func RemoteServices(ctx context.Context, cfg Flags, logger log.Logger, rootCancel context.CancelFunc) (db kv.RoDB, eth services.ApiBackend, txPool *services.TxPoolService, mining *services.MiningService, err error) { +func RemoteServices(ctx context.Context, cfg Flags, logger log.Logger, rootCancel context.CancelFunc) (db kv.RoDB, eth services.ApiBackend, txPool *services.TxPoolService, mining *services.MiningService, stateCache kvcache.Cache, err error) { if !cfg.SingleNodeMode && cfg.PrivateApiAddr == "" { - return nil, nil, nil, nil, fmt.Errorf("either remote db or local db must be specified") + return nil, nil, nil, nil, nil, fmt.Errorf("either remote db or local db must be specified") } // Do not change the order of these checks. Chaindata needs to be checked first, because PrivateApiAddr has default value which is not "" // If PrivateApiAddr is checked first, the Chaindata option will never work @@ -174,60 +232,68 @@ func RemoteServices(ctx context.Context, cfg Flags, logger log.Logger, rootCance var rwKv kv.RwDB rwKv, err = kv2.NewMDBX(logger).Path(cfg.Chaindata).Readonly().Open() if err != nil { - return nil, nil, nil, nil, err + return nil, nil, nil, nil, nil, err } - if compatErr := checkDbCompatibility(rwKv); compatErr != nil { - return nil, nil, nil, nil, compatErr + if compatErr := checkDbCompatibility(ctx, rwKv); compatErr != nil { + return nil, nil, nil, nil, nil, compatErr } db = rwKv - } else { - log.Info("if you run RPCDaemon on same machine with Erigon add --datadir option") + stateCache = kvcache.NewDummy() + return db, eth, txPool, mining, stateCache, nil } - if cfg.PrivateApiAddr != "" { - creds, err := grpcutil.TLS(cfg.TLSCACert, cfg.TLSCertfile, cfg.TLSKeyFile) + log.Info("if you run RPCDaemon on same machine with Erigon add --datadir option") + + if cfg.PrivateApiAddr == "" { + return db, eth, txPool, mining, stateCache, nil + } + + creds, err := grpcutil.TLS(cfg.TLSCACert, cfg.TLSCertfile, cfg.TLSKeyFile) + if err != nil { + return nil, nil, nil, nil, nil, fmt.Errorf("open tls cert: %w", err) + } + conn, err := grpcutil.Connect(creds, cfg.PrivateApiAddr) + if err != nil { + return nil, nil, nil, nil, nil, fmt.Errorf("could not connect to execution service privateApi: %w", err) + } + + kvClient := remote.NewKVClient(conn) + remoteKv, err := remotedb.NewRemote(gointerfaces.VersionFromProto(remotedbserver.KvServiceAPIVersion), logger, kvClient).Open() + if err != nil { + return nil, nil, nil, nil, nil, fmt.Errorf("could not connect to remoteKv: %w", err) + } + + stateCache = kvcache.New(cfg.StateCache) + subscribeToStateChangesLoop(ctx, kvClient, stateCache) + + remoteEth := services.NewRemoteBackend(conn) + txpoolConn := conn + if cfg.TxPoolV2 { + txpoolConn, err = grpcutil.Connect(creds, cfg.TxPoolApiAddr) if err != nil { - return nil, nil, nil, nil, fmt.Errorf("open tls cert: %w", err) + return nil, nil, nil, nil, nil, fmt.Errorf("could not connect to txpool api: %w", err) } - conn, err := grpcutil.Connect(creds, cfg.PrivateApiAddr) - if err != nil { - return nil, nil, nil, nil, fmt.Errorf("could not connect to execution service privateApi: %w", err) + } + mining = services.NewMiningService(txpoolConn) + txPool = services.NewTxPoolService(txpoolConn) + if db == nil { + db = remoteKv + } + eth = remoteEth + go func() { + if !remoteKv.EnsureVersionCompatibility() { + rootCancel() } - - kvClient := remote.NewKVClient(conn) - remoteKv, err := remotedb.NewRemote(gointerfaces.VersionFromProto(remotedbserver.KvServiceAPIVersion), logger, kvClient).Open() - if err != nil { - return nil, nil, nil, nil, fmt.Errorf("could not connect to remoteKv: %w", err) + if !remoteEth.EnsureVersionCompatibility() { + rootCancel() } - remoteEth := services.NewRemoteBackend(conn) - txpoolConn := conn - if cfg.TxPoolV2 { - txpoolConn, err = grpcutil.Connect(creds, cfg.TxPoolApiAddr) - if err != nil { - return nil, nil, nil, nil, fmt.Errorf("could not connect to txpool api: %w", err) - } + if mining != nil && !mining.EnsureVersionCompatibility() { + rootCancel() } - mining = services.NewMiningService(txpoolConn) - txPool = services.NewTxPoolService(txpoolConn) - if db == nil { - db = remoteKv + if !txPool.EnsureVersionCompatibility() { + rootCancel() } - eth = remoteEth - go func() { - if !remoteKv.EnsureVersionCompatibility() { - rootCancel() - } - if !remoteEth.EnsureVersionCompatibility() { - rootCancel() - } - if mining != nil && !mining.EnsureVersionCompatibility() { - rootCancel() - } - if !txPool.EnsureVersionCompatibility() { - rootCancel() - } - }() - } - return db, eth, txPool, mining, err + }() + return db, eth, txPool, mining, stateCache, err } func StartRpcServer(ctx context.Context, cfg Flags, rpcAPI []rpc.API) error { diff --git a/cmd/rpcdaemon/commands/call_traces_test.go b/cmd/rpcdaemon/commands/call_traces_test.go index bdb972f78f981f4965ac135ef78e758ba5f592a3..736c13535e91554c72d6ca10669047fe677f0ea1 100644 --- a/cmd/rpcdaemon/commands/call_traces_test.go +++ b/cmd/rpcdaemon/commands/call_traces_test.go @@ -6,6 +6,7 @@ import ( "testing" jsoniter "github.com/json-iterator/go" + "github.com/ledgerwatch/erigon-lib/kv/kvcache" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/cli" "github.com/ledgerwatch/erigon/common" "github.com/ledgerwatch/erigon/common/hexutil" @@ -44,7 +45,7 @@ func TestCallTraceOneByOne(t *testing.T) { if err != nil { t.Fatalf("generate chain: %v", err) } - api := NewTraceAPI(NewBaseApi(nil), m.DB, &cli.Flags{}) + api := NewTraceAPI(NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig)), m.DB, &cli.Flags{}) // Insert blocks 1 by 1, to tirgget possible "off by one" errors for i := 0; i < chain.Length; i++ { if err = m.InsertChain(chain.Slice(i, i+1)); err != nil { @@ -89,7 +90,7 @@ func TestCallTraceUnwind(t *testing.T) { if err != nil { t.Fatalf("generate chainB: %v", err) } - api := NewTraceAPI(NewBaseApi(nil), m.DB, &cli.Flags{}) + api := NewTraceAPI(NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig)), m.DB, &cli.Flags{}) if err = m.InsertChain(chainA); err != nil { t.Fatalf("inserting chainA: %v", err) } @@ -149,7 +150,7 @@ func TestFilterNoAddresses(t *testing.T) { if err != nil { t.Fatalf("generate chain: %v", err) } - api := NewTraceAPI(NewBaseApi(nil), m.DB, &cli.Flags{}) + api := NewTraceAPI(NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig)), m.DB, &cli.Flags{}) // Insert blocks 1 by 1, to tirgget possible "off by one" errors for i := 0; i < chain.Length; i++ { if err = m.InsertChain(chain.Slice(i, i+1)); err != nil { diff --git a/cmd/rpcdaemon/commands/corner_cases_support_test.go b/cmd/rpcdaemon/commands/corner_cases_support_test.go index 36c678cbcda5faa4621a3856489b15a441661b7a..858723e6d24fe1f66482937fd8494375ccf44802 100644 --- a/cmd/rpcdaemon/commands/corner_cases_support_test.go +++ b/cmd/rpcdaemon/commands/corner_cases_support_test.go @@ -4,6 +4,7 @@ import ( "context" "testing" + "github.com/ledgerwatch/erigon-lib/kv/kvcache" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/rpcdaemontest" "github.com/ledgerwatch/erigon/common" "github.com/ledgerwatch/erigon/rpc" @@ -16,7 +17,8 @@ func TestNotFoundMustReturnNil(t *testing.T) { require := require.New(t) db := rpcdaemontest.CreateTestKV(t) defer db.Close() - api := NewEthAPI(NewBaseApi(nil), db, nil, nil, nil, 5000000) + stateCache := kvcache.New(kvcache.DefaultCoherentConfig) + api := NewEthAPI(NewBaseApi(nil, stateCache), db, nil, nil, nil, 5000000) ctx := context.Background() a, err := api.GetTransactionByBlockNumberAndIndex(ctx, 10_000, 1) diff --git a/cmd/rpcdaemon/commands/daemon.go b/cmd/rpcdaemon/commands/daemon.go index d6dbe316bcb9616c6ccc680f1c0c804ef6c24f1e..6c84e68e6efae07e8796e8129cead07026529ae7 100644 --- a/cmd/rpcdaemon/commands/daemon.go +++ b/cmd/rpcdaemon/commands/daemon.go @@ -5,6 +5,7 @@ import ( "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon-lib/kv/kvcache" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/cli" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/filters" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/services" @@ -12,10 +13,12 @@ import ( ) // APIList describes the list of available RPC apis -func APIList(ctx context.Context, db kv.RoDB, eth services.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, filters *filters.Filters, cfg cli.Flags, customAPIList []rpc.API) []rpc.API { +func APIList(ctx context.Context, db kv.RoDB, + eth services.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, filters *filters.Filters, stateCache kvcache.Cache, + cfg cli.Flags, customAPIList []rpc.API) []rpc.API { var defaultAPIList []rpc.API - base := NewBaseApi(filters) + base := NewBaseApi(filters, stateCache) ethImpl := NewEthAPI(base, db, eth, txPool, mining, cfg.Gascap) erigonImpl := NewErigonAPI(base, db) txpoolImpl := NewTxPoolAPI(base, db, txPool) diff --git a/cmd/rpcdaemon/commands/debug_api_test.go b/cmd/rpcdaemon/commands/debug_api_test.go index e2c3e816a3d0eb228d009965f4692f999c7ec7d6..a8c31922ad438d4d29b3ebcb191a51fa3a9db277 100644 --- a/cmd/rpcdaemon/commands/debug_api_test.go +++ b/cmd/rpcdaemon/commands/debug_api_test.go @@ -7,6 +7,7 @@ import ( "testing" jsoniter "github.com/json-iterator/go" + "github.com/ledgerwatch/erigon-lib/kv/kvcache" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/rpcdaemontest" "github.com/ledgerwatch/erigon/common" "github.com/ledgerwatch/erigon/eth/tracers" @@ -37,7 +38,8 @@ var debugTraceTransactionNoRefundTests = []struct { func TestTraceTransaction(t *testing.T) { db := rpcdaemontest.CreateTestKV(t) - api := NewPrivateDebugAPI(NewBaseApi(nil), db, 0) + stateCache := kvcache.New(kvcache.DefaultCoherentConfig) + api := NewPrivateDebugAPI(NewBaseApi(nil, stateCache), db, 0) for _, tt := range debugTraceTransactionTests { var buf bytes.Buffer stream := jsoniter.NewStream(jsoniter.ConfigDefault, &buf, 4096) @@ -66,7 +68,8 @@ func TestTraceTransaction(t *testing.T) { func TestTraceTransactionNoRefund(t *testing.T) { db := rpcdaemontest.CreateTestKV(t) - api := NewPrivateDebugAPI(NewBaseApi(nil), db, 0) + stateCache := kvcache.New(kvcache.DefaultCoherentConfig) + api := NewPrivateDebugAPI(NewBaseApi(nil, stateCache), db, 0) for _, tt := range debugTraceTransactionNoRefundTests { var buf bytes.Buffer stream := jsoniter.NewStream(jsoniter.ConfigDefault, &buf, 4096) diff --git a/cmd/rpcdaemon/commands/eth_api.go b/cmd/rpcdaemon/commands/eth_api.go index 1cd4a0172fadaf7b40c3f3aab9efaab7dcbe9d54..9e1797a7b34edb6409863fe120ef0ae7357a3b17 100644 --- a/cmd/rpcdaemon/commands/eth_api.go +++ b/cmd/rpcdaemon/commands/eth_api.go @@ -8,6 +8,7 @@ import ( "github.com/holiman/uint256" "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon-lib/kv/kvcache" "github.com/ledgerwatch/erigon/consensus/misc" "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" @@ -97,14 +98,15 @@ type EthAPI interface { } type BaseAPI struct { + stateCache kvcache.Cache filters *filters.Filters _chainConfig *params.ChainConfig _genesis *types.Block _genesisLock sync.RWMutex } -func NewBaseApi(f *filters.Filters) *BaseAPI { - return &BaseAPI{filters: f} +func NewBaseApi(f *filters.Filters, stateCache kvcache.Cache) *BaseAPI { + return &BaseAPI{filters: f, stateCache: stateCache} } func (api *BaseAPI) chainConfig(tx kv.Tx) (*params.ChainConfig, error) { diff --git a/cmd/rpcdaemon/commands/eth_api_test.go b/cmd/rpcdaemon/commands/eth_api_test.go index 52ec7c9a17e411f25478c98d033483ccc52a01b8..ff1d0479d345a4896bb05fc2d39d49c5ca84b13d 100644 --- a/cmd/rpcdaemon/commands/eth_api_test.go +++ b/cmd/rpcdaemon/commands/eth_api_test.go @@ -9,13 +9,15 @@ import ( "github.com/stretchr/testify/assert" "testing" + "github.com/ledgerwatch/erigon-lib/kv/kvcache" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/rpcdaemontest" "github.com/ledgerwatch/erigon/common" ) func TestGetTransactionReceipt(t *testing.T) { db := rpcdaemontest.CreateTestKV(t) - api := NewEthAPI(NewBaseApi(nil), db, nil, nil, nil, 5000000) + stateCache := kvcache.New(kvcache.DefaultCoherentConfig) + api := NewEthAPI(NewBaseApi(nil, stateCache), db, nil, nil, nil, 5000000) // Call GetTransactionReceipt for transaction which is not in the database if _, err := api.GetTransactionReceipt(context.Background(), common.Hash{}); err != nil { t.Errorf("calling GetTransactionReceipt with empty hash: %v", err) @@ -24,7 +26,8 @@ func TestGetTransactionReceipt(t *testing.T) { func TestGetTransactionReceiptUnprotected(t *testing.T) { db := rpcdaemontest.CreateTestKV(t) - api := NewEthAPI(NewBaseApi(nil), db, nil, nil, nil, 5000000) + stateCache := kvcache.New(kvcache.DefaultCoherentConfig) + api := NewEthAPI(NewBaseApi(nil, stateCache), db, nil, nil, nil, 5000000) // Call GetTransactionReceipt for un-protected transaction if _, err := api.GetTransactionReceipt(context.Background(), common.HexToHash("0x3f3cb8a0e13ed2481f97f53f7095b9cbc78b6ffb779f2d3e565146371a8830ea")); err != nil { t.Errorf("calling GetTransactionReceipt for unprotected tx: %v", err) diff --git a/cmd/rpcdaemon/commands/eth_block.go b/cmd/rpcdaemon/commands/eth_block.go index c2f3710f0b3534db07584a9d33c03bee17be7b92..6817b31c56ba30df62b1d51bf470d93f7812074f 100644 --- a/cmd/rpcdaemon/commands/eth_block.go +++ b/cmd/rpcdaemon/commands/eth_block.go @@ -60,7 +60,11 @@ func (api *APIImpl) CallBundle(ctx context.Context, txHashes []common.Hash, stat var stateReader state.StateReader if num, ok := stateBlockNumberOrHash.Number(); ok && num == rpc.LatestBlockNumber { - stateReader = state.NewPlainStateReader(tx) + cacheView, err := api.stateCache.View(ctx, tx) + if err != nil { + return nil, err + } + stateReader = state.NewCachedReader2(cacheView, tx) } else { stateReader = state.NewPlainState(tx, stateBlockNumber) } diff --git a/cmd/rpcdaemon/commands/eth_call.go b/cmd/rpcdaemon/commands/eth_call.go index 32e7a66cf215f2fd1ada5a1c4ac5b93a8f259ac6..13ee8509e02a4e3b5dfbff03f34a978c4233b6bf 100644 --- a/cmd/rpcdaemon/commands/eth_call.go +++ b/cmd/rpcdaemon/commands/eth_call.go @@ -41,7 +41,7 @@ func (api *APIImpl) Call(ctx context.Context, args ethapi.CallArgs, blockNrOrHas contractHasTEVM := ethdb.GetHasTEVM(tx) - result, err := transactions.DoCall(ctx, args, tx, blockNrOrHash, overrides, api.GasCap, chainConfig, api.filters, contractHasTEVM) + result, err := transactions.DoCall(ctx, args, tx, blockNrOrHash, overrides, api.GasCap, chainConfig, api.filters, api.stateCache, contractHasTEVM) if err != nil { return nil, err } @@ -128,7 +128,11 @@ func (api *APIImpl) EstimateGas(ctx context.Context, args ethapi.CallArgs, block // Recap the highest gas limit with account's available balance. if args.GasPrice != nil && args.GasPrice.ToInt().Uint64() != 0 { - stateReader := state.NewPlainStateReader(dbtx) + cacheView, err := api.stateCache.View(ctx, dbtx) + if err != nil { + return 0, err + } + stateReader := state.NewCachedReader2(cacheView, dbtx) state := state.New(stateReader) if state == nil { return 0, fmt.Errorf("can't get the current state") @@ -172,7 +176,8 @@ func (api *APIImpl) EstimateGas(ctx context.Context, args ethapi.CallArgs, block executable := func(gas uint64) (bool, *core.ExecutionResult, error) { args.Gas = (*hexutil.Uint64)(&gas) - result, err := transactions.DoCall(ctx, args, dbtx, rpc.BlockNumberOrHash{BlockNumber: &lastBlockNum}, nil, api.GasCap, chainConfig, api.filters, contractHasTEVM) + result, err := transactions.DoCall(ctx, args, dbtx, rpc.BlockNumberOrHash{BlockNumber: &lastBlockNum}, nil, + api.GasCap, chainConfig, api.filters, api.stateCache, contractHasTEVM) if err != nil { if errors.Is(err, core.ErrIntrinsicGas) { // Special case, raise gas limit diff --git a/cmd/rpcdaemon/commands/eth_call_test.go b/cmd/rpcdaemon/commands/eth_call_test.go index d276172f0acf03496d5c130ff0f54ea321546450..653a767550e8090181a33428e2f25fba581f829d 100644 --- a/cmd/rpcdaemon/commands/eth_call_test.go +++ b/cmd/rpcdaemon/commands/eth_call_test.go @@ -5,6 +5,7 @@ import ( "fmt" "testing" + "github.com/ledgerwatch/erigon-lib/kv/kvcache" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/rpcdaemontest" "github.com/ledgerwatch/erigon/common" "github.com/ledgerwatch/erigon/internal/ethapi" @@ -13,7 +14,8 @@ import ( func TestEstimateGas(t *testing.T) { db := rpcdaemontest.CreateTestKV(t) - api := NewEthAPI(NewBaseApi(nil), db, nil, nil, nil, 5000000) + stateCache := kvcache.New(kvcache.DefaultCoherentConfig) + api := NewEthAPI(NewBaseApi(nil, stateCache), db, nil, nil, nil, 5000000) var from = common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") var to = common.HexToAddress("0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e") if _, err := api.EstimateGas(context.Background(), ethapi.CallArgs{ @@ -26,7 +28,8 @@ func TestEstimateGas(t *testing.T) { func TestEthCallNonCanonical(t *testing.T) { db := rpcdaemontest.CreateTestKV(t) - api := NewEthAPI(NewBaseApi(nil), db, nil, nil, nil, 5000000) + stateCache := kvcache.New(kvcache.DefaultCoherentConfig) + api := NewEthAPI(NewBaseApi(nil, stateCache), db, nil, nil, nil, 5000000) var from = common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") var to = common.HexToAddress("0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e") if _, err := api.Call(context.Background(), ethapi.CallArgs{ diff --git a/cmd/rpcdaemon/commands/eth_ming_test.go b/cmd/rpcdaemon/commands/eth_ming_test.go index 4d8868491f2f4d82b1af0c881fa3ad000a0a80a4..b1bad5b716fbc535cbce8da2ee2a4eb253b48dfb 100644 --- a/cmd/rpcdaemon/commands/eth_ming_test.go +++ b/cmd/rpcdaemon/commands/eth_ming_test.go @@ -6,6 +6,7 @@ import ( "time" "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" + "github.com/ledgerwatch/erigon-lib/kv/kvcache" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/filters" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/rpcdaemontest" "github.com/ledgerwatch/erigon/core/types" @@ -18,7 +19,8 @@ func TestPendingBlock(t *testing.T) { ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, stages.Mock(t)) mining := txpool.NewMiningClient(conn) ff := filters.New(ctx, nil, nil, mining) - api := NewEthAPI(NewBaseApi(ff), nil, nil, nil, mining, 5000000) + stateCache := kvcache.New(kvcache.DefaultCoherentConfig) + api := NewEthAPI(NewBaseApi(ff, stateCache), nil, nil, nil, mining, 5000000) expect := uint64(12345) b, err := rlp.EncodeToBytes(types.NewBlockWithHeader(&types.Header{Number: big.NewInt(int64(expect))})) require.NoError(t, err) diff --git a/cmd/rpcdaemon/commands/send_transaction_test.go b/cmd/rpcdaemon/commands/send_transaction_test.go index c2eec7fc44f34f625fbe4c6525f243bc718a57b8..9634ca113fd1fb2dd38058c1e88cb36728d3f7b4 100644 --- a/cmd/rpcdaemon/commands/send_transaction_test.go +++ b/cmd/rpcdaemon/commands/send_transaction_test.go @@ -9,6 +9,7 @@ import ( "github.com/holiman/uint256" "github.com/ledgerwatch/erigon-lib/gointerfaces/sentry" "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" + "github.com/ledgerwatch/erigon-lib/kv/kvcache" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/commands" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/filters" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/rpcdaemontest" @@ -69,7 +70,8 @@ func TestSendRawTransaction(t *testing.T) { ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, m) txPool := txpool.NewTxpoolClient(conn) ff := filters.New(ctx, nil, txPool, txpool.NewMiningClient(conn)) - api := commands.NewEthAPI(commands.NewBaseApi(ff), m.DB, nil, txPool, nil, 5000000) + stateCache := kvcache.New(kvcache.DefaultCoherentConfig) + api := commands.NewEthAPI(commands.NewBaseApi(ff, stateCache), m.DB, nil, txPool, nil, 5000000) buf := bytes.NewBuffer(nil) err = txn.MarshalBinary(buf) diff --git a/cmd/rpcdaemon/commands/trace_adhoc.go b/cmd/rpcdaemon/commands/trace_adhoc.go index f60e6201c1d45ac6a59104d468c877a1c669080c..691dd69f694fd16615624569b9d8acfa4dda64fa 100644 --- a/cmd/rpcdaemon/commands/trace_adhoc.go +++ b/cmd/rpcdaemon/commands/trace_adhoc.go @@ -864,7 +864,11 @@ func (api *TraceAPIImpl) Call(ctx context.Context, args TraceCallParam, traceTyp } var stateReader state.StateReader if num, ok := blockNrOrHash.Number(); ok && num == rpc.LatestBlockNumber { - stateReader = state.NewPlainStateReader(tx) + cacheView, err := api.stateCache.View(ctx, tx) + if err != nil { + return nil, err + } + stateReader = state.NewCachedReader2(cacheView, tx) } else { stateReader = state.NewPlainState(tx, blockNumber) } @@ -1062,7 +1066,11 @@ func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx kv.Tx, msgs []type } var stateReader state.StateReader if num, ok := parentNrOrHash.Number(); ok && num == rpc.LatestBlockNumber { - stateReader = state.NewPlainStateReader(dbtx) + cacheView, err := api.stateCache.View(ctx, dbtx) + if err != nil { + return nil, err + } + stateReader = state.NewCachedReader2(cacheView, dbtx) } else { stateReader = state.NewPlainState(dbtx, blockNumber) } diff --git a/cmd/rpcdaemon/commands/trace_adhoc_test.go b/cmd/rpcdaemon/commands/trace_adhoc_test.go index a2f8df2008dd1dad48d5106a6ba756a3911afc5d..acc05a706ee6b64bab0f82594e0ab2d9f796f124 100644 --- a/cmd/rpcdaemon/commands/trace_adhoc_test.go +++ b/cmd/rpcdaemon/commands/trace_adhoc_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon-lib/kv/kvcache" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/cli" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/rpcdaemontest" "github.com/ledgerwatch/erigon/common" @@ -17,7 +18,8 @@ import ( func TestEmptyQuery(t *testing.T) { db := rpcdaemontest.CreateTestKV(t) - api := NewTraceAPI(NewBaseApi(nil), db, &cli.Flags{}) + stateCache := kvcache.New(kvcache.DefaultCoherentConfig) + api := NewTraceAPI(NewBaseApi(nil, stateCache), db, &cli.Flags{}) // Call GetTransactionReceipt for transaction which is not in the database var latest = rpc.LatestBlockNumber results, err := api.CallMany(context.Background(), json.RawMessage("[]"), &rpc.BlockNumberOrHash{BlockNumber: &latest}) @@ -33,7 +35,8 @@ func TestEmptyQuery(t *testing.T) { } func TestCoinbaseBalance(t *testing.T) { db := rpcdaemontest.CreateTestKV(t) - api := NewTraceAPI(NewBaseApi(nil), db, &cli.Flags{}) + stateCache := kvcache.New(kvcache.DefaultCoherentConfig) + api := NewTraceAPI(NewBaseApi(nil, stateCache), db, &cli.Flags{}) // Call GetTransactionReceipt for transaction which is not in the database var latest = rpc.LatestBlockNumber results, err := api.CallMany(context.Background(), json.RawMessage(` @@ -59,7 +62,8 @@ func TestCoinbaseBalance(t *testing.T) { func TestReplayTransaction(t *testing.T) { db := rpcdaemontest.CreateTestKV(t) - api := NewTraceAPI(NewBaseApi(nil), db, &cli.Flags{}) + stateCache := kvcache.New(kvcache.DefaultCoherentConfig) + api := NewTraceAPI(NewBaseApi(nil, stateCache), db, &cli.Flags{}) var txnHash common.Hash if err := db.View(context.Background(), func(tx kv.Tx) error { b, err := rawdb.ReadBlockByNumber(tx, 6) @@ -86,7 +90,8 @@ func TestReplayTransaction(t *testing.T) { func TestReplayBlockTransactions(t *testing.T) { db := rpcdaemontest.CreateTestKV(t) - api := NewTraceAPI(NewBaseApi(nil), db, &cli.Flags{}) + stateCache := kvcache.New(kvcache.DefaultCoherentConfig) + api := NewTraceAPI(NewBaseApi(nil, stateCache), db, &cli.Flags{}) // Call GetTransactionReceipt for transaction which is not in the database n := rpc.BlockNumber(6) diff --git a/cmd/rpcdaemon/commands/tracing.go b/cmd/rpcdaemon/commands/tracing.go index d9dce5a2c3ea62e70d3a8b02ee6abc22c3046be6..9b1f4ac1cda3bfa40c9c8a30d0730c4f79a4ca00 100644 --- a/cmd/rpcdaemon/commands/tracing.go +++ b/cmd/rpcdaemon/commands/tracing.go @@ -85,7 +85,11 @@ func (api *PrivateDebugAPIImpl) TraceCall(ctx context.Context, args ethapi.CallA } var stateReader state.StateReader if num, ok := blockNrOrHash.Number(); ok && num == rpc.LatestBlockNumber { - stateReader = state.NewPlainStateReader(dbtx) + cacheView, err := api.stateCache.View(ctx, dbtx) + if err != nil { + return err + } + stateReader = state.NewCachedReader2(cacheView, dbtx) } else { stateReader = state.NewPlainState(dbtx, blockNumber) } diff --git a/cmd/rpcdaemon/commands/txpool_api_test.go b/cmd/rpcdaemon/commands/txpool_api_test.go index 4162bb548359519c77ec1906d0357def1f3cf649..6ef762550aab6dc02d002dd9f38e61fb04c8fee5 100644 --- a/cmd/rpcdaemon/commands/txpool_api_test.go +++ b/cmd/rpcdaemon/commands/txpool_api_test.go @@ -8,6 +8,7 @@ import ( "github.com/holiman/uint256" "github.com/ledgerwatch/erigon-lib/gointerfaces/sentry" "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" + "github.com/ledgerwatch/erigon-lib/kv/kvcache" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/filters" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/rpcdaemontest" "github.com/ledgerwatch/erigon/common" @@ -62,7 +63,7 @@ func TestTxPoolContent(t *testing.T) { ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, m) txPool := txpool.NewTxpoolClient(conn) ff := filters.New(ctx, nil, txPool, txpool.NewMiningClient(conn)) - api := NewTxPoolAPI(NewBaseApi(ff), m.DB, txPool) + api := NewTxPoolAPI(NewBaseApi(ff, kvcache.New(kvcache.DefaultCoherentConfig)), m.DB, txPool) expectValue := uint64(1234) txn, err := types.SignTx(types.NewTransaction(0, common.Address{1}, uint256.NewInt(expectValue), params.TxGas, u256.Num1, nil), *types.LatestSignerForChainID(m.ChainConfig.ChainID), m.Key) diff --git a/cmd/rpcdaemon/main.go b/cmd/rpcdaemon/main.go index 9e71247a2c826de65c1b0b0bdc8a3e88f53516cb..a9b525d95fbfa7956dd935024411385f3e8e5d5f 100644 --- a/cmd/rpcdaemon/main.go +++ b/cmd/rpcdaemon/main.go @@ -16,7 +16,7 @@ func main() { rootCtx, rootCancel := utils.RootContext() cmd.RunE = func(cmd *cobra.Command, args []string) error { logger := log.New() - db, backend, txPool, mining, err := cli.RemoteServices(cmd.Context(), *cfg, logger, rootCancel) + db, backend, txPool, mining, stateCache, err := cli.RemoteServices(cmd.Context(), *cfg, logger, rootCancel) if err != nil { log.Error("Could not connect to DB", "error", err) return nil @@ -30,7 +30,7 @@ func main() { log.Info("filters are not supported in chaindata mode") } - if err := cli.StartRpcServer(cmd.Context(), *cfg, commands.APIList(cmd.Context(), db, backend, txPool, mining, ff, *cfg, nil)); err != nil { + if err := cli.StartRpcServer(cmd.Context(), *cfg, commands.APIList(cmd.Context(), db, backend, txPool, mining, ff, stateCache, *cfg, nil)); err != nil { log.Error(err.Error()) return nil } diff --git a/cmd/txpool/main.go b/cmd/txpool/main.go index d7b4ee11931053debcc9ee36db137aa6fc748028..3dc5fb8adf55475d9f3cd6cadcf11ad3e2a7397a 100644 --- a/cmd/txpool/main.go +++ b/cmd/txpool/main.go @@ -98,7 +98,7 @@ var rootCmd = &cobra.Command{ cfg.LogEvery = 30 * time.Second cfg.CommitEvery = 30 * time.Second - cacheConfig := kvcache.DefaultCoherentCacheConfig + cacheConfig := kvcache.DefaultCoherentConfig cacheConfig.MetricsLabel = "txpool" newTxs := make(chan txpool.Hashes, 1024) @@ -113,7 +113,7 @@ var rootCmd = &cobra.Command{ /* var ethashApi *ethash.API - if casted, ok := backend.engine.(*ethash.Ethash); ok { + sif casted, ok := backend.engine.(*ethash.Ethash); ok { ethashApi = casted.APIs(nil)[1].Service.(*ethash.API) } */ diff --git a/core/state/cached_reader2.go b/core/state/cached_reader2.go index f8a05164722a98ca2441a7a0c0e03d8541ecfad7..1f841330c1964ffcdb1923912112f21d9b3a1d64 100644 --- a/core/state/cached_reader2.go +++ b/core/state/cached_reader2.go @@ -14,19 +14,18 @@ import ( // CachedReader2 is a wrapper for an instance of type StateReader // This wrapper only makes calls to the underlying reader if the item is not in the cache type CachedReader2 struct { - r StateReader cache kvcache.CacheView db kv.Tx } // NewCachedReader2 wraps a given state reader into the cached reader -func NewCachedReader2(r StateReader, cache kvcache.CacheView, tx kv.Tx) *CachedReader2 { - return &CachedReader2{r: r, cache: cache, db: tx} +func NewCachedReader2(cache kvcache.CacheView, tx kv.Tx) *CachedReader2 { + return &CachedReader2{cache: cache, db: tx} } // ReadAccountData is called when an account needs to be fetched from the state -func (cr *CachedReader2) ReadAccountData(address common.Address) (*accounts.Account, error) { - enc, err := cr.cache.Get(address.Bytes()) +func (r *CachedReader2) ReadAccountData(address common.Address) (*accounts.Account, error) { + enc, err := r.cache.Get(address.Bytes()) if err != nil { return nil, err } diff --git a/core/state/plain_readonly.go b/core/state/plain_readonly.go index cea636df2dece0ef8fe7a2b629aace12f11fc2d0..186aa25709c8056967bc1b0a54f0ba548e163f8c 100644 --- a/core/state/plain_readonly.go +++ b/core/state/plain_readonly.go @@ -48,7 +48,6 @@ type PlainState struct { } func NewPlainState(tx kv.Tx, blockNr uint64) *PlainState { - c1, _ := tx.Cursor(kv.AccountsHistory) c2, _ := tx.Cursor(kv.StorageHistory) c3, _ := tx.CursorDupSort(kv.AccountChangeSet) diff --git a/docker-compose.yml b/docker-compose.yml index 207d52419fa25240eab5c78efaa926fd087010f0..e224d238a7d73be45dbee93e3ff8a6695f85c735 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -27,7 +27,7 @@ services: restart: unless-stopped grafana: - image: grafana/grafana:8.1.2 + image: grafana/grafana:8.1.5 user: 1000:1000 # Uses erigon user from Dockerfile ports: - "3000:3000" diff --git a/go.mod b/go.mod index 14917e744b69c1db1af9b66909082927e173fee3..f39636271ab3f5e8b6d3bd7b66ad3695193df215 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require ( github.com/json-iterator/go v1.1.11 github.com/julienschmidt/httprouter v1.3.0 github.com/kevinburke/go-bindata v3.21.0+incompatible - github.com/ledgerwatch/erigon-lib v0.0.0-20210927124510-ffac34a86fd0 + github.com/ledgerwatch/erigon-lib v0.0.0-20210928085402-33aa4498f0fc github.com/ledgerwatch/log/v3 v3.3.1 github.com/ledgerwatch/secp256k1 v0.0.0-20210626115225-cd5cd00ed72d github.com/logrusorgru/aurora/v3 v3.0.0 diff --git a/go.sum b/go.sum index 030a57a942b2ec184e21184858b8db9dfde7b2dc..c76277ef4fb8a4d64a7873e89683c6b7ec16da2c 100644 --- a/go.sum +++ b/go.sum @@ -498,8 +498,8 @@ github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758 h1:0D5M2HQSGD3P github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/ledgerwatch/erigon-lib v0.0.0-20210927124510-ffac34a86fd0 h1:hthm2WSAmlY//ImGjQjD2AdxKJObDFkQbFoKVmf4Ev0= -github.com/ledgerwatch/erigon-lib v0.0.0-20210927124510-ffac34a86fd0/go.mod h1:WgyjBACSDhgfepaaDJIbzd2TV868EjOrp2ILnEMKspY= +github.com/ledgerwatch/erigon-lib v0.0.0-20210928085402-33aa4498f0fc h1:8yRRYOthoMgZsncLCnQXRMQy6mWz9Xl3/iSjqRYrXOQ= +github.com/ledgerwatch/erigon-lib v0.0.0-20210928085402-33aa4498f0fc/go.mod h1:WgyjBACSDhgfepaaDJIbzd2TV868EjOrp2ILnEMKspY= github.com/ledgerwatch/log/v3 v3.3.1 h1:HmvLeTEvtCtqSvtu4t/a5MAdcLfeBcbIeowXbLYuzLc= github.com/ledgerwatch/log/v3 v3.3.1/go.mod h1:S3VJqhhVX32rbp1JyyvhJou12twtFwNEPESBgpbNkRk= github.com/ledgerwatch/secp256k1 v0.0.0-20210626115225-cd5cd00ed72d h1:/IKMrJdfRsoYNc36PXqP4xMH3vhW/8IQyBKGQbKZUno= diff --git a/rpc/handler.go b/rpc/handler.go index 6bc776462a8d4750cfc0218f0941e7279f893c3d..39784cb60b025afe3ef464234883a0c5bb944ffa 100644 --- a/rpc/handler.go +++ b/rpc/handler.go @@ -402,7 +402,7 @@ func (h *handler) handleCall(cp *callProc, msg *jsonrpcMessage, stream *jsoniter if answer != nil && answer.Error != nil { failedReqeustGauge.Inc() } - newRPCServingTimerMS(msg.Method, answer == nil || answer.Error == nil).Update(float64(time.Since(start).Milliseconds())) + newRPCServingTimerMS(msg.Method, answer == nil || answer.Error == nil).UpdateDuration(start) } return answer } diff --git a/turbo/transactions/call.go b/turbo/transactions/call.go index a249bc5fc721665735fc229fc365b53af0bfa65b..fabbcf5ecf4f5ecc009fd7f50066ecfce14fefa7 100644 --- a/turbo/transactions/call.go +++ b/turbo/transactions/call.go @@ -8,6 +8,7 @@ import ( "github.com/holiman/uint256" "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon-lib/kv/kvcache" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/filters" "github.com/ledgerwatch/erigon/common" "github.com/ledgerwatch/erigon/core" @@ -24,7 +25,9 @@ import ( const callTimeout = 5 * time.Minute -func DoCall(ctx context.Context, args ethapi.CallArgs, tx kv.Tx, blockNrOrHash rpc.BlockNumberOrHash, overrides *map[common.Address]ethapi.Account, gasCap uint64, chainConfig *params.ChainConfig, filters *filters.Filters, contractHasTEVM func(hash common.Hash) (bool, error)) (*core.ExecutionResult, error) { +func DoCall(ctx context.Context, args ethapi.CallArgs, tx kv.Tx, blockNrOrHash rpc.BlockNumberOrHash, + overrides *map[common.Address]ethapi.Account, gasCap uint64, chainConfig *params.ChainConfig, + filters *filters.Filters, stateCache kvcache.Cache, contractHasTEVM func(hash common.Hash) (bool, error)) (*core.ExecutionResult, error) { // todo: Pending state is only known by the miner /* if blockNrOrHash.BlockNumber != nil && *blockNrOrHash.BlockNumber == rpc.PendingBlockNumber { @@ -38,7 +41,11 @@ func DoCall(ctx context.Context, args ethapi.CallArgs, tx kv.Tx, blockNrOrHash r } var stateReader state.StateReader if num, ok := blockNrOrHash.Number(); ok && num == rpc.LatestBlockNumber { - stateReader = state.NewPlainStateReader(tx) + cacheView, err := stateCache.View(ctx, tx) + if err != nil { + return nil, err + } + stateReader = state.NewCachedReader2(cacheView, tx) } else { stateReader = state.NewPlainState(tx, blockNumber) }