p2p: silkworm sentry (#8527)

This commit is contained in:
battlmonstr 2023-11-02 02:35:13 +01:00 committed by GitHub
parent 329d18ef6f
commit d92898a508
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 622 additions and 251 deletions

View File

@ -15,6 +15,7 @@ import (
"github.com/ledgerwatch/erigon/consensus/bor/heimdallgrpc"
"github.com/ledgerwatch/erigon/core/rawdb/blockio"
"github.com/ledgerwatch/erigon/node/nodecfg"
"github.com/ledgerwatch/erigon/p2p/sentry/sentry_multi_client"
"github.com/ledgerwatch/erigon/turbo/builder"
"github.com/ledgerwatch/erigon/turbo/snapshotsync/freezeblocks"
"github.com/ledgerwatch/log/v3"
@ -33,7 +34,6 @@ import (
"github.com/ledgerwatch/erigon-lib/kv/rawdbv3"
libstate "github.com/ledgerwatch/erigon-lib/state"
"github.com/ledgerwatch/erigon/cmd/hack/tool/fromdb"
"github.com/ledgerwatch/erigon/cmd/sentry/sentry"
"github.com/ledgerwatch/erigon/consensus"
"github.com/ledgerwatch/erigon/core"
"github.com/ledgerwatch/erigon/core/rawdb"
@ -1529,7 +1529,7 @@ func newSync(ctx context.Context, db kv.RwDB, miningConfig *params.MiningConfig,
maxBlockBroadcastPeers := func(header *types.Header) uint { return 0 }
sentryControlServer, err := sentry.NewMultiClient(
sentryControlServer, err := sentry_multi_client.NewMultiClient(
db,
"",
chainConfig,

View File

@ -8,9 +8,9 @@ import (
"github.com/ledgerwatch/erigon-lib/common/datadir"
"github.com/spf13/cobra"
"github.com/ledgerwatch/erigon/cmd/sentry/sentry"
"github.com/ledgerwatch/erigon/cmd/utils"
"github.com/ledgerwatch/erigon/common/paths"
"github.com/ledgerwatch/erigon/p2p/sentry"
"github.com/ledgerwatch/erigon/turbo/debug"
"github.com/ledgerwatch/erigon/turbo/logging"
node2 "github.com/ledgerwatch/erigon/turbo/node"

View File

@ -838,9 +838,21 @@ var (
SilkwormPathFlag = cli.StringFlag{
Name: "silkworm.path",
Usage: "Path to the silkworm_api library (enables embedded Silkworm execution)",
Usage: "Path to the Silkworm library",
Value: "",
}
SilkwormExecutionFlag = cli.BoolFlag{
Name: "silkworm.exec",
Usage: "Enable Silkworm block execution",
}
SilkwormRpcDaemonFlag = cli.BoolFlag{
Name: "silkworm.rpcd",
Usage: "Enable embedded Silkworm RPC daemon",
}
SilkwormSentryFlag = cli.BoolFlag{
Name: "silkworm.sentry",
Usage: "Enable embedded Silkworm Sentry service",
}
)
var MetricFlags = []cli.Flag{&MetricsEnabledFlag, &MetricsHTTPFlag, &MetricsPortFlag}
@ -1031,6 +1043,7 @@ func NewP2PConfig(
return nil, fmt.Errorf("invalid nat option %s: %w", natSetting, err)
}
cfg.NAT = natif
cfg.NATSpec = natSetting
return cfg, nil
}
@ -1079,11 +1092,13 @@ func setListenAddress(ctx *cli.Context, cfg *p2p.Config) {
// setNAT creates a port mapper from command line flags.
func setNAT(ctx *cli.Context, cfg *p2p.Config) {
if ctx.IsSet(NATFlag.Name) {
natif, err := nat.Parse(ctx.String(NATFlag.Name))
natSetting := ctx.String(NATFlag.Name)
natif, err := nat.Parse(natSetting)
if err != nil {
Fatalf("Option %s: %v", NATFlag.Name, err)
}
cfg.NAT = natif
cfg.NATSpec = natSetting
}
}
@ -1161,7 +1176,6 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config, nodeName, datadir string, l
}
ethPeers := cfg.MaxPeers
cfg.Name = nodeName
logger.Info("Maximum peer count", "ETH", ethPeers, "total", cfg.MaxPeers)
if netrestrict := ctx.String(NetrestrictFlag.Name); netrestrict != "" {
@ -1460,10 +1474,12 @@ func setWhitelist(ctx *cli.Context, cfg *ethconfig.Config) {
}
func setSilkworm(ctx *cli.Context, cfg *ethconfig.Config) {
cfg.SilkwormEnabled = ctx.IsSet(SilkwormPathFlag.Name)
if cfg.SilkwormEnabled {
cfg.SilkwormPath = ctx.String(SilkwormPathFlag.Name)
cfg.SilkwormPath = ctx.String(SilkwormPathFlag.Name)
if ctx.IsSet(SilkwormExecutionFlag.Name) {
cfg.SilkwormExecution = ctx.Bool(SilkwormExecutionFlag.Name)
}
cfg.SilkwormRpcDaemon = ctx.Bool(SilkwormRpcDaemonFlag.Name)
cfg.SilkwormSentry = ctx.Bool(SilkwormSentryFlag.Name)
}
// CheckExclusive verifies that only a single instance of the provided flags was
@ -1576,7 +1592,6 @@ func SetEthConfig(ctx *cli.Context, nodeConfig *nodecfg.Config, cfg *ethconfig.C
setSilkworm(ctx, cfg)
cfg.Ethstats = ctx.String(EthStatsURLFlag.Name)
cfg.P2PEnabled = len(nodeConfig.P2P.SentryAddr) == 0
cfg.HistoryV3 = ctx.Bool(HistoryV3Flag.Name)
if ctx.IsSet(NetworkIdFlag.Name) {
cfg.NetworkID = ctx.Uint64(NetworkIdFlag.Name)

View File

@ -47,6 +47,8 @@ import (
"github.com/ledgerwatch/erigon/core/rawdb/blockio"
"github.com/ledgerwatch/erigon/ethdb/prune"
"github.com/ledgerwatch/erigon/p2p/sentry"
"github.com/ledgerwatch/erigon/p2p/sentry/sentry_multi_client"
"github.com/ledgerwatch/erigon/turbo/builder"
"github.com/ledgerwatch/erigon/turbo/engineapi"
"github.com/ledgerwatch/erigon/turbo/engineapi/engine_block_downloader"
@ -87,7 +89,6 @@ import (
"github.com/ledgerwatch/erigon/cmd/caplin/caplin1"
"github.com/ledgerwatch/erigon/cmd/rpcdaemon/cli"
"github.com/ledgerwatch/erigon/cmd/sentry/sentry"
"github.com/ledgerwatch/erigon/common/debug"
rpcsentinel "github.com/ledgerwatch/erigon-lib/gointerfaces/sentinel"
@ -165,7 +166,7 @@ type Ethereum struct {
// downloader fields
sentryCtx context.Context
sentryCancel context.CancelFunc
sentriesClient *sentry.MultiClient
sentriesClient *sentry_multi_client.MultiClient
sentryServers []*sentry.GrpcServer
stagedSync *stagedsync.Sync
@ -200,7 +201,10 @@ type Ethereum struct {
logger log.Logger
sentinel rpcsentinel.SentinelClient
silkworm *silkworm.Silkworm
silkworm *silkworm.Silkworm
silkwormRPCDaemonService *silkworm.RpcDaemonService
silkwormSentryService *silkworm.SentryService
}
func splitAddrIntoHostAndPort(addr string) (host string, port int, err error) {
@ -339,15 +343,56 @@ func New(ctx context.Context, stack *node.Node, config *ethconfig.Config, logger
backend.gasPrice, _ = uint256.FromBig(config.Miner.GasPrice)
if config.SilkwormPath != "" {
backend.silkworm, err = silkworm.New(config.SilkwormPath, config.Dirs.DataDir)
if err != nil {
return nil, err
}
}
var sentries []direct.SentryClient
if len(stack.Config().P2P.SentryAddr) > 0 {
for _, addr := range stack.Config().P2P.SentryAddr {
sentryClient, err := sentry.GrpcClient(backend.sentryCtx, addr)
sentryClient, err := sentry_multi_client.GrpcClient(backend.sentryCtx, addr)
if err != nil {
return nil, err
}
sentries = append(sentries, sentryClient)
}
} else if config.SilkwormSentry {
apiPort := 53774
apiAddr := fmt.Sprintf("127.0.0.1:%d", apiPort)
p2pConfig := stack.Config().P2P
collectNodeURLs := func(nodes []*enode.Node) []string {
var urls []string
for _, n := range nodes {
urls = append(urls, n.URLv4())
}
return urls
}
settings := silkworm.SentrySettings{
ClientId: p2pConfig.Name,
ApiPort: apiPort,
Port: p2pConfig.ListenPort(),
Nat: p2pConfig.NATSpec,
NetworkId: config.NetworkID,
NodeKey: crypto.FromECDSA(p2pConfig.PrivateKey),
StaticPeers: collectNodeURLs(p2pConfig.StaticNodes),
Bootnodes: collectNodeURLs(p2pConfig.BootstrapNodes),
NoDiscover: p2pConfig.NoDiscovery,
MaxPeers: p2pConfig.MaxPeers,
}
silkwormSentryService := backend.silkworm.NewSentryService(settings)
backend.silkwormSentryService = &silkwormSentryService
sentryClient, err := sentry_multi_client.GrpcClient(backend.sentryCtx, apiAddr)
if err != nil {
return nil, err
}
sentries = append(sentries, sentryClient)
} else {
var readNodeInfo = func() *eth.NodeInfo {
var res *eth.NodeInfo
@ -478,13 +523,6 @@ func New(ctx context.Context, stack *node.Node, config *ethconfig.Config, logger
backend.engine = ethconsensusconfig.CreateConsensusEngine(ctx, stack.Config(), chainConfig, consensusConfig, config.Miner.Notify, config.Miner.Noverify, heimdallClient, config.WithoutHeimdall, blockReader, false /* readonly */, logger)
if config.SilkwormEnabled {
backend.silkworm, err = silkworm.New(config.SilkwormPath)
if err != nil {
return nil, err
}
}
inMemoryExecution := func(batch kv.RwTx, header *types.Header, body *types.RawBody, unwindPoint uint64, headersChain []*types.Header, bodiesChain []*types.RawBody,
notifications *shards.Notifications) error {
terseLogger := log.New()
@ -529,7 +567,7 @@ func New(ctx context.Context, stack *node.Node, config *ethconfig.Config, logger
}
}
backend.sentriesClient, err = sentry.NewMultiClient(
backend.sentriesClient, err = sentry_multi_client.NewMultiClient(
chainKv,
stack.Config().NodeName(),
chainConfig,
@ -862,24 +900,17 @@ func (s *Ethereum) Init(stack *node.Node, config *ethconfig.Config) error {
}
s.apiList = jsonrpc.APIList(chainKv, ethRpcClient, txPoolRpcClient, miningRpcClient, ff, stateCache, blockReader, s.agg, httpRpcCfg, s.engine, s.logger)
go func() {
if config.SilkwormEnabled && httpRpcCfg.Enabled {
go func() {
<-ctx.Done()
s.silkworm.StopRpcDaemon()
}()
err = s.silkworm.StartRpcDaemon(chainKv)
if err != nil {
s.logger.Error(err.Error())
return
}
} else {
if config.SilkwormRpcDaemon && httpRpcCfg.Enabled {
silkwormRPCDaemonService := s.silkworm.NewRpcDaemonService(chainKv)
s.silkwormRPCDaemonService = &silkwormRPCDaemonService
} else {
go func() {
if err := cli.StartRpcServer(ctx, httpRpcCfg, s.apiList, s.logger); err != nil {
s.logger.Error(err.Error())
return
s.logger.Error("cli.StartRpcServer error", "err", err)
}
}
}()
}()
}
go s.engineBackendRPC.Start(httpRpcCfg, s.chainDB, s.blockReader, ff, stateCache, s.agg, s.engine, ethRpcClient, txPoolRpcClient, miningRpcClient)
@ -1265,6 +1296,17 @@ func (s *Ethereum) Start() error {
s.engine.(*bor.Bor).Start(s.chainDB)
}
if s.silkwormRPCDaemonService != nil {
if err := s.silkwormRPCDaemonService.Start(); err != nil {
s.logger.Error("silkworm.StartRpcDaemon error", "err", err)
}
}
if s.silkwormSentryService != nil {
if err := s.silkwormSentryService.Start(); err != nil {
s.logger.Error("silkworm.SentryStart error", "err", err)
}
}
return nil
}
@ -1310,7 +1352,17 @@ func (s *Ethereum) Stop() error {
}
s.chainDB.Close()
if s.config.SilkwormEnabled {
if s.silkwormRPCDaemonService != nil {
if err := s.silkwormRPCDaemonService.Stop(); err != nil {
s.logger.Error("silkworm.StopRpcDaemon error", "err", err)
}
}
if s.silkwormSentryService != nil {
if err := s.silkwormSentryService.Stop(); err != nil {
s.logger.Error("silkworm.SentryStop error", "err", err)
}
}
if s.silkworm != nil {
s.silkworm.Close()
}
@ -1337,7 +1389,7 @@ func (s *Ethereum) SentryCtx() context.Context {
return s.sentryCtx
}
func (s *Ethereum) SentryControlServer() *sentry.MultiClient {
func (s *Ethereum) SentryControlServer() *sentry_multi_client.MultiClient {
return s.sentriesClient
}
func (s *Ethereum) BlockIO() (services.FullBlockReader, *blockio.BlockWriter) {

View File

@ -102,7 +102,8 @@ var Defaults = Config{
Produce: true,
},
SilkwormEnabled: false,
// applies if SilkwormPath is set
SilkwormExecution: true,
}
func init() {
@ -178,8 +179,6 @@ type Config struct {
// for nodes to connect to.
EthDiscoveryURLs []string
P2PEnabled bool
Prune prune.Mode
BatchSize datasize.ByteSize // Batch size for execution stage
@ -253,8 +252,10 @@ type Config struct {
ForcePartialCommit bool
// Embedded Silkworm support
SilkwormEnabled bool
SilkwormPath string
SilkwormPath string
SilkwormExecution bool
SilkwormRpcDaemon bool
SilkwormSentry bool
}
type Sync struct {

View File

@ -22,7 +22,6 @@ func (c Config) MarshalTOML() (interface{}, error) {
Genesis *types.Genesis `toml:",omitempty"`
NetworkID uint64
EthDiscoveryURLs []string
P2PEnabled bool
Prune prune.Mode
BatchSize datasize.ByteSize
ImportMode bool
@ -47,7 +46,6 @@ func (c Config) MarshalTOML() (interface{}, error) {
enc.Genesis = c.Genesis
enc.NetworkID = c.NetworkID
enc.EthDiscoveryURLs = c.EthDiscoveryURLs
enc.P2PEnabled = c.P2PEnabled
enc.Prune = c.Prune
enc.BatchSize = c.BatchSize
enc.ImportMode = c.ImportMode
@ -73,7 +71,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
Genesis *types.Genesis `toml:",omitempty"`
NetworkID *uint64
EthDiscoveryURLs []string
P2PEnabled *bool
Prune *prune.Mode
BatchSize *datasize.ByteSize
ImportMode *bool
@ -107,9 +104,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
if dec.EthDiscoveryURLs != nil {
c.EthDiscoveryURLs = dec.EthDiscoveryURLs
}
if dec.P2PEnabled != nil {
c.P2PEnabled = *dec.P2PEnabled
}
if dec.Prune != nil {
c.Prune = *dec.Prune
}

View File

@ -37,12 +37,12 @@ import (
"github.com/ledgerwatch/erigon/turbo/services"
"github.com/ledgerwatch/log/v3"
"github.com/ledgerwatch/erigon/cmd/sentry/sentry"
"github.com/ledgerwatch/erigon/consensus"
"github.com/ledgerwatch/erigon/core/rawdb"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/eth/stagedsync/stages"
"github.com/ledgerwatch/erigon/node"
"github.com/ledgerwatch/erigon/p2p/sentry"
)
const (

View File

@ -1,4 +1,4 @@
package sentry
package sentry_multi_client
import (
"context"

View File

@ -1,7 +1,8 @@
package sentry
package sentry_multi_client
import (
"context"
"github.com/ledgerwatch/erigon/p2p/sentry"
"math/rand"
"github.com/holiman/uint256"
@ -72,7 +73,7 @@ func (cs *MultiClient) SendBodyRequest(ctx context.Context, req *bodydownload.Bo
if sentPeers == nil || len(sentPeers.Peers) == 0 {
continue
}
return ConvertH512ToPeerID(sentPeers.Peers[0]), true
return sentry.ConvertH512ToPeerID(sentPeers.Peers[0]), true
}
return [64]byte{}, false
}
@ -119,7 +120,7 @@ func (cs *MultiClient) SendHeaderRequest(ctx context.Context, req *headerdownloa
if sentPeers == nil || len(sentPeers.Peers) == 0 {
continue
}
return ConvertH512ToPeerID(sentPeers.Peers[0]), true
return sentry.ConvertH512ToPeerID(sentPeers.Peers[0]), true
}
return [64]byte{}, false
}

View File

@ -1,4 +1,4 @@
package sentry
package sentry_multi_client
import (
"bytes"
@ -6,6 +6,7 @@ import (
"encoding/hex"
"errors"
"fmt"
sentry2 "github.com/ledgerwatch/erigon/p2p/sentry"
"math/rand"
"sort"
"sync"
@ -441,7 +442,7 @@ func (cs *MultiClient) blockHeaders(ctx context.Context, pkt eth.BlockHeadersPac
return err
}
defer tx.Rollback()
penalties, err := cs.Hd.ProcessHeadersPOS(csHeaders, tx, ConvertH512ToPeerID(peerID))
penalties, err := cs.Hd.ProcessHeadersPOS(csHeaders, tx, sentry2.ConvertH512ToPeerID(peerID))
if err != nil {
return err
}
@ -450,7 +451,7 @@ func (cs *MultiClient) blockHeaders(ctx context.Context, pkt eth.BlockHeadersPac
}
} else {
sort.Sort(headerdownload.HeadersSort(csHeaders)) // Sorting by order of block heights
canRequestMore := cs.Hd.ProcessHeaders(csHeaders, false /* newBlock */, ConvertH512ToPeerID(peerID))
canRequestMore := cs.Hd.ProcessHeaders(csHeaders, false /* newBlock */, sentry2.ConvertH512ToPeerID(peerID))
if canRequestMore {
currentTime := time.Now()
@ -520,7 +521,7 @@ func (cs *MultiClient) newBlock66(ctx context.Context, inreq *proto_sentry.Inbou
})
}
cs.Hd.ProcessHeaders(segments, true /* newBlock */, ConvertH512ToPeerID(inreq.PeerId)) // There is only one segment in this case
cs.Hd.ProcessHeaders(segments, true /* newBlock */, sentry2.ConvertH512ToPeerID(inreq.PeerId)) // There is only one segment in this case
} else {
outreq := proto_sentry.PenalizePeerRequest{
PeerId: inreq.PeerId,
@ -546,7 +547,7 @@ func (cs *MultiClient) newBlock66(ctx context.Context, inreq *proto_sentry.Inbou
if _, err1 := sentry.PeerMinBlock(ctx, &outreq, &grpc.EmptyCallOption{}); err1 != nil {
cs.logger.Error("Could not send min block for peer", "err", err1)
}
cs.logger.Trace(fmt.Sprintf("NewBlockMsg{blockNumber: %d} from [%s]", request.Block.NumberU64(), ConvertH512ToPeerID(inreq.PeerId)))
cs.logger.Trace(fmt.Sprintf("NewBlockMsg{blockNumber: %d} from [%s]", request.Block.NumberU64(), sentry2.ConvertH512ToPeerID(inreq.PeerId)))
return nil
}
@ -560,7 +561,7 @@ func (cs *MultiClient) blockBodies66(ctx context.Context, inreq *proto_sentry.In
// No point processing empty response
return nil
}
cs.Bd.DeliverBodies(txs, uncles, withdrawals, uint64(len(inreq.Data)), ConvertH512ToPeerID(inreq.PeerId))
cs.Bd.DeliverBodies(txs, uncles, withdrawals, uint64(len(inreq.Data)), sentry2.ConvertH512ToPeerID(inreq.PeerId))
return nil
}
@ -751,7 +752,7 @@ func (cs *MultiClient) handleInboundMessage(ctx context.Context, inreq *proto_se
func (cs *MultiClient) HandlePeerEvent(ctx context.Context, event *proto_sentry.PeerEvent, sentry direct.SentryClient) error {
eventID := event.EventId.String()
peerID := ConvertH512ToPeerID(event.PeerId)
peerID := sentry2.ConvertH512ToPeerID(event.PeerId)
peerIDStr := hex.EncodeToString(peerID[:])
if !cs.logPeerInfo {

View File

@ -156,6 +156,9 @@ type Config struct {
// Internet.
NAT nat.Interface `toml:",omitempty"`
// NAT interface description (see NAT.Parse()).
NATSpec string
// If Dialer is set to a non-nil value, the given Dialer
// is used to dial outbound peer connections.
Dialer NodeDialer `toml:"-"`

View File

@ -142,7 +142,6 @@ func InitMiner(ctx context.Context, genesis *types.Genesis, privKey *ecdsa.Priva
RPCGasCap: 50000000,
RPCTxFeeCap: 1, // 1 ether
Snapshot: ethconfig.BlocksFreezing{NoDownloader: true},
P2PEnabled: true,
StateStream: true,
}
ethCfg.TxPool.DBDir = nodeCfg.Dirs.TxPool

View File

@ -165,6 +165,9 @@ var DefaultFlags = []cli.Flag{
&utils.OtsSearchMaxCapFlag,
&utils.SilkwormPathFlag,
&utils.SilkwormExecutionFlag,
&utils.SilkwormRpcDaemonFlag,
&utils.SilkwormSentryFlag,
&utils.TrustedSetupFile,
}

View File

@ -1,19 +0,0 @@
//go:build !linux
// +build !linux
package silkworm
import (
"errors"
"unsafe"
)
func OpenLibrary(dllPath string) (unsafe.Pointer, error) {
// See https://github.com/golang/go/issues/28024
return nil, errors.New("Silkworm is only supported on Linux")
}
func LoadFunction(dllHandle unsafe.Pointer, funcName string) (unsafe.Pointer, error) {
// See https://github.com/golang/go/issues/28024
return nil, errors.New("Silkworm is only supported on Linux")
}

View File

@ -1,3 +1,5 @@
//go:build unix
package silkworm
/*

View File

@ -0,0 +1,16 @@
//go:build windows
package silkworm
import (
"errors"
"unsafe"
)
func OpenLibrary(dllPath string) (unsafe.Pointer, error) {
return nil, errors.New("not implemented")
}
func LoadFunction(dllHandle unsafe.Pointer, funcName string) (unsafe.Pointer, error) {
return nil, errors.New("not implemented")
}

View File

@ -1,156 +1,28 @@
package silkworm
/*
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// START silkworm_api.h: C API exported by Silkworm to be used in Erigon.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef SILKWORM_API_H_
#define SILKWORM_API_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "silkworm_api_bridge.h"
#if defined _MSC_VER
#define SILKWORM_EXPORT __declspec(dllexport)
#else
#define SILKWORM_EXPORT __attribute__((visibility("default")))
#endif
#if __cplusplus
#define SILKWORM_NOEXCEPT noexcept
#else
#define SILKWORM_NOEXCEPT
#endif
#if __cplusplus
extern "C" {
#endif
typedef struct MDBX_env MDBX_env;
typedef struct MDBX_txn MDBX_txn;
#define SILKWORM_OK 0
#define SILKWORM_INTERNAL_ERROR 1
#define SILKWORM_UNKNOWN_ERROR 2
#define SILKWORM_INVALID_HANDLE 3
#define SILKWORM_INVALID_PATH 4
#define SILKWORM_INVALID_SNAPSHOT 5
#define SILKWORM_INVALID_MDBX_TXN 6
#define SILKWORM_INVALID_BLOCK_RANGE 7
#define SILKWORM_BLOCK_NOT_FOUND 8
#define SILKWORM_UNKNOWN_CHAIN_ID 9
#define SILKWORM_MDBX_ERROR 10
#define SILKWORM_INVALID_BLOCK 11
#define SILKWORM_DECODING_ERROR 12
#define SILKWORM_TOO_MANY_INSTANCES 13
#define SILKWORM_INSTANCE_NOT_FOUND 14
#define SILKWORM_TERMINATION_SIGNAL 15
typedef struct SilkwormHandle SilkwormHandle;
SILKWORM_EXPORT int silkworm_init(SilkwormHandle** handle) SILKWORM_NOEXCEPT;
struct SilkwormMemoryMappedFile {
const char* file_path;
uint8_t* memory_address;
uint64_t memory_length;
};
struct SilkwormHeadersSnapshot {
struct SilkwormMemoryMappedFile segment;
struct SilkwormMemoryMappedFile header_hash_index;
};
struct SilkwormBodiesSnapshot {
struct SilkwormMemoryMappedFile segment;
struct SilkwormMemoryMappedFile block_num_index;
};
struct SilkwormTransactionsSnapshot {
struct SilkwormMemoryMappedFile segment;
struct SilkwormMemoryMappedFile tx_hash_index;
struct SilkwormMemoryMappedFile tx_hash_2_block_index;
};
struct SilkwormChainSnapshot {
struct SilkwormHeadersSnapshot headers;
struct SilkwormBodiesSnapshot bodies;
struct SilkwormTransactionsSnapshot transactions;
};
SILKWORM_EXPORT int silkworm_add_snapshot(SilkwormHandle* handle, struct SilkwormChainSnapshot* snapshot) SILKWORM_NOEXCEPT;
SILKWORM_EXPORT int silkworm_start_rpcdaemon(SilkwormHandle* handle, MDBX_env* env) SILKWORM_NOEXCEPT;
SILKWORM_EXPORT int silkworm_stop_rpcdaemon(SilkwormHandle* handle) SILKWORM_NOEXCEPT;
SILKWORM_EXPORT int silkworm_execute_blocks(
SilkwormHandle* handle, MDBX_txn* txn, uint64_t chain_id, uint64_t start_block, uint64_t max_block,
uint64_t batch_size, bool write_change_sets, bool write_receipts, bool write_call_traces,
uint64_t* last_executed_block, int* mdbx_error_code) SILKWORM_NOEXCEPT;
SILKWORM_EXPORT int silkworm_fini(SilkwormHandle* handle) SILKWORM_NOEXCEPT;
#if __cplusplus
}
#endif
#endif // SILKWORM_API_H_
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// END silkworm_api.h: C API exported by Silkworm to be used in Erigon.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef int (*silkworm_init_func)(SilkwormHandle** handle);
int call_silkworm_init_func(void* func_ptr, SilkwormHandle** handle) {
return ((silkworm_init_func)func_ptr)(handle);
}
typedef int (*silkworm_add_snapshot_func)(SilkwormHandle* handle, struct SilkwormChainSnapshot* snapshot);
int call_silkworm_add_snapshot_func(void* func_ptr, SilkwormHandle* handle, struct SilkwormChainSnapshot* snapshot) {
return ((silkworm_add_snapshot_func)func_ptr)(handle, snapshot);
}
typedef int (*silkworm_start_rpcdaemon_func)(SilkwormHandle* handle, MDBX_env* env);
int call_silkworm_start_rpcdaemon_func(void* func_ptr, SilkwormHandle* handle, MDBX_env* env) {
return ((silkworm_start_rpcdaemon_func)func_ptr)(handle, env);
}
typedef int (*silkworm_stop_rpcdaemon_func)(SilkwormHandle* handle);
int call_silkworm_stop_rpcdaemon_func(void* func_ptr, SilkwormHandle* handle) {
return ((silkworm_stop_rpcdaemon_func)func_ptr)(handle);
}
typedef int (*silkworm_execute_blocks_func)(SilkwormHandle* handle, MDBX_txn* txn, uint64_t chain_id, uint64_t start_block,
uint64_t max_block, uint64_t batch_size, bool write_change_sets, bool write_receipts, bool write_call_traces,
uint64_t* last_executed_block, int* mdbx_error_code);
int call_silkworm_execute_blocks_func(void* func_ptr, SilkwormHandle* handle, MDBX_txn* txn, uint64_t chain_id, uint64_t start_block,
uint64_t max_block, uint64_t batch_size, bool write_change_sets, bool write_receipts, bool write_call_traces,
uint64_t* last_executed_block, int* mdbx_error_code) {
return ((silkworm_execute_blocks_func)func_ptr)(handle, txn, chain_id, start_block, max_block, batch_size, write_change_sets,
write_receipts, write_call_traces, last_executed_block, mdbx_error_code);
}
typedef int (*silkworm_fini_func)(SilkwormHandle* handle);
int call_silkworm_fini_func(void* func_ptr, SilkwormHandle* handle) {
return ((silkworm_fini_func)func_ptr)(handle);
static bool go_string_copy(_GoString_ s, char *dest, size_t size) {
size_t len = _GoStringLen(s);
if (len >= size) return false;
const char *src = _GoStringPtr(s);
strncpy(dest, src, len);
dest[len] = '\0';
return true;
}
*/
import "C"
import (
"errors"
"fmt"
"math/big"
"runtime"
"unsafe"
"github.com/ledgerwatch/erigon-lib/kv"
@ -158,22 +30,23 @@ import (
)
const (
SILKWORM_OK = iota
SILKWORM_INTERNAL_ERROR
SILKWORM_UNKNOWN_ERROR
SILKWORM_INVALID_HANDLE
SILKWORM_INVALID_PATH
SILKWORM_INVALID_SNAPSHOT
SILKWORM_INVALID_MDBX_TXN
SILKWORM_INVALID_BLOCK_RANGE
SILKWORM_BLOCK_NOT_FOUND
SILKWORM_UNKNOWN_CHAIN_ID
SILKWORM_MDBX_ERROR
SILKWORM_INVALID_BLOCK
SILKWORM_DECODING_ERROR
SILKWORM_TOO_MANY_INSTANCES
SILKWORM_INSTANCE_NOT_FOUND
SILKWORM_TERMINATION_SIGNAL
SILKWORM_OK = C.SILKWORM_OK
SILKWORM_INTERNAL_ERROR = C.SILKWORM_INTERNAL_ERROR
SILKWORM_UNKNOWN_ERROR = C.SILKWORM_UNKNOWN_ERROR
SILKWORM_INVALID_HANDLE = C.SILKWORM_INVALID_HANDLE
SILKWORM_INVALID_PATH = C.SILKWORM_INVALID_PATH
SILKWORM_INVALID_SNAPSHOT = C.SILKWORM_INVALID_SNAPSHOT
SILKWORM_INVALID_MDBX_TXN = C.SILKWORM_INVALID_MDBX_TXN
SILKWORM_INVALID_BLOCK_RANGE = C.SILKWORM_INVALID_BLOCK_RANGE
SILKWORM_BLOCK_NOT_FOUND = C.SILKWORM_BLOCK_NOT_FOUND
SILKWORM_UNKNOWN_CHAIN_ID = C.SILKWORM_UNKNOWN_CHAIN_ID
SILKWORM_MDBX_ERROR = C.SILKWORM_MDBX_ERROR
SILKWORM_INVALID_BLOCK = C.SILKWORM_INVALID_BLOCK
SILKWORM_DECODING_ERROR = C.SILKWORM_DECODING_ERROR
SILKWORM_TOO_MANY_INSTANCES = C.SILKWORM_TOO_MANY_INSTANCES
SILKWORM_INVALID_SETTINGS = C.SILKWORM_INVALID_SETTINGS
SILKWORM_TERMINATION_SIGNAL = C.SILKWORM_TERMINATION_SIGNAL
SILKWORM_SERVICE_ALREADY_STARTED = C.SILKWORM_SERVICE_ALREADY_STARTED
)
// ErrInterrupted is the error returned by Silkworm APIs when stopped by any termination signal.
@ -187,10 +60,12 @@ type Silkworm struct {
addSnapshot unsafe.Pointer
startRpcDaemon unsafe.Pointer
stopRpcDaemon unsafe.Pointer
sentryStart unsafe.Pointer
sentryStop unsafe.Pointer
executeBlocks unsafe.Pointer
}
func New(dllPath string) (*Silkworm, error) {
func New(dllPath string, dataDirPath string) (*Silkworm, error) {
dllHandle, err := OpenLibrary(dllPath)
if err != nil {
return nil, fmt.Errorf("failed to load silkworm library from path %s: %w", dllPath, err)
@ -216,6 +91,14 @@ func New(dllPath string) (*Silkworm, error) {
if err != nil {
return nil, fmt.Errorf("failed to load silkworm function silkworm_stop_rpcdaemon: %w", err)
}
sentryStart, err := LoadFunction(dllHandle, "silkworm_sentry_start")
if err != nil {
return nil, fmt.Errorf("failed to load silkworm function silkworm_sentry_start: %w", err)
}
sentryStop, err := LoadFunction(dllHandle, "silkworm_sentry_stop")
if err != nil {
return nil, fmt.Errorf("failed to load silkworm function silkworm_sentry_stop: %w", err)
}
executeBlocks, err := LoadFunction(dllHandle, "silkworm_execute_blocks")
if err != nil {
return nil, fmt.Errorf("failed to load silkworm function silkworm_execute_blocks: %w", err)
@ -223,14 +106,24 @@ func New(dllPath string) (*Silkworm, error) {
silkworm := &Silkworm{
dllHandle: dllHandle,
instance: nil,
initFunc: initFunc,
finiFunc: finiFunc,
addSnapshot: addSnapshot,
startRpcDaemon: startRpcDaemon,
stopRpcDaemon: stopRpcDaemon,
sentryStart: sentryStart,
sentryStop: sentryStop,
executeBlocks: executeBlocks,
}
status := C.call_silkworm_init_func(silkworm.initFunc, &silkworm.instance) //nolint:gocritic
settings := &C.struct_SilkwormSettings{}
if !C.go_string_copy(dataDirPath, &settings.data_dir_path[0], C.SILKWORM_PATH_SIZE) {
return nil, errors.New("silkworm.New failed to copy dataDirPath")
}
status := C.call_silkworm_init_func(silkworm.initFunc, &silkworm.instance, settings) //nolint:gocritic
if status == SILKWORM_OK {
return silkworm, nil
}
@ -333,7 +226,129 @@ func (s *Silkworm) StopRpcDaemon() error {
return fmt.Errorf("silkworm_stop_rpcdaemon error %d", status)
}
type RpcDaemonService struct {
silkworm *Silkworm
db kv.RoDB
}
func (s *Silkworm) NewRpcDaemonService(db kv.RoDB) RpcDaemonService {
return RpcDaemonService{
silkworm: s,
db: db,
}
}
func (service RpcDaemonService) Start() error {
return service.silkworm.StartRpcDaemon(service.db)
}
func (service RpcDaemonService) Stop() error {
return service.silkworm.StopRpcDaemon()
}
type SentrySettings struct {
ClientId string
ApiPort int
Port int
Nat string
NetworkId uint64
NodeKey []byte
StaticPeers []string
Bootnodes []string
NoDiscover bool
MaxPeers int
}
func copyPeerURLs(list []string, cList *[C.SILKWORM_SENTRY_SETTINGS_PEERS_MAX][C.SILKWORM_SENTRY_SETTINGS_PEER_URL_SIZE]C.char) error {
listLen := len(list)
if listLen > C.SILKWORM_SENTRY_SETTINGS_PEERS_MAX {
return errors.New("copyPeerURLs: peers URL list has too many items")
}
// mark the list end with an empty string
if listLen < C.SILKWORM_SENTRY_SETTINGS_PEERS_MAX {
cList[listLen][0] = 0
}
for i, url := range list {
if !C.go_string_copy(url, &cList[i][0], C.SILKWORM_SENTRY_SETTINGS_PEER_URL_SIZE) {
return fmt.Errorf("copyPeerURLs: failed to copy peer URL %d", i)
}
}
return nil
}
func makeCSentrySettings(settings SentrySettings) (*C.struct_SilkwormSentrySettings, error) {
cSettings := &C.struct_SilkwormSentrySettings{
api_port: C.uint16_t(settings.ApiPort),
port: C.uint16_t(settings.Port),
network_id: C.uint64_t(settings.NetworkId),
no_discover: C.bool(settings.NoDiscover),
max_peers: C.size_t(settings.MaxPeers),
}
if !C.go_string_copy(settings.ClientId, &cSettings.client_id[0], C.SILKWORM_SENTRY_SETTINGS_CLIENT_ID_SIZE) {
return nil, errors.New("makeCSentrySettings failed to copy ClientId")
}
if !C.go_string_copy(settings.Nat, &cSettings.nat[0], C.SILKWORM_SENTRY_SETTINGS_NAT_SIZE) {
return nil, errors.New("makeCSentrySettings failed to copy Nat")
}
if len(settings.NodeKey) == C.SILKWORM_SENTRY_SETTINGS_NODE_KEY_SIZE {
C.memcpy(unsafe.Pointer(&cSettings.node_key[0]), unsafe.Pointer(&settings.NodeKey[0]), C.SILKWORM_SENTRY_SETTINGS_NODE_KEY_SIZE) //nolint:gocritic
} else {
return nil, errors.New("makeCSentrySettings failed to copy NodeKey")
}
if err := copyPeerURLs(settings.StaticPeers, &cSettings.static_peers); err != nil {
return nil, fmt.Errorf("copyPeerURLs failed to copy StaticPeers: %w", err)
}
if err := copyPeerURLs(settings.Bootnodes, &cSettings.bootnodes); err != nil {
return nil, fmt.Errorf("copyPeerURLs failed to copy Bootnodes: %w", err)
}
return cSettings, nil
}
func (s *Silkworm) SentryStart(settings SentrySettings) error {
cSettings, err := makeCSentrySettings(settings)
if err != nil {
return err
}
status := C.call_silkworm_sentry_start_func(s.sentryStart, s.instance, cSettings)
if status == SILKWORM_OK {
return nil
}
return fmt.Errorf("silkworm_sentry_start error %d", status)
}
func (s *Silkworm) SentryStop() error {
status := C.call_silkworm_stop_rpcdaemon_func(s.sentryStop, s.instance)
if status == SILKWORM_OK {
return nil
}
return fmt.Errorf("silkworm_sentry_stop error %d", status)
}
type SentryService struct {
silkworm *Silkworm
settings SentrySettings
}
func (s *Silkworm) NewSentryService(settings SentrySettings) SentryService {
return SentryService{
silkworm: s,
settings: settings,
}
}
func (service SentryService) Start() error {
return service.silkworm.SentryStart(service.settings)
}
func (service SentryService) Stop() error {
return service.silkworm.SentryStop()
}
func (s *Silkworm) ExecuteBlocks(txn kv.Tx, chainID *big.Int, startBlock uint64, maxBlock uint64, batchSize uint64, writeChangeSets, writeReceipts, writeCallTraces bool) (lastExecutedBlock uint64, err error) {
if runtime.GOOS == "darwin" {
return 0, errors.New("silkworm execution is incompatible with Go runtime on macOS due to stack size mismatch (see https://github.com/golang/go/issues/28024)")
}
cTxn := (*C.MDBX_txn)(txn.CHandle())
cChainId := C.uint64_t(chainID.Uint64())
cStartBlock := C.uint64_t(startBlock)
@ -351,7 +366,7 @@ func (s *Silkworm) ExecuteBlocks(txn kv.Tx, chainID *big.Int, startBlock uint64,
if status == SILKWORM_OK {
return lastExecutedBlock, nil
}
// Handle special erros
// Handle special errors
if status == SILKWORM_INVALID_BLOCK {
return lastExecutedBlock, consensus.ErrInvalidBlock
}

View File

@ -0,0 +1,206 @@
/*
Copyright 2023 The Silkworm Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef SILKWORM_API_H_
#define SILKWORM_API_H_
// C API exported by Silkworm to be used in Erigon.
#include <stdbool.h> // NOLINT(*-deprecated-headers)
#include <stddef.h> // NOLINT(*-deprecated-headers)
#include <stdint.h> // NOLINT(*-deprecated-headers)
#if defined _MSC_VER
#define SILKWORM_EXPORT __declspec(dllexport)
#else
#define SILKWORM_EXPORT __attribute__((visibility("default")))
#endif
#if __cplusplus
#define SILKWORM_NOEXCEPT noexcept
#else
#define SILKWORM_NOEXCEPT
#endif
#if __cplusplus
extern "C" {
#endif
// Silkworm library error codes (SILKWORM_OK indicates no error, i.e. success)
#define SILKWORM_OK 0
#define SILKWORM_INTERNAL_ERROR 1
#define SILKWORM_UNKNOWN_ERROR 2
#define SILKWORM_INVALID_HANDLE 3
#define SILKWORM_INVALID_PATH 4
#define SILKWORM_INVALID_SNAPSHOT 5
#define SILKWORM_INVALID_MDBX_TXN 6
#define SILKWORM_INVALID_BLOCK_RANGE 7
#define SILKWORM_BLOCK_NOT_FOUND 8
#define SILKWORM_UNKNOWN_CHAIN_ID 9
#define SILKWORM_MDBX_ERROR 10
#define SILKWORM_INVALID_BLOCK 11
#define SILKWORM_DECODING_ERROR 12
#define SILKWORM_TOO_MANY_INSTANCES 13
#define SILKWORM_INVALID_SETTINGS 14
#define SILKWORM_TERMINATION_SIGNAL 15
#define SILKWORM_SERVICE_ALREADY_STARTED 16
typedef struct MDBX_env MDBX_env;
typedef struct MDBX_txn MDBX_txn;
typedef struct SilkwormHandle SilkwormHandle;
struct SilkwormMemoryMappedFile {
const char* file_path;
uint8_t* memory_address;
uint64_t memory_length;
};
struct SilkwormHeadersSnapshot {
struct SilkwormMemoryMappedFile segment;
struct SilkwormMemoryMappedFile header_hash_index;
};
struct SilkwormBodiesSnapshot {
struct SilkwormMemoryMappedFile segment;
struct SilkwormMemoryMappedFile block_num_index;
};
struct SilkwormTransactionsSnapshot {
struct SilkwormMemoryMappedFile segment;
struct SilkwormMemoryMappedFile tx_hash_index;
struct SilkwormMemoryMappedFile tx_hash_2_block_index;
};
struct SilkwormChainSnapshot {
struct SilkwormHeadersSnapshot headers;
struct SilkwormBodiesSnapshot bodies;
struct SilkwormTransactionsSnapshot transactions;
};
#define SILKWORM_PATH_SIZE 260
struct SilkwormSettings {
//! Data directory path in UTF-8.
char data_dir_path[SILKWORM_PATH_SIZE];
};
/**
* \brief Initialize the Silkworm C API library.
* \param[in,out] handle Silkworm instance handle returned on successful initialization.
* \param[in] settings General Silkworm settings.
* \return SILKWORM_OK (=0) on success, a non-zero error value on failure.
*/
SILKWORM_EXPORT int silkworm_init(
SilkwormHandle** handle,
const struct SilkwormSettings* settings) SILKWORM_NOEXCEPT;
/**
* \brief Build a set of indexes for the given snapshots.
* \param[in] handle A valid Silkworm instance handle, got with silkworm_init.
* \param[in] snapshots An array of snapshots to index.
* \param[in] indexPaths An array of paths to write indexes to.
* Note that the name of the index is a part of the path and it is used to determine the index type.
* \param[in] len The number of snapshots and paths.
* \return SILKWORM_OK (=0) on success, a non-zero error value on failure on some or all indexes.
*/
SILKWORM_EXPORT int silkworm_build_recsplit_indexes(SilkwormHandle* handle, struct SilkwormMemoryMappedFile* snapshots[], int len) SILKWORM_NOEXCEPT;
/**
* \brief Notify Silkworm about a new snapshot to use.
* \param[in] handle A valid Silkworm instance handle, got with silkworm_init.
* \param[in] snapshot A snapshot to use.
* \return SILKWORM_OK (=0) on success, a non-zero error value on failure.
*/
SILKWORM_EXPORT int silkworm_add_snapshot(SilkwormHandle* handle, struct SilkwormChainSnapshot* snapshot) SILKWORM_NOEXCEPT;
/**
* \brief Start Silkworm RPC daemon.
* \param[in] handle A valid Silkworm instance handle, got with silkworm_init.Must not be zero.
* \param[in] env An valid MDBX environment. Must not be zero.
* \return SILKWORM_OK (=0) on success, a non-zero error value on failure.
*/
SILKWORM_EXPORT int silkworm_start_rpcdaemon(SilkwormHandle* handle, MDBX_env* env) SILKWORM_NOEXCEPT;
/**
* \brief Stop Silkworm RPC daemon and wait for its termination.
* \param[in] handle A valid Silkworm instance handle, got with silkworm_init. Must not be zero.
* \param[in] snapshot A snapshot to use.
* \return SILKWORM_OK (=0) on success, a non-zero error value on failure.
*/
SILKWORM_EXPORT int silkworm_stop_rpcdaemon(SilkwormHandle* handle) SILKWORM_NOEXCEPT;
#define SILKWORM_SENTRY_SETTINGS_CLIENT_ID_SIZE 128
#define SILKWORM_SENTRY_SETTINGS_NAT_SIZE 50
#define SILKWORM_SENTRY_SETTINGS_NODE_KEY_SIZE 32
#define SILKWORM_SENTRY_SETTINGS_PEERS_MAX 128
#define SILKWORM_SENTRY_SETTINGS_PEER_URL_SIZE 200
struct SilkwormSentrySettings {
char client_id[SILKWORM_SENTRY_SETTINGS_CLIENT_ID_SIZE];
uint16_t api_port;
uint16_t port;
char nat[SILKWORM_SENTRY_SETTINGS_NAT_SIZE];
uint64_t network_id;
uint8_t node_key[SILKWORM_SENTRY_SETTINGS_NODE_KEY_SIZE];
char static_peers[SILKWORM_SENTRY_SETTINGS_PEERS_MAX][SILKWORM_SENTRY_SETTINGS_PEER_URL_SIZE];
char bootnodes[SILKWORM_SENTRY_SETTINGS_PEERS_MAX][SILKWORM_SENTRY_SETTINGS_PEER_URL_SIZE];
bool no_discover;
size_t max_peers;
};
SILKWORM_EXPORT int silkworm_sentry_start(SilkwormHandle* handle, const struct SilkwormSentrySettings* settings) SILKWORM_NOEXCEPT;
SILKWORM_EXPORT int silkworm_sentry_stop(SilkwormHandle* handle) SILKWORM_NOEXCEPT;
/**
* \brief Execute a batch of blocks and write resulting changes into the database.
* \param[in] handle A valid Silkworm instance handle, got with silkworm_init.
* \param[in] txn A valid read-write MDBX transaction. Must not be zero.
* This function does not commit nor abort the transaction.
* \param[in] chain_id EIP-155 chain ID. SILKWORM_UNKNOWN_CHAIN_ID is returned in case of an unknown or unsupported chain.
* \param[in] start_block The block height to start the execution from.
* \param[in] max_block Do not execute after this block.
* max_block may be executed, or the execution may stop earlier if the batch is full.
* \param[in] batch_size The size of DB changes to accumulate before returning from this method.
* Pass 0 if you want to execute just 1 block.
* \param[in] write_change_sets Whether to write state changes into the DB.
* \param[in] write_receipts Whether to write CBOR-encoded receipts into the DB.
* \param[in] write_call_traces Whether to write call traces into the DB.
* \param[out] last_executed_block The height of the last successfully executed block.
* Not written to if no blocks were executed, otherwise *last_executed_block max_block.
* \param[out] mdbx_error_code If an MDBX error occurs (this function returns kSilkwormMdbxError)
* and mdbx_error_code isn't NULL, it's populated with the relevant MDBX error code.
* \return SILKWORM_OK (=0) on success, a non-zero error value on failure.
* SILKWORM_BLOCK_NOT_FOUND is probably OK: it simply means that the execution reached the end of the chain
* (blocks up to and incl. last_executed_block were still executed).
*/
SILKWORM_EXPORT int silkworm_execute_blocks(
SilkwormHandle* handle, MDBX_txn* txn, uint64_t chain_id, uint64_t start_block, uint64_t max_block,
uint64_t batch_size, bool write_change_sets, bool write_receipts, bool write_call_traces,
uint64_t* last_executed_block, int* mdbx_error_code) SILKWORM_NOEXCEPT;
/**
* \brief Finalize the Silkworm C API library.
* \param[in] handle A valid Silkworm instance handle got with silkworm_init.
* \return SILKWORM_OK (=0) on success, a non-zero error value on failure.
*/
SILKWORM_EXPORT int silkworm_fini(SilkwormHandle* handle) SILKWORM_NOEXCEPT;
#if __cplusplus
}
#endif
#endif // SILKWORM_API_H_

View File

@ -0,0 +1,75 @@
/*
Copyright 2023 The Silkworm Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef SILKWORM_API_FUNC_H_
#define SILKWORM_API_FUNC_H_
#include "silkworm_api.h"
typedef int (*silkworm_init_func)(SilkwormHandle** handle, const struct SilkwormSettings* settings);
int call_silkworm_init_func(void* func_ptr, SilkwormHandle** handle, const struct SilkwormSettings* settings) {
return ((silkworm_init_func)func_ptr)(handle, settings);
}
typedef int (*silkworm_add_snapshot_func)(SilkwormHandle* handle, struct SilkwormChainSnapshot* snapshot);
int call_silkworm_add_snapshot_func(void* func_ptr, SilkwormHandle* handle, struct SilkwormChainSnapshot* snapshot) {
return ((silkworm_add_snapshot_func)func_ptr)(handle, snapshot);
}
typedef int (*silkworm_start_rpcdaemon_func)(SilkwormHandle* handle, MDBX_env* env);
int call_silkworm_start_rpcdaemon_func(void* func_ptr, SilkwormHandle* handle, MDBX_env* env) {
return ((silkworm_start_rpcdaemon_func)func_ptr)(handle, env);
}
typedef int (*silkworm_stop_rpcdaemon_func)(SilkwormHandle* handle);
int call_silkworm_stop_rpcdaemon_func(void* func_ptr, SilkwormHandle* handle) {
return ((silkworm_stop_rpcdaemon_func)func_ptr)(handle);
}
typedef int (*silkworm_sentry_start_func)(SilkwormHandle* handle, const struct SilkwormSentrySettings* settings);
int call_silkworm_sentry_start_func(void* func_ptr, SilkwormHandle* handle, const struct SilkwormSentrySettings* settings) {
return ((silkworm_sentry_start_func)func_ptr)(handle, settings);
}
typedef int (*silkworm_sentry_stop_func)(SilkwormHandle* handle);
int call_silkworm_sentry_stop_func(void* func_ptr, SilkwormHandle* handle) {
return ((silkworm_sentry_stop_func)func_ptr)(handle);
}
typedef int (*silkworm_execute_blocks_func)(SilkwormHandle* handle, MDBX_txn* txn, uint64_t chain_id, uint64_t start_block,
uint64_t max_block, uint64_t batch_size, bool write_change_sets, bool write_receipts, bool write_call_traces,
uint64_t* last_executed_block, int* mdbx_error_code);
int call_silkworm_execute_blocks_func(void* func_ptr, SilkwormHandle* handle, MDBX_txn* txn, uint64_t chain_id, uint64_t start_block,
uint64_t max_block, uint64_t batch_size, bool write_change_sets, bool write_receipts, bool write_call_traces,
uint64_t* last_executed_block, int* mdbx_error_code) {
return ((silkworm_execute_blocks_func)func_ptr)(handle, txn, chain_id, start_block, max_block, batch_size, write_change_sets,
write_receipts, write_call_traces, last_executed_block, mdbx_error_code);
}
typedef int (*silkworm_fini_func)(SilkwormHandle* handle);
int call_silkworm_fini_func(void* func_ptr, SilkwormHandle* handle) {
return ((silkworm_fini_func)func_ptr)(handle);
}
#endif // SILKWORM_API_FUNC_H_

View File

@ -33,7 +33,6 @@ import (
"github.com/ledgerwatch/erigon-lib/txpool/txpoolcfg"
types2 "github.com/ledgerwatch/erigon-lib/types"
"github.com/ledgerwatch/erigon/cmd/sentry/sentry"
"github.com/ledgerwatch/erigon/consensus"
"github.com/ledgerwatch/erigon/consensus/bor"
"github.com/ledgerwatch/erigon/consensus/ethash"
@ -51,6 +50,7 @@ import (
"github.com/ledgerwatch/erigon/eth/stagedsync"
"github.com/ledgerwatch/erigon/eth/stagedsync/stages"
"github.com/ledgerwatch/erigon/ethdb/prune"
"github.com/ledgerwatch/erigon/p2p/sentry/sentry_multi_client"
"github.com/ledgerwatch/erigon/params"
"github.com/ledgerwatch/erigon/rlp"
"github.com/ledgerwatch/erigon/turbo/builder"
@ -84,7 +84,7 @@ type MockSentry struct {
MiningSync *stagedsync.Sync
PendingBlocks chan *types.Block
MinedBlocks chan *types.Block
sentriesClient *sentry.MultiClient
sentriesClient *sentry_multi_client.MultiClient
Key *ecdsa.PrivateKey
Genesis *types.Block
SentryClient direct.SentryClient
@ -367,7 +367,7 @@ func MockWithEverything(tb testing.TB, gspec *types.Genesis, key *ecdsa.PrivateK
networkID := uint64(1)
maxBlockBroadcastPeers := func(header *types.Header) uint { return 0 }
mock.sentriesClient, err = sentry.NewMultiClient(
mock.sentriesClient, err = sentry_multi_client.NewMultiClient(
mock.DB,
"mock",
mock.ChainConfig,

View File

@ -19,7 +19,6 @@ import (
"github.com/ledgerwatch/erigon-lib/kv/membatchwithdb"
"github.com/ledgerwatch/erigon-lib/state"
"github.com/ledgerwatch/erigon/cmd/sentry/sentry"
"github.com/ledgerwatch/erigon/consensus"
"github.com/ledgerwatch/erigon/consensus/bor/finality/flags"
"github.com/ledgerwatch/erigon/consensus/bor/heimdall"
@ -32,6 +31,7 @@ import (
"github.com/ledgerwatch/erigon/eth/stagedsync"
"github.com/ledgerwatch/erigon/eth/stagedsync/stages"
"github.com/ledgerwatch/erigon/p2p"
"github.com/ledgerwatch/erigon/p2p/sentry/sentry_multi_client"
"github.com/ledgerwatch/erigon/turbo/engineapi/engine_helpers"
"github.com/ledgerwatch/erigon/turbo/services"
"github.com/ledgerwatch/erigon/turbo/shards"
@ -443,11 +443,18 @@ func StateStep(ctx context.Context, chainReader consensus.ChainReader, engine co
return nil
}
func silkwormForExecutionStage(silkworm *silkworm.Silkworm, cfg *ethconfig.Config) *silkworm.Silkworm {
if cfg.SilkwormExecution {
return silkworm
}
return nil
}
func NewDefaultStages(ctx context.Context,
db kv.RwDB,
p2pCfg p2p.Config,
cfg *ethconfig.Config,
controlServer *sentry.MultiClient,
controlServer *sentry_multi_client.MultiClient,
notifications *shards.Notifications,
snapDownloader proto_downloader.DownloaderClient,
blockReader services.FullBlockReader,
@ -496,7 +503,7 @@ func NewDefaultStages(ctx context.Context,
cfg.Genesis,
cfg.Sync,
agg,
silkworm,
silkwormForExecutionStage(silkworm, cfg),
),
stagedsync.StageHashStateCfg(db, dirs, cfg.HistoryV3),
stagedsync.StageTrieCfg(db, true, true, false, dirs.Tmp, blockReader, controlServer.Hd, cfg.HistoryV3, agg),
@ -511,7 +518,7 @@ func NewDefaultStages(ctx context.Context,
func NewPipelineStages(ctx context.Context,
db kv.RwDB,
cfg *ethconfig.Config,
controlServer *sentry.MultiClient,
controlServer *sentry_multi_client.MultiClient,
notifications *shards.Notifications,
snapDownloader proto_downloader.DownloaderClient,
blockReader services.FullBlockReader,
@ -551,7 +558,7 @@ func NewPipelineStages(ctx context.Context,
cfg.Genesis,
cfg.Sync,
agg,
silkworm,
silkwormForExecutionStage(silkworm, cfg),
),
stagedsync.StageHashStateCfg(db, dirs, cfg.HistoryV3),
stagedsync.StageTrieCfg(db, checkStateRoot, true, false, dirs.Tmp, blockReader, controlServer.Hd, cfg.HistoryV3, agg),
@ -563,7 +570,7 @@ func NewPipelineStages(ctx context.Context,
runInTestMode)
}
func NewInMemoryExecution(ctx context.Context, db kv.RwDB, cfg *ethconfig.Config, controlServer *sentry.MultiClient,
func NewInMemoryExecution(ctx context.Context, db kv.RwDB, cfg *ethconfig.Config, controlServer *sentry_multi_client.MultiClient,
dirs datadir.Dirs, notifications *shards.Notifications, blockReader services.FullBlockReader, blockWriter *blockio.BlockWriter, agg *state.AggregatorV3,
silkworm *silkworm.Silkworm, logger log.Logger) *stagedsync.Sync {
return stagedsync.New(
@ -590,7 +597,7 @@ func NewInMemoryExecution(ctx context.Context, db kv.RwDB, cfg *ethconfig.Config
cfg.Genesis,
cfg.Sync,
agg,
silkworm,
silkwormForExecutionStage(silkworm, cfg),
),
stagedsync.StageHashStateCfg(db, dirs, cfg.HistoryV3),
stagedsync.StageTrieCfg(db, true, true, true, dirs.Tmp, blockReader, controlServer.Hd, cfg.HistoryV3, agg)),