Embed rpcdaemon: prepared direct clients (#3492)

This commit is contained in:
Alex Sharov 2022-02-12 19:47:19 +07:00 committed by GitHub
parent aca755ab43
commit 479c7f3d9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 100 additions and 73 deletions

View File

@ -10,12 +10,10 @@ import (
"github.com/ledgerwatch/erigon-lib/gointerfaces"
proto_downloader "github.com/ledgerwatch/erigon-lib/gointerfaces/downloader"
prototypes "github.com/ledgerwatch/erigon-lib/gointerfaces/types"
"github.com/ledgerwatch/erigon/cmd/downloader/downloader"
"github.com/ledgerwatch/erigon/common"
"google.golang.org/grpc"
"google.golang.org/grpc/backoff"
"google.golang.org/grpc/keepalive"
"google.golang.org/protobuf/types/known/emptypb"
)
func NewClient(ctx context.Context, downloaderAddr string) (proto_downloader.DownloaderClient, error) {
@ -64,18 +62,3 @@ func String2Proto(in string) *prototypes.H160 {
copy(infoHash[:], common.FromHex(in))
return gointerfaces.ConvertAddressToH160(infoHash)
}
type ClientDirect struct {
server *downloader.GrpcServer
}
func NewClientDirect(server *downloader.GrpcServer) *ClientDirect {
return &ClientDirect{server: server}
}
func (c *ClientDirect) Download(ctx context.Context, in *proto_downloader.DownloadRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
return c.server.Download(ctx, in)
}
func (c *ClientDirect) Stats(ctx context.Context, in *proto_downloader.StatsRequest, opts ...grpc.CallOption) (*proto_downloader.StatsReply, error) {
return c.server.Stats(ctx, in)
}

View File

@ -12,6 +12,7 @@ import (
"strings"
"time"
"github.com/ledgerwatch/erigon-lib/direct"
"github.com/ledgerwatch/erigon-lib/gointerfaces"
"github.com/ledgerwatch/erigon-lib/gointerfaces/grpcutil"
"github.com/ledgerwatch/erigon-lib/gointerfaces/remote"
@ -21,6 +22,7 @@ import (
kv2 "github.com/ledgerwatch/erigon-lib/kv/mdbx"
"github.com/ledgerwatch/erigon-lib/kv/remotedb"
"github.com/ledgerwatch/erigon-lib/kv/remotedbserver"
"github.com/ledgerwatch/erigon/cmd/rpcdaemon/filters"
"github.com/ledgerwatch/erigon/cmd/rpcdaemon/health"
"github.com/ledgerwatch/erigon/cmd/rpcdaemon/interfaces"
"github.com/ledgerwatch/erigon/cmd/rpcdaemon/services"
@ -238,11 +240,36 @@ func checkDbCompatibility(ctx context.Context, db kv.RoDB) error {
return nil
}
func EmbeddedServices(ctx context.Context, erigonDB kv.RoDB, stateCacheCfg kvcache.CoherentConfig, blockReader interfaces.BlockAndTxnReader, ethBackendServer remote.ETHBACKENDServer,
txPoolServer txpool.TxpoolServer, miningServer txpool.MiningServer) (eth services.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, starknet *services.StarknetService, stateCache kvcache.Cache, ff *filters.Filters, err error) {
if stateCacheCfg.KeysLimit > 0 {
stateCache = kvcache.New(stateCacheCfg)
} else {
stateCache = kvcache.NewDummy()
}
kvRPC := remotedbserver.NewKvServer(ctx, erigonDB)
stateDiffClient := direct.NewStateDiffClientDirect(kvRPC)
subscribeToStateChangesLoop(ctx, stateDiffClient, stateCache)
directClient := direct.NewEthBackendClientDirect(ethBackendServer)
eth = services.NewRemoteBackend(directClient, erigonDB, blockReader)
txPool = direct.NewTxPoolClient(txPoolServer)
mining = direct.NewMiningClient(miningServer)
ff = filters.New(ctx, eth, txPool, mining)
return
}
// RemoteServices - use when RPCDaemon run as independent process. Still it can use --datadir flag to enable
// `cfg.SingleNodeMode` (mode when it on 1 machine with Erigon)
func RemoteServices(ctx context.Context, cfg Flags, logger log.Logger, rootCancel context.CancelFunc) (db kv.RoDB, borDb kv.RoDB, eth services.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, starknet *services.StarknetService, stateCache kvcache.Cache, blockReader interfaces.BlockAndTxnReader, err error) {
func RemoteServices(ctx context.Context, cfg Flags, logger log.Logger, rootCancel context.CancelFunc) (
db kv.RoDB, borDb kv.RoDB,
eth services.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient,
starknet *services.StarknetService,
stateCache kvcache.Cache, blockReader interfaces.BlockAndTxnReader,
ff *filters.Filters, err error) {
if !cfg.SingleNodeMode && cfg.PrivateApiAddr == "" {
return nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("either remote db or local db must be specified")
return nil, nil, nil, nil, nil, nil, nil, nil, ff, 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 ""
@ -252,10 +279,10 @@ func RemoteServices(ctx context.Context, cfg Flags, logger log.Logger, rootCance
log.Trace("Creating chain db", "path", cfg.Chaindata)
rwKv, err = kv2.NewMDBX(logger).Path(cfg.Chaindata).Readonly().Open()
if err != nil {
return nil, nil, nil, nil, nil, nil, nil, nil, err
return nil, nil, nil, nil, nil, nil, nil, nil, ff, err
}
if compatErr := checkDbCompatibility(ctx, rwKv); compatErr != nil {
return nil, nil, nil, nil, nil, nil, nil, nil, compatErr
return nil, nil, nil, nil, nil, nil, nil, nil, ff, compatErr
}
db = rwKv
stateCache = kvcache.NewDummy()
@ -268,14 +295,14 @@ func RemoteServices(ctx context.Context, cfg Flags, logger log.Logger, rootCance
// ensure db exist
tmpDb, err := kv2.NewMDBX(logger).Path(borDbPath).Label(kv.ConsensusDB).Open()
if err != nil {
return nil, nil, nil, nil, nil, nil, nil, nil, err
return nil, nil, nil, nil, nil, nil, nil, nil, ff, err
}
tmpDb.Close()
}
log.Trace("Creating consensus db", "path", borDbPath)
borKv, err = kv2.NewMDBX(logger).Path(borDbPath).Label(kv.ConsensusDB).Readonly().Open()
if err != nil {
return nil, nil, nil, nil, nil, nil, nil, nil, err
return nil, nil, nil, nil, nil, nil, nil, nil, ff, err
}
// Skip the compatibility check, until we have a schema in erigon-lib
borDb = borKv
@ -302,10 +329,10 @@ func RemoteServices(ctx context.Context, cfg Flags, logger log.Logger, rootCance
}
return nil
}); err != nil {
return nil, nil, nil, nil, nil, nil, nil, nil, err
return nil, nil, nil, nil, nil, nil, nil, nil, ff, err
}
if cc == nil {
return nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("chain config not found in db. Need start erigon at least once on this db")
return nil, nil, nil, nil, nil, nil, nil, nil, ff, fmt.Errorf("chain config not found in db. Need start erigon at least once on this db")
}
allSnapshots := snapshotsync.NewAllSnapshots(cfg.Snapshot, path.Join(cfg.Datadir, "snapshots"))
@ -315,23 +342,20 @@ func RemoteServices(ctx context.Context, cfg Flags, logger log.Logger, rootCance
blockReader = snapshotsync.NewBlockReader()
}
}
if cfg.PrivateApiAddr == "" {
return db, borDb, eth, txPool, mining, starknet, stateCache, blockReader, nil
}
creds, err := grpcutil.TLS(cfg.TLSCACert, cfg.TLSCertfile, cfg.TLSKeyFile)
if err != nil {
return nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("open tls cert: %w", err)
return nil, nil, nil, nil, nil, nil, nil, nil, ff, fmt.Errorf("open tls cert: %w", err)
}
conn, err := grpcutil.Connect(creds, cfg.PrivateApiAddr)
if err != nil {
return nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("could not connect to execution service privateApi: %w", err)
return nil, nil, nil, nil, nil, nil, nil, nil, ff, 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, nil, nil, nil, fmt.Errorf("could not connect to remoteKv: %w", err)
return nil, nil, nil, nil, nil, nil, nil, nil, ff, fmt.Errorf("could not connect to remoteKv: %w", err)
}
subscribeToStateChangesLoop(ctx, kvClient, stateCache)
@ -346,7 +370,7 @@ func RemoteServices(ctx context.Context, cfg Flags, logger log.Logger, rootCance
if cfg.TxPoolApiAddr != cfg.PrivateApiAddr {
txpoolConn, err = grpcutil.Connect(creds, cfg.TxPoolApiAddr)
if err != nil {
return nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("could not connect to txpool api: %w", err)
return nil, nil, nil, nil, nil, nil, nil, nil, ff, fmt.Errorf("could not connect to txpool api: %w", err)
}
}
@ -376,12 +400,14 @@ func RemoteServices(ctx context.Context, cfg Flags, logger log.Logger, rootCance
if cfg.StarknetGRPCAddress != "" {
starknetConn, err := grpcutil.Connect(creds, cfg.StarknetGRPCAddress)
if err != nil {
return nil, nil, nil, nil, nil, nil, nil, nil, fmt.Errorf("could not connect to starknet api: %w", err)
return nil, nil, nil, nil, nil, nil, nil, nil, ff, fmt.Errorf("could not connect to starknet api: %w", err)
}
starknet = services.NewStarknetService(starknetConn)
}
return db, borDb, eth, txPool, mining, starknet, stateCache, blockReader, err
ff = filters.New(ctx, eth, txPool, mining)
return db, borDb, eth, txPool, mining, starknet, stateCache, blockReader, ff, err
}
func StartRpcServer(ctx context.Context, cfg Flags, rpcAPI []rpc.API) error {

View File

@ -1,8 +1,6 @@
package commands
import (
"context"
"github.com/ledgerwatch/erigon-lib/gointerfaces/starknet"
"github.com/ledgerwatch/erigon-lib/gointerfaces/txpool"
"github.com/ledgerwatch/erigon-lib/kv"
@ -15,11 +13,10 @@ import (
)
// APIList describes the list of available RPC apis
func APIList(ctx context.Context, db kv.RoDB, borDb kv.RoDB,
eth services.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient,
starknet starknet.CAIROVMClient, filters *filters.Filters,
stateCache kvcache.Cache,
blockReader interfaces.BlockAndTxnReader,
func APIList(db kv.RoDB, borDb kv.RoDB, eth services.ApiBackend,
txPool txpool.TxpoolClient, mining txpool.MiningClient,
starknet starknet.CAIROVMClient,
filters *filters.Filters, stateCache kvcache.Cache, blockReader interfaces.BlockAndTxnReader,
cfg cli.Flags, customAPIList []rpc.API) []rpc.API {
var defaultAPIList []rpc.API

View File

@ -13,7 +13,6 @@ import (
"github.com/ledgerwatch/erigon/core/rawdb"
"github.com/ledgerwatch/erigon/core/state"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/eth"
"github.com/ledgerwatch/erigon/eth/stagedsync/stages"
"github.com/ledgerwatch/erigon/eth/tracers"
"github.com/ledgerwatch/erigon/ethdb"
@ -22,6 +21,9 @@ import (
"github.com/ledgerwatch/erigon/turbo/transactions"
)
// AccountRangeMaxResults is the maximum number of results to be returned per call
const AccountRangeMaxResults = 256
// PrivateDebugAPI Exposed RPC endpoints for debugging use
type PrivateDebugAPI interface {
StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex uint64, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error)
@ -121,8 +123,8 @@ func (api *PrivateDebugAPIImpl) AccountRange(ctx context.Context, blockNrOrHash
blockNumber = block.NumberU64()
}
if maxResults > eth.AccountRangeMaxResults || maxResults <= 0 {
maxResults = eth.AccountRangeMaxResults
if maxResults > AccountRangeMaxResults || maxResults <= 0 {
maxResults = AccountRangeMaxResults
}
dumper := state.NewDumper(tx, blockNumber)

View File

@ -6,7 +6,6 @@ import (
"github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon/cmd/rpcdaemon/cli"
"github.com/ledgerwatch/erigon/cmd/rpcdaemon/commands"
"github.com/ledgerwatch/erigon/cmd/rpcdaemon/filters"
"github.com/ledgerwatch/log/v3"
"github.com/spf13/cobra"
)
@ -15,22 +14,18 @@ func main() {
cmd, cfg := cli.RootCommand()
rootCtx, rootCancel := common.RootContext()
cmd.RunE = func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
logger := log.New()
db, borDb, backend, txPool, mining, starknet, stateCache, blockReader, err := cli.RemoteServices(cmd.Context(), *cfg, logger, rootCancel)
db, borDb, backend, txPool, mining, starknet, stateCache, blockReader, ff, err := cli.RemoteServices(ctx, *cfg, logger, rootCancel)
if err != nil {
log.Error("Could not connect to DB", "error", err)
return nil
}
defer db.Close()
defer borDb.Close()
var ff *filters.Filters
if backend != nil {
ff = filters.New(rootCtx, backend, txPool, mining)
} else {
log.Info("filters are not supported in chaindata mode")
}
if err := cli.StartRpcServer(cmd.Context(), *cfg, commands.APIList(cmd.Context(), db, borDb, backend, txPool, mining, starknet, ff, stateCache, blockReader, *cfg, nil)); err != nil {
apiList := commands.APIList(db, borDb, backend, txPool, mining, starknet, ff, stateCache, blockReader, *cfg, nil)
if err := cli.StartRpcServer(ctx, *cfg, apiList); err != nil {
log.Error(err.Error())
return nil
}

View File

@ -206,7 +206,7 @@ func BorRLP(header *types.Header, c *params.BorConfig) []byte {
type Bor struct {
chainConfig *params.ChainConfig // Chain config
config *params.BorConfig // Consensus engine configuration parameters for bor consensus
db kv.RwDB // Database to store and retrieve snapshot checkpoints
DB kv.RwDB // Database to store and retrieve snapshot checkpoints
recents *lru.ARCCache // Snapshots for recent block to speed up reorgs
signatures *lru.ARCCache // Signatures of recent blocks to speed up mining
@ -253,7 +253,7 @@ func New(
c := &Bor{
chainConfig: chainConfig,
config: borConfig,
db: db,
DB: db,
recents: recents,
signatures: signatures,
validatorSetABI: vABI,
@ -442,7 +442,7 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
// If an on-disk checkpoint snapshot can be found, use that
if number%checkpointInterval == 0 {
if s, err := loadSnapshot(c.config, c.signatures, c.db, hash); err == nil {
if s, err := loadSnapshot(c.config, c.signatures, c.DB, hash); err == nil {
log.Trace("Loaded snapshot from disk", "number", number, "hash", hash)
snap = s
break
@ -468,7 +468,7 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
// new snap shot
snap = newSnapshot(c.config, c.signatures, number, hash, validators)
if err := snap.store(c.db); err != nil {
if err := snap.store(c.DB); err != nil {
return nil, err
}
log.Info("Stored checkpoint snapshot to disk", "number", number, "hash", hash)
@ -514,7 +514,7 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
// If we've generated a new checkpoint snapshot, save to disk
if snap.Number%checkpointInterval == 0 && len(headers) > 0 {
if err = snap.store(c.db); err != nil {
if err = snap.store(c.DB); err != nil {
return nil, err
}
log.Trace("Stored snapshot to disk", "number", snap.Number, "hash", snap.Hash)
@ -908,6 +908,7 @@ func (c *Bor) APIs(chain consensus.ChainHeaderReader) []rpc.API {
// Close implements consensus.Engine. It's a noop for bor as there are no background threads.
func (c *Bor) Close() error {
c.DB.Close()
return nil
}

View File

@ -15,6 +15,3 @@
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package eth
// AccountRangeMaxResults is the maximum number of results to be returned per call
const AccountRangeMaxResults = 256

View File

@ -47,21 +47,18 @@ import (
txpool2 "github.com/ledgerwatch/erigon-lib/txpool"
"github.com/ledgerwatch/erigon-lib/txpool/txpooluitl"
"github.com/ledgerwatch/erigon/cmd/downloader/downloader"
"github.com/ledgerwatch/erigon/turbo/snapshotsync/snapshotsynccli"
"github.com/ledgerwatch/log/v3"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"github.com/ledgerwatch/erigon/consensus/parlia"
"github.com/ledgerwatch/erigon/cmd/downloader/downloadergrpc"
"github.com/ledgerwatch/erigon/cmd/rpcdaemon/cli"
"github.com/ledgerwatch/erigon/cmd/rpcdaemon/commands"
"github.com/ledgerwatch/erigon/cmd/rpcdaemon/interfaces"
"github.com/ledgerwatch/erigon/cmd/sentry/sentry"
"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/common/debug"
"github.com/ledgerwatch/erigon/consensus"
"github.com/ledgerwatch/erigon/consensus/bor"
"github.com/ledgerwatch/erigon/consensus/clique"
"github.com/ledgerwatch/erigon/consensus/ethash"
"github.com/ledgerwatch/erigon/consensus/parlia"
"github.com/ledgerwatch/erigon/core"
"github.com/ledgerwatch/erigon/core/rawdb"
"github.com/ledgerwatch/erigon/core/types"
@ -81,7 +78,11 @@ import (
"github.com/ledgerwatch/erigon/turbo/shards"
"github.com/ledgerwatch/erigon/turbo/snapshotsync"
"github.com/ledgerwatch/erigon/turbo/snapshotsync/snapshothashes"
"github.com/ledgerwatch/erigon/turbo/snapshotsync/snapshotsynccli"
stages2 "github.com/ledgerwatch/erigon/turbo/stages"
"github.com/ledgerwatch/log/v3"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
// Config contains the configuration options of the ETH protocol.
@ -331,7 +332,7 @@ func New(stack *node.Node, config *ethconfig.Config, txpoolCfg txpool2.Config, l
return nil, fmt.Errorf("new server: %w", err)
}
backend.downloaderClient = downloadergrpc.NewClientDirect(bittorrentServer)
backend.downloaderClient = direct.NewDownloaderClient(bittorrentServer)
}
if err != nil {
return nil, err
@ -526,6 +527,31 @@ func New(stack *node.Node, config *ethconfig.Config, txpoolCfg txpool2.Config, l
}
//eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams)
// start HTTP API
httpRpcCfg := cli.Flags{} // TODO: add rpcdaemon cli flags to Erigon and fill this struct (or break it to smaller config objects)
ethRpcClient, txPoolRpcClient, miningRpcClient, starkNetRpcClient, stateCache, ff, err := cli.EmbeddedServices(
ctx, chainKv, httpRpcCfg.StateCache, blockReader,
ethBackendRPC,
backend.txPool2GrpcServer,
miningRPC,
)
if err != nil {
return nil, err
}
var borDb kv.RoDB
if casted, ok := backend.engine.(*bor.Bor); ok {
borDb = casted.DB
}
apiList := commands.APIList(chainKv, borDb, ethRpcClient, txPoolRpcClient, miningRpcClient, starkNetRpcClient, ff, stateCache, blockReader, httpRpcCfg, nil)
go func() {
_ = apiList
//if err := cli.StartRpcServer(ctx, httpRpcCfg, apiList); err != nil {
// log.Error(err.Error())
// return
//}
}()
// Register the backend on the node
stack.RegisterAPIs(backend.APIs())
stack.RegisterLifecycle(backend)

2
go.mod
View File

@ -40,7 +40,7 @@ require (
github.com/json-iterator/go v1.1.12
github.com/julienschmidt/httprouter v1.3.0
github.com/kevinburke/go-bindata v3.21.0+incompatible
github.com/ledgerwatch/erigon-lib v0.0.0-20220212030730-fc0a90f3b518
github.com/ledgerwatch/erigon-lib v0.0.0-20220212114842-31982dacc8a5
github.com/ledgerwatch/log/v3 v3.4.0
github.com/ledgerwatch/secp256k1 v1.0.0
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect

4
go.sum
View File

@ -632,8 +632,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-20220212030730-fc0a90f3b518 h1:4SPtNxvC6AkdD6e5oLdIhTa770CEIDoj8xyMfDm/T0M=
github.com/ledgerwatch/erigon-lib v0.0.0-20220212030730-fc0a90f3b518/go.mod h1:NzHpr5GGDbLM/hYSU4BWB0INU6ZALzMzaqX4i03R6i0=
github.com/ledgerwatch/erigon-lib v0.0.0-20220212114842-31982dacc8a5 h1:P8LFJVTTfh3s+vjWa8g7tK8MyEF0fuIz+36Ksj1iAz8=
github.com/ledgerwatch/erigon-lib v0.0.0-20220212114842-31982dacc8a5/go.mod h1:phuzMr8tLvqjo5cQVA9jj8odAso6eLyS4LFmUJrDFGw=
github.com/ledgerwatch/log/v3 v3.4.0 h1:SEIOcv5a2zkG3PmoT5jeTU9m/0nEUv0BJS5bzsjwKCI=
github.com/ledgerwatch/log/v3 v3.4.0/go.mod h1:VXcz6Ssn6XEeU92dCMc39/g1F0OYAjw1Mt+dGP5DjXY=
github.com/ledgerwatch/secp256k1 v1.0.0 h1:Usvz87YoTG0uePIV8woOof5cQnLXGYa162rFf3YnwaQ=