From 4a64354ba7e2f000b32225264fc2aafc231ac3a2 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Tue, 22 Apr 2025 18:37:49 +0200 Subject: [PATCH 01/65] fix: resolve case sensitivity issue with funding.json --- funding.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 funding.json diff --git a/funding.json b/funding.json deleted file mode 100644 index 5d0fede..0000000 --- a/funding.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "opRetro": { - "projectId": "0x7504e494cb8d227193182e083128912173c14eaeecec9b90fa453de28377b269" - } -} From a0bc3ba63f14f20f05d3291f1ce1431a6bf88f3b Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Tue, 22 Apr 2025 18:38:06 +0200 Subject: [PATCH 02/65] filecoin support: initial commit --- cmd/hermes/cmd.go | 1 + cmd/hermes/cmd_fil.go | 177 ++++++++++++++++++++++++ eth/node_config.go | 2 +- fil/node.go | 260 +++++++++++++++++++++++++++++++++++ fil/node_config.go | 309 ++++++++++++++++++++++++++++++++++++++++++ fil/node_notifiee.go | 71 ++++++++++ fil/pubsub.go | 100 ++++++++++++++ host/pubsub.go | 1 + 8 files changed, 920 insertions(+), 1 deletion(-) create mode 100644 cmd/hermes/cmd_fil.go create mode 100644 fil/node.go create mode 100644 fil/node_config.go create mode 100644 fil/node_notifiee.go create mode 100644 fil/pubsub.go diff --git a/cmd/hermes/cmd.go b/cmd/hermes/cmd.go index 0b0515a..76c154b 100644 --- a/cmd/hermes/cmd.go +++ b/cmd/hermes/cmd.go @@ -99,6 +99,7 @@ var app = &cli.App{ Before: rootBefore, Commands: []*cli.Command{ cmdEth, + cmdFil, cmdBenchmark, }, After: rootAfter, diff --git a/cmd/hermes/cmd_fil.go b/cmd/hermes/cmd_fil.go new file mode 100644 index 0000000..49ea558 --- /dev/null +++ b/cmd/hermes/cmd_fil.go @@ -0,0 +1,177 @@ +package main + +import ( + "encoding/json" + "fmt" + "log/slog" + "time" + + "github.com/libp2p/go-libp2p/core/peer" + + "github.com/probe-lab/hermes/fil" + + "github.com/urfave/cli/v2" + "go.opentelemetry.io/otel" + + "github.com/probe-lab/hermes/host" + "github.com/probe-lab/hermes/tele" +) + +var filConfig = &struct { + PrivateKeyStr string + Libp2pHost string + Libp2pPort int + Libp2pPeerscoreSnapshotFreq time.Duration + BootrapperMaddrs *cli.StringSlice + DialConcurrency int + DialTimeout time.Duration +}{ + PrivateKeyStr: "", // unset means it'll be generated + Libp2pHost: "127.0.0.1", + Libp2pPort: 0, + Libp2pPeerscoreSnapshotFreq: 60 * time.Second, + BootrapperMaddrs: cli.NewStringSlice(), + DialConcurrency: 16, + DialTimeout: 5 * time.Second, +} + +var cmdFil = &cli.Command{ + Name: "fil", + Aliases: []string{"filecoin"}, + Usage: "Listen to gossipsub topics of the Filecoin network", + Flags: cmdFilFlags, + Action: cmdFilAction, + Before: cmdFilBefore, +} + +var cmdFilFlags = []cli.Flag{ + &cli.StringFlag{ + Name: "key", + Aliases: []string{"k"}, + EnvVars: []string{"HERMES_FIL_KEY"}, + Usage: "The private key for the hermes libp2p/ethereum node in hex format.", + Value: filConfig.PrivateKeyStr, + Destination: &filConfig.PrivateKeyStr, + Action: validateKeyFlag, + }, + &cli.IntFlag{ + Name: "dial.concurrency", + EnvVars: []string{"HERMES_FIL_DIAL_CONCURRENCY"}, + Usage: "The maximum number of parallel workers dialing other peers in the network", + Value: filConfig.DialConcurrency, + Destination: &filConfig.DialConcurrency, + }, + &cli.DurationFlag{ + Name: "dial.timeout", + EnvVars: []string{"HERMES_FIL_DIAL_TIMEOUT"}, + Usage: "The request timeout when contacting other network participants", + Value: filConfig.DialTimeout, + Destination: &filConfig.DialTimeout, + }, + &cli.StringFlag{ + Name: "libp2p.host", + EnvVars: []string{"HERMES_FIL_LIBP2P_HOST"}, + Usage: "Which network interface should libp2p bind to.", + Value: filConfig.Libp2pHost, + Destination: &filConfig.Libp2pHost, + }, + &cli.IntFlag{ + Name: "libp2p.port", + EnvVars: []string{"HERMES_FIL_LIBP2P_PORT"}, + Usage: "On which port should libp2p (disv5) listen", + Value: filConfig.Libp2pPort, + Destination: &filConfig.Libp2pPort, + DefaultText: "random", + }, + &cli.StringSliceFlag{ + Name: "bootstrappers", + EnvVars: []string{"HERMES_FIL_BOOTSTRAPPERS"}, + Usage: "The peer multi addresses to use for connecting to the Filecoin network", + Value: filConfig.BootrapperMaddrs, + Destination: filConfig.BootrapperMaddrs, + DefaultText: "mainnet", + }, + &cli.DurationFlag{ + Name: "libp2p.peerscore.snapshot.frequency", + EnvVars: []string{"HERMES_FIL_LIBP2P_PEERSCORE_SNAPSHOT_FREQUENCY"}, + Usage: "Frequency at which GossipSub peerscores will be accessed (in seconds)", + Value: filConfig.Libp2pPeerscoreSnapshotFreq, + Destination: &filConfig.Libp2pPeerscoreSnapshotFreq, + DefaultText: "random", + }, +} + +func cmdFilBefore(c *cli.Context) error { + if !c.IsSet("bootstrappers") { + filConfig.BootrapperMaddrs = cli.NewStringSlice( + "/dns/node.glif.io/tcp/1235/p2p/12D3KooWBF8cpp65hp2u9LK5mh19x67ftAam84z9LsfaquTDSBpt", + "/dns/bootstrap-venus.mainnet.filincubator.com/tcp/8888/p2p/QmQu8C6deXwKvJP2D8B6QGyhngc3ZiDnFzEHBDx8yeBXST", + "/dns/bootstrap-mainnet-0.chainsafe-fil.io/tcp/34000/p2p/12D3KooWKKkCZbcigsWTEu1cgNetNbZJqeNtysRtFpq7DTqw3eqH", + "/dns/bootstrap-mainnet-1.chainsafe-fil.io/tcp/34000/p2p/12D3KooWGnkd9GQKo3apkShQDaq1d6cKJJmsVe6KiQkacUk1T8oZ", + "/dns/bootstrap-mainnet-2.chainsafe-fil.io/tcp/34000/p2p/12D3KooWHQRSDFv4FvAjtU32shQ7znz7oRbLBryXzZ9NMK2feyyH", + "/dns/n1.mainnet.fil.devtty.eu/udp/443/quic-v1/p2p/12D3KooWAke3M2ji7tGNKx3BQkTHCyxVhtV1CN68z6Fkrpmfr37F", + "/dns/n1.mainnet.fil.devtty.eu/tcp/443/p2p/12D3KooWAke3M2ji7tGNKx3BQkTHCyxVhtV1CN68z6Fkrpmfr37F", + "/dns/n1.mainnet.fil.devtty.eu/udp/443/quic-v1/webtransport/certhash/uEiAWlgd8EqbNhYLv86OdRvXHMosaUWFFDbhgGZgCkcmKnQ/certhash/uEiAvtq6tvZOZf_sIuityDDTyAXDJPfXSRRDK2xy9UVPsqA/p2p/12D3KooWAke3M2ji7tGNKx3BQkTHCyxVhtV1CN68z6Fkrpmfr37F", + ) + } + + return nil +} + +func cmdFilAction(c *cli.Context) error { + slog.Info("Starting Hermes for Filecoin...") + defer slog.Info("Stopped Hermes for Filecoin.") + + // Print hermes configuration for debugging purposes + printFilConfig() + + bootstrappers := make([]peer.AddrInfo, len(filConfig.BootrapperMaddrs.Value())) + for i, maddrStr := range filConfig.BootrapperMaddrs.Value() { + bp, err := peer.AddrInfoFromString(maddrStr) + if err != nil { + slog.Warn("Failed parsing bootstrapper multiaddress", slog.String("maddr", maddrStr), tele.LogAttrError(err)) + continue + } + bootstrappers[i] = *bp + } + + cfg := &fil.NodeConfig{ + PrivateKeyStr: filConfig.PrivateKeyStr, + DialTimeout: filConfig.DialTimeout, + Libp2pHost: filConfig.Libp2pHost, + Libp2pPort: filConfig.Libp2pPort, + Libp2pPeerscoreSnapshotFreq: filConfig.Libp2pPeerscoreSnapshotFreq, + Bootstrappers: bootstrappers, + DataStreamType: host.DataStreamtypeFromStr(rootConfig.DataStreamType), + AWSConfig: rootConfig.awsConfig, + S3Config: rootConfig.s3Config, + KinesisRegion: rootConfig.KinesisRegion, + KinesisStream: rootConfig.KinesisStream, + DialConcurrency: filConfig.DialConcurrency, + Tracer: otel.GetTracerProvider().Tracer("hermes"), + Meter: otel.GetMeterProvider().Meter("hermes"), + } + + n, err := fil.NewNode(cfg) + if err != nil { + return fmt.Errorf("new node: %w", err) + } + + return n.Start(c.Context) +} + +func printFilConfig() { + cfgCopy := *filConfig + if cfgCopy.PrivateKeyStr != "" { + cfgCopy.PrivateKeyStr = "***" + } + + dat, err := json.Marshal(cfgCopy) + if err != nil { + slog.Warn("Failed marshalling eth config struct", tele.LogAttrError(err)) + return + } + + slog.Info("Config:") + slog.Info(string(dat)) +} diff --git a/eth/node_config.go b/eth/node_config.go index 27be5fc..a7968ee 100644 --- a/eth/node_config.go +++ b/eth/node_config.go @@ -145,7 +145,7 @@ func (n *NodeConfig) Validate() error { } if n.Libp2pPort < 0 { - return fmt.Errorf("libp2p port must be greater than or equal to 0, got %d", n.Devp2pPort) + return fmt.Errorf("libp2p port must be greater than or equal to 0, got %d", n.Libp2pPort) } if n.Libp2pPeerscoreSnapshotFreq < 0 { diff --git a/fil/node.go b/fil/node.go new file mode 100644 index 0000000..e728ba9 --- /dev/null +++ b/fil/node.go @@ -0,0 +1,260 @@ +package fil + +import ( + "context" + "errors" + "fmt" + "log/slog" + "sync" + "sync/atomic" + "time" + + "github.com/aws/aws-sdk-go-v2/service/kinesis" + gk "github.com/dennis-tra/go-kinesis" + "github.com/thejerf/suture/v4" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" + + "github.com/probe-lab/hermes/host" + "github.com/probe-lab/hermes/tele" +) + +// Node is the main entry point to listening to the Ethereum GossipSub mesh. +type Node struct { + // The configuration that's passed in externally + cfg *NodeConfig + + // The libp2p host, however, this is a custom Hermes wrapper host. + host *host.Host + + // The data stream to which we transmit data + ds host.DataStream + + // The PubSub service that implements various gossipsub topics + pubSub *PubSub + + // The suture supervisor that is the root of the service tree + sup *suture.Supervisor + + // eventCallbacks contains a list of callbacks that are executed when an event is received + eventCallbacks []func(ctx context.Context, event *host.TraceEvent) +} + +// NewNode initializes a new [Node] using the provided configuration. +// It first validates the node configuration. Then it initializes the libp2p +// host using the libp2p options from the given configuration object. Next, it +// initializes the Ethereum node by extracting the ECDSA private key, +// creating a new discovery service, creating a new ReqResp server, +// creating a new PubSub server, and creating a new Prysm client. +// Finally, it initializes the Hermes node by setting the configuration and +// dependencies. +func NewNode(cfg *NodeConfig) (*Node, error) { + if err := cfg.Validate(); err != nil { + return nil, fmt.Errorf("node config validation failed: %w", err) + } + + var ds host.DataStream + switch cfg.DataStreamType { + case host.DataStreamTypeLogger: + ds = new(host.TraceLogger) + + case host.DataStreamTypeKinesis: + droppedTraces, err := cfg.Meter.Int64Counter("dropped_traces") + if err != nil { + return nil, fmt.Errorf("new dropped_traces counter: %w", err) + } + + notifiee := &gk.NotifieeBundle{ + DroppedRecordF: func(ctx context.Context, record gk.Record) { + tevt, ok := record.(*host.TraceEvent) + if !ok { + droppedTraces.Add(ctx, 1, metric.WithAttributes(attribute.String("evt_type", "UNKNOWN"))) + } else { + droppedTraces.Add(ctx, 1, metric.WithAttributes(attribute.String("evt_type", tevt.Type))) + } + slog.Warn("Dropped record", "partition_key", record.PartitionKey(), "size", len(record.Data())) + }, + } + + pcfg := gk.DefaultProducerConfig() + pcfg.Log = slog.Default() + pcfg.Meter = cfg.Meter + pcfg.Notifiee = notifiee + pcfg.RetryLimit = 5 + + p, err := gk.NewProducer(kinesis.NewFromConfig(*cfg.AWSConfig), cfg.KinesisStream, pcfg) + if err != nil { + return nil, fmt.Errorf("new kinesis producer: %w", err) + } + + ds = host.NewKinesisDataStream(p) + + case host.DataStreamTypeCallback: + ds = host.NewCallbackDataStream() + + case host.DataStreamTypeS3: + // get the metrics tracer and meter from the root config + cfg.S3Config.Meter = cfg.Meter + var err error + ds, err = host.NewS3DataStream(*cfg.S3Config) + if err != nil { + return nil, fmt.Errorf("new s3 producer %w", err) + } + default: + return nil, fmt.Errorf("not recognised data-stream (%s)", cfg.DataStreamType) + } + + hostCfg := &host.Config{ + DataStream: ds, + PeerscoreSnapshotFreq: cfg.Libp2pPeerscoreSnapshotFreq, + Tracer: cfg.Tracer, + Meter: cfg.Meter, + } + + // initialize libp2p host + opts, err := cfg.libp2pOptions() + if err != nil { + return nil, fmt.Errorf("build libp2p options: %w", err) + } + + h, err := host.New(hostCfg, opts...) + if err != nil { + return nil, fmt.Errorf("new libp2p host: %w", err) + } + slog.Info("Initialized new libp2p Host", tele.LogAttrPeerID(h.ID()), "maddrs", h.Addrs()) + + // initialize the pubsub topic handlers + pubSubConfig := &PubSubConfig{ + Topics: []string{ + "/drand/pubsub/v0.0.0/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971", + "/drand/pubsub/v0.0.0/80c8b872c714f4c00fdd3daa465d5514049f457f01f85a4caf68cdcd394ba039", + "/drand/pubsub/v0.0.0/8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce", + "/f3/chainexchange/0.0.1/filecoin/62", + "/f3/granite/0.0.3/filecoin/62", + "/f3/manifests/0.0.1", + "/f3/manifests/0.0.2", + "/fil/blocks/testnetnet", + "/fil/msgs/testnetnet", + "/indexer/ingest/mainnet", + }, + } + + pubSub, err := NewPubSub(h, pubSubConfig) + if err != nil { + return nil, fmt.Errorf("new PubSub service: %w", err) + } + + // finally, initialize hermes node + n := &Node{ + cfg: cfg, + host: h, + ds: ds, + pubSub: pubSub, + sup: suture.NewSimple("fil"), + } + + if ds.Type() == host.DataStreamTypeCallback { + cbDs := ds.(*host.CallbackDataStream) + + cbDs.OnEvent(func(ctx context.Context, event *host.TraceEvent) { + for _, cb := range n.eventCallbacks { + cb(ctx, event) + } + }) + } + return n, nil +} + +// OnEvent registers a callback that is executed when an event is received. +func (n *Node) OnEvent(cb func(ctx context.Context, event *host.TraceEvent)) { + n.eventCallbacks = append(n.eventCallbacks, cb) +} + +// Start starts the listening process. +func (n *Node) Start(ctx context.Context) error { + defer logDeferErr(n.host.Close, "Failed closing libp2p host") + + dsCleanupFn, err := n.startDataStream(ctx) + if err != nil { + return fmt.Errorf("failed starting data stream producer: %w", err) + } + defer dsCleanupFn() + + // initialize GossipSub + n.pubSub.gs, err = n.host.InitGossipSub(ctx, n.cfg.pubsubOptions(n)...) + if err != nil { + return fmt.Errorf("init gossip sub: %w", err) + } + + // register the node itself as the notifiee for network connection events + n.host.Network().Notify(n) + + // start the pubsub subscriptions and handlers + n.sup.Add(n.pubSub) + + // start the hermes host to trace gossipsub messages + n.sup.Add(n.host) + + // connect to bootstrappers + timeoutCtx, timeoutCancel := context.WithTimeout(ctx, 5*time.Second) + defer timeoutCancel() + + var wg sync.WaitGroup + var errCounter atomic.Int32 + for _, p := range n.cfg.Bootstrappers { + wg.Add(1) + go func() { + defer wg.Done() + if err := n.host.Connect(timeoutCtx, p); err != nil { + slog.Warn("Failed to connect to bootstrapper", tele.LogAttrError(err), "peer", p) + errCounter.Add(1) + } + }() + } + wg.Wait() + + if errCounter.Load() == int32(len(n.cfg.Bootstrappers)) { + return fmt.Errorf("failed to connect to all bootstrappers") + } + + // start all long-running services + return n.sup.Serve(ctx) +} + +// logDeferErr executes the given function and logs the given error message +// in case of an error. +func logDeferErr(fn func() error, onErrMsg string) { + if err := fn(); err != nil && !errors.Is(err, context.Canceled) { + slog.Warn(onErrMsg, tele.LogAttrError(err)) + } +} + +// terminateSupervisorTreeOnErr can be used like +// +// defer func() { err = terminateSupervisorTreeOnErr(err) }() +// +// to instruct the suture supervisor to terminate the supervisor tree if +// the surrounding function returns an error. +func terminateSupervisorTreeOnErr(err error) error { + if err != nil { + return fmt.Errorf("%s: %w", err, suture.ErrTerminateSupervisorTree) + } + return nil +} + +// startDataStream starts the data stream and implements a graceful shutdown +func (n *Node) startDataStream(ctx context.Context) (func(), error) { + backgroundCtx := context.Background() + + go func() { + if err := n.ds.Start(backgroundCtx); err != nil { + slog.Warn("Failed to start data stream", tele.LogAttrError(err)) + } + }() + + cleanupFn := func() { + n.ds.Stop(ctx) + } + + return cleanupFn, nil +} diff --git a/fil/node_config.go b/fil/node_config.go new file mode 100644 index 0000000..c5ffb70 --- /dev/null +++ b/fil/node_config.go @@ -0,0 +1,309 @@ +package fil + +import ( + "crypto/ecdsa" + "crypto/rand" + "encoding/hex" + "fmt" + "log/slog" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/decred/dcrd/dcrec/secp256k1/v4" + gcrypto "github.com/ethereum/go-ethereum/crypto" + "github.com/libp2p/go-libp2p" + pubsub "github.com/libp2p/go-libp2p-pubsub" + pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/trace" + "golang.org/x/crypto/blake2b" + + "github.com/probe-lab/hermes/host" +) + +type NodeConfig struct { + // The private key for the libp2p host and local enode in hex format + PrivateKeyStr string + + Bootstrappers []peer.AddrInfo + + // The parsed private key as an unexported field. This is used to cache the + // parsing result, so that [PrivateKey] can be called multiple times without + // regenerating the key over and over again. + privateKey *crypto.Secp256k1PrivateKey + + // General timeout when communicating with other network participants + DialTimeout time.Duration + + // The address information of the local libp2p host + Libp2pHost string + Libp2pPort int + Libp2pPeerscoreSnapshotFreq time.Duration + + // The Data Stream configuration + DataStreamType host.DataStreamType + AWSConfig *aws.Config + S3Config *host.S3DSConfig + KinesisRegion string + KinesisStream string + + // Limits the number of concurrent connection establishment routines. When + // we discover peers over discv5 and are not at our MaxPeers limit we try + // to establish a connection to a peer. However, we limit the concurrency to + // this DialConcurrency value. + DialConcurrency int + + // Telemetry accessors + Tracer trace.Tracer + Meter metric.Meter +} + +// Validate validates the [NodeConfig] [Node] configuration. +func (n *NodeConfig) Validate() error { + if _, err := n.PrivateKey(); err != nil { + return err + } + + if n.DialTimeout <= 0 { + return fmt.Errorf("dial timeout must be positive") + } + + if n.Libp2pPort < 0 { + return fmt.Errorf("libp2p port must be greater than or equal to 0, got %d", n.Libp2pPort) + } + + if len(n.Bootstrappers) == 0 { + return fmt.Errorf("no valid bootstrapper multiaddresses provided, please check the --bootstrappers flag") + } + + if n.DialConcurrency <= 0 { + return fmt.Errorf("dialer count must be positive, got %d", n.DialConcurrency) + } + + // ensure that if the data stream is AWS, the parameters where given + if n.DataStreamType == host.DataStreamTypeKinesis { + if n.AWSConfig != nil { + if n.KinesisStream == "" { + return fmt.Errorf("kinesis is enabled but stream is not set") + } + + if n.KinesisRegion == "" { + return fmt.Errorf("kinesis is enabled but region is not set") + } + } + } + + if n.DataStreamType == host.DataStreamTypeS3 { + if n.S3Config != nil { + // we should have caught the error at the root_cmd, but still adding it here + if err := n.S3Config.CheckValidity(); err != nil { + return fmt.Errorf("s3 trace submission is enabled but no valid config was given %w", err) + } + } else { + return fmt.Errorf("s3 configuration is empty") + } + } + + if n.Tracer == nil { + return fmt.Errorf("tracer must not be nil") + } + + if n.Meter == nil { + return fmt.Errorf("meter must not be nil") + } + + return nil +} + +// PrivateKey returns a parsed Secp256k1 private key from the given +// PrivateKeyStr. If that's unset, a new one will be generated. In any case, +// the result will be cached, so that the private key won't be generated twice. +func (n *NodeConfig) PrivateKey() (*crypto.Secp256k1PrivateKey, error) { + if n.privateKey != nil { + return n.privateKey, nil + } + + var err error + var privBytes []byte + if n.PrivateKeyStr == "" { + slog.Debug("Generating new private key") + key, err := ecdsa.GenerateKey(gcrypto.S256(), rand.Reader) + if err != nil { + return nil, fmt.Errorf("failed to generate key: %w", err) + } + + privBytes = gcrypto.FromECDSA(key) + if len(privBytes) != secp256k1.PrivKeyBytesLen { + return nil, fmt.Errorf("expected secp256k1 data size to be %d", secp256k1.PrivKeyBytesLen) + } + } else { + privBytes, err = hex.DecodeString(n.PrivateKeyStr) + if err != nil { + return nil, fmt.Errorf("failed to decode private key: %w", err) + } + } + + n.privateKey = (*crypto.Secp256k1PrivateKey)(secp256k1.PrivKeyFromBytes(privBytes)) + + if n.PrivateKeyStr == "" { + n.PrivateKeyStr = hex.EncodeToString(privBytes) + } + + return n.privateKey, nil +} + +// ECDSAPrivateKey returns the ECDSA private key associated with the [NodeConfig]. +// It retrieves the private key using the PrivateKey method and then converts it +// to ECDSA format. If there is an error retrieving the private key or +// converting it to ECDSA format, an error is returned. +func (n *NodeConfig) ECDSAPrivateKey() (*ecdsa.PrivateKey, error) { + privKey, err := n.PrivateKey() + if err != nil { + return nil, fmt.Errorf("private key: %w", err) + } + data, err := privKey.Raw() + if err != nil { + return nil, fmt.Errorf("get raw bytes from private key: %w", err) + } + + return gcrypto.ToECDSA(data) +} + +// libp2pOptions returns the options to configure the libp2p node. It retrieves +// the private key, constructs the libp2p listen multiaddr based on the node +// configuration. The options include setting the identity with the private key, +// adding the listen address, setting the user agent to "hermes", +// using only the TCP transport, enabling the Mplex multiplexer explicitly (this +// is required by the specs). +func (n *NodeConfig) libp2pOptions() ([]libp2p.Option, error) { + privKey, err := n.PrivateKey() + if err != nil { + return nil, fmt.Errorf("get private key: %w", err) + } + + listenMaddr, err := host.MaddrFrom(n.Libp2pHost, uint(n.Libp2pPort)) + if err != nil { + return nil, fmt.Errorf("construct libp2p listen maddr: %w", err) + } + + str, err := rcmgr.NewStatsTraceReporter() + if err != nil { + return nil, err + } + + rmgr, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(rcmgr.DefaultLimits.AutoScale()), rcmgr.WithTraceReporter(str)) + if err != nil { + return nil, err + } + + opts := []libp2p.Option{ + libp2p.Identity(privKey), + libp2p.ListenAddrs(listenMaddr), + libp2p.UserAgent("hermes"), + libp2p.DisableRelay(), + libp2p.Ping(true), + libp2p.ResourceManager(rmgr), + libp2p.DisableMetrics(), + } + return opts, nil +} + +func (n *NodeConfig) pubsubOptions(subFilter pubsub.SubscriptionFilter) []pubsub.Option { + //drandTopicParams := &pubsub.TopicScoreParams{ + // TopicWeight: 0.5, // 5x block topic; max cap is 62.5 + // TimeInMeshWeight: 0.00027, // ~1/3600 + // TimeInMeshQuantum: time.Second, + // TimeInMeshCap: 1, + // FirstMessageDeliveriesWeight: 5, // max value is 125 + // FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + // FirstMessageDeliveriesCap: 25, // the maximum expected in an hour is ~26, including the decay + // InvalidMessageDeliveriesWeight: -1000, + // InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + //} + + topicParams := map[string]*pubsub.TopicScoreParams{ + "/fil/blocks/mainnet": { + TopicWeight: 0.1, // max cap is 50, max mesh penalty is -10, single invalid message is -100 + TimeInMeshWeight: 0.00027, // ~1/3600 + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 1, + FirstMessageDeliveriesWeight: 5, // max value is 500 + FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + FirstMessageDeliveriesCap: 100, // 100 blocks in an hour + InvalidMessageDeliveriesWeight: -1000, + InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + }, + "/fil/msgs/mainnet": { + TopicWeight: 0.1, // max cap is 5, single invalid message is -100 + TimeInMeshWeight: 0.0002778, // ~1/3600 + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 1, + FirstMessageDeliveriesWeight: 0.5, // max value is 50 + FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(10 * time.Minute), + FirstMessageDeliveriesCap: 100, // 100 messages in 10 minutes + InvalidMessageDeliveriesWeight: -1000, + InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + }, + } + + const ( + GossipScoreThreshold = -500 + PublishScoreThreshold = -1000 + GraylistScoreThreshold = -2500 + AcceptPXScoreThreshold = 1000 + OpportunisticGraftScoreThreshold = 3.5 + ) + + psOpts := []pubsub.Option{ + // pubsub.WithMessageSignaturePolicy(pubsub.StrictSign), + // pubsub.WithNoAuthor(), + pubsub.WithMessageIdFn(func(pmsg *pubsubpb.Message) string { + hash := blake2b.Sum256(pmsg.Data) + return string(hash[:]) + }), + pubsub.WithSubscriptionFilter(subFilter), + pubsub.WithPeerScore( + &pubsub.PeerScoreParams{ + AppSpecificScore: func(p peer.ID) float64 { + // return a heavy positive score for bootstrappers so that we don't unilaterally prune + // them and accept PX from them. + // we don't do that in the bootstrappers themselves to avoid creating a closed mesh + // between them (however we might want to consider doing just that) + //_, ok := bootstrappers[p] + //if ok && !isBootstrapNode { + // return 2500 + //} + // + //_, ok = drandBootstrappers[p] + //if ok && !isBootstrapNode { + // return 1500 + //} + + return 0 + }, + AppSpecificWeight: 1, + IPColocationFactorThreshold: 5, + IPColocationFactorWeight: -100, + BehaviourPenaltyThreshold: 6, + BehaviourPenaltyWeight: -10, + BehaviourPenaltyDecay: pubsub.ScoreParameterDecay(time.Hour), + + DecayInterval: pubsub.DefaultDecayInterval, + DecayToZero: pubsub.DefaultDecayToZero, + RetainScore: 6 * time.Hour, + Topics: topicParams, + }, + &pubsub.PeerScoreThresholds{ + GossipThreshold: GossipScoreThreshold, + PublishThreshold: PublishScoreThreshold, + GraylistThreshold: GraylistScoreThreshold, + AcceptPXThreshold: AcceptPXScoreThreshold, + OpportunisticGraftThreshold: OpportunisticGraftScoreThreshold, + }, + ), + } + return psOpts +} diff --git a/fil/node_notifiee.go b/fil/node_notifiee.go new file mode 100644 index 0000000..3abc0ea --- /dev/null +++ b/fil/node_notifiee.go @@ -0,0 +1,71 @@ +package fil + +import ( + "log/slog" + "strings" + "time" + + "github.com/libp2p/go-libp2p/core/network" + "github.com/libp2p/go-libp2p/core/peer" + ma "github.com/multiformats/go-multiaddr" + "github.com/probe-lab/hermes/tele" +) + +const ( + peerstoreKeyConnectedAt = "connected_at" + peerstoreKeyIsHandshaked = "is_handshaked" +) + +// The Hermes Ethereum [Node] implements the [network.Notifiee] interface. +// This means it will be notified about new connections. +var _ network.Notifiee = (*Node)(nil) + +func (n *Node) Connected(net network.Network, c network.Conn) { + slog.Debug("Connected with peer", tele.LogAttrPeerID(c.RemotePeer()), "total", len(n.host.Network().Peers()), "dir", c.Stat().Direction) + + if err := n.host.Peerstore().Put(c.RemotePeer(), peerstoreKeyConnectedAt, time.Now()); err != nil { + slog.Warn("Failed to store connection timestamp in peerstore", tele.LogAttrError(err)) + } + + if c.Stat().Direction == network.DirOutbound { + // handle the new connection by validating the peer. Needs to happen in a + // go routine because Connected is called synchronously. + go n.handleNewConnection(c.RemotePeer()) + } +} + +func (n *Node) Disconnected(net network.Network, c network.Conn) { + if !c.Stat().Opened.IsZero() { + av := n.host.AgentVersion(c.RemotePeer()) + parts := strings.Split(av, "/") + if len(parts) > 0 { + switch strings.ToLower(parts[0]) { + case "prysm", "lighthouse", "nimbus", "lodestar", "grandine", "teku", "erigon": + av = strings.ToLower(parts[0]) + default: + av = "other" + } + } else { + av = "unknown" + } + // n.connAge.Record(context.TODO(), time.Since(c.Stat().Opened).Seconds(), metric.WithAttributes(attribute.String("agent", av))) + } + + ps := n.host.Peerstore() + if _, err := ps.Get(c.RemotePeer(), peerstoreKeyIsHandshaked); err == nil { + if val, err := ps.Get(c.RemotePeer(), peerstoreKeyConnectedAt); err == nil { + slog.Info("Disconnected from handshaked peer", tele.LogAttrPeerID(c.RemotePeer())) + // n.connDurHist.Record(context.Background(), time.Since(val.(time.Time)).Hours()) + _ = val + } + } +} + +func (n *Node) Listen(net network.Network, maddr ma.Multiaddr) {} + +func (n *Node) ListenClose(net network.Network, maddr ma.Multiaddr) {} + +// handleNewConnection validates the newly established connection to the given +// peer. +func (n *Node) handleNewConnection(pid peer.ID) { +} diff --git a/fil/pubsub.go b/fil/pubsub.go new file mode 100644 index 0000000..da00cd3 --- /dev/null +++ b/fil/pubsub.go @@ -0,0 +1,100 @@ +package fil + +import ( + "context" + "fmt" + "log/slog" + + pubsub "github.com/libp2p/go-libp2p-pubsub" + pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/thejerf/suture/v4" + + "github.com/probe-lab/hermes/host" +) + +type PubSubConfig struct { + Topics []string +} + +func (p PubSubConfig) Validate() error { + return nil +} + +type PubSub struct { + host *host.Host + cfg *PubSubConfig + gs *pubsub.PubSub +} + +func NewPubSub(h *host.Host, cfg *PubSubConfig) (*PubSub, error) { + if err := cfg.Validate(); err != nil { + return nil, fmt.Errorf("validate configuration: %w", err) + } + + return &PubSub{ + host: h, + cfg: cfg, + }, nil +} + +func (p *PubSub) Serve(ctx context.Context) error { + if p.gs == nil { + return fmt.Errorf("node's pubsub service uninitialized gossip sub: %w", suture.ErrTerminateSupervisorTree) + } + + supervisor := suture.NewSimple("pubsub") + + for _, topicName := range p.cfg.Topics { + topic, err := p.gs.Join(topicName) + if err != nil { + return fmt.Errorf("join pubsub topic %s: %w", topicName, err) + } + defer logDeferErr(topic.Close, fmt.Sprintf("failed closing %s topic", topicName)) + + // get the handler for the specific topic + topicHandler := p.mapPubSubTopicWithHandlers(topicName) + + sub, err := topic.Subscribe() + if err != nil { + return fmt.Errorf("subscribe to pubsub topic %s: %w", topicName, err) + } + + ts := &host.TopicSubscription{ + Topic: topicName, + LocalID: p.host.ID(), + Sub: sub, + Handler: topicHandler, + } + + supervisor.Add(ts) + } + + return supervisor.Serve(ctx) +} + +func (p *PubSub) mapPubSubTopicWithHandlers(topic string) host.TopicHandler { + switch { + default: + return func(ctx context.Context, msg *pubsub.Message) error { + slog.Info("Handle", slog.String("topic", msg.GetTopic())) + return nil + } + + return p.host.TracedTopicHandler(host.NoopHandler) + } +} + +var _ pubsub.SubscriptionFilter = (*Node)(nil) + +// CanSubscribe originally returns true if the topic is of interest, and we could subscribe to it. +func (n *Node) CanSubscribe(topic string) bool { + return true +} + +// FilterIncomingSubscriptions is invoked for all RPCs containing subscription notifications. +// This method returns only the topics of interest and may return an error if the subscription +// request contains too many topics. +func (n *Node) FilterIncomingSubscriptions(id peer.ID, subs []*pubsubpb.RPC_SubOpts) ([]*pubsubpb.RPC_SubOpts, error) { + return pubsub.FilterSubscriptions(subs, n.CanSubscribe), nil +} diff --git a/host/pubsub.go b/host/pubsub.go index b702a7a..b6061cd 100644 --- a/host/pubsub.go +++ b/host/pubsub.go @@ -39,6 +39,7 @@ func (t *TopicSubscription) Serve(ctx context.Context) error { return fmt.Errorf("failed to read next gossip message for topic %s: %w", t.Sub.Topic(), err) } + slog.Error("MESSAGE!") // check if it's our own event if msg.ReceivedFrom == t.LocalID { From 4867ad2fdc3f5a25f2a66862c54b3d562829fbac Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Wed, 23 Apr 2025 12:16:07 +0200 Subject: [PATCH 03/65] filecoin: parse gossipsub messages --- cmd/hermes/cmd_fil.go | 4 +- eth/node.go | 2 +- fil/discovery.go | 87 +++++++ fil/node.go | 96 ++++++++ fil/node_config.go | 1 + fil/node_notifiee.go | 36 +-- fil/pubsub.go | 141 ++++++++++- go.mod | 134 ++++++---- go.sum | 555 ++++++++++++++++++++++++++++++++++-------- host/pubsub.go | 1 - 10 files changed, 875 insertions(+), 182 deletions(-) create mode 100644 fil/discovery.go diff --git a/cmd/hermes/cmd_fil.go b/cmd/hermes/cmd_fil.go index 49ea558..ae5ce67 100644 --- a/cmd/hermes/cmd_fil.go +++ b/cmd/hermes/cmd_fil.go @@ -7,12 +7,10 @@ import ( "time" "github.com/libp2p/go-libp2p/core/peer" - - "github.com/probe-lab/hermes/fil" - "github.com/urfave/cli/v2" "go.opentelemetry.io/otel" + "github.com/probe-lab/hermes/fil" "github.com/probe-lab/hermes/host" "github.com/probe-lab/hermes/tele" ) diff --git a/eth/node.go b/eth/node.go index ffeab2a..5a9c9fe 100644 --- a/eth/node.go +++ b/eth/node.go @@ -271,7 +271,7 @@ func (n *Node) initMetrics(cfg *NodeConfig) (err error) { return nil }, n.connCount) if err != nil { - return fmt.Errorf("register connectin_count gauge callback: %w", err) + return fmt.Errorf("register connection_count gauge callback: %w", err) } n.connBeacon, err = cfg.Meter.Int64ObservableGauge("beacon_connected", metric.WithDescription("Tracks the standing connection to our beacon node (1=connected, 0=disconnected)")) diff --git a/fil/discovery.go b/fil/discovery.go new file mode 100644 index 0000000..6a121b5 --- /dev/null +++ b/fil/discovery.go @@ -0,0 +1,87 @@ +package fil + +import ( + "context" + "errors" + "fmt" + "log/slog" + "time" + + kaddht "github.com/libp2p/go-libp2p-kad-dht" + "github.com/libp2p/go-libp2p/core/host" + "github.com/thejerf/suture/v4" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/trace" +) + +type DiscoveryConfig struct { + Tracer trace.Tracer + Meter metric.Meter +} + +type Discovery struct { + cfg *DiscoveryConfig + host host.Host + + // Metrics + MeterDiscoveredPeers metric.Int64Counter +} + +var _ suture.Service = (*Discovery)(nil) + +func NewDiscovery(h host.Host, cfg *DiscoveryConfig) (*Discovery, error) { + slog.Info("Initialize Discovery service") + + d := &Discovery{ + cfg: cfg, + host: h, + } + + var err error + d.MeterDiscoveredPeers, err = cfg.Meter.Int64Counter("discovered_peers", metric.WithDescription("Total number of discovered peers")) + if err != nil { + return nil, fmt.Errorf("discovered_peers counter: %w", err) + } + + return d, nil +} + +func (d *Discovery) Serve(ctx context.Context) (err error) { + slog.Info("Starting discv5 Discovery Service") + defer slog.Info("Stopped disv5 Discovery Service") + defer func() { err = terminateSupervisorTreeOnErr(err) }() + + opts := []kaddht.Option{ + kaddht.Mode(kaddht.ModeClient), + kaddht.V1ProtocolOverride("/fil/kad/testnetnet/kad/1.0.0"), // TODO: parameterize + } + + dht, err := kaddht.New(ctx, d.host, opts...) + if err != nil { + return fmt.Errorf("failed to create DHT: %w", err) + } + + for { + + k, err := dht.RoutingTable().GenRandomKey(0) + if err != nil { + return fmt.Errorf("failed to generate random key: %w", err) + } + start := time.Now() + slog.Info("NEW LOOKUP") + peers, err := dht.GetClosestPeers(ctx, string(k)) + if errors.Is(err, context.Canceled) { + return nil + } else if err != nil { + slog.Warn("error", "err", err) + } + slog.Info("Found peers", "peers", len(peers)) + + select { + case <-ctx.Done(): + return nil + case <-time.After(10*time.Second - time.Since(start)): + continue + } + } +} diff --git a/fil/node.go b/fil/node.go index e728ba9..c54995a 100644 --- a/fil/node.go +++ b/fil/node.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "log/slog" + "sort" "sync" "sync/atomic" "time" @@ -33,9 +34,18 @@ type Node struct { // The PubSub service that implements various gossipsub topics pubSub *PubSub + // The discovery service, periodically querying the discv5 DHT network + disc *Discovery + // The suture supervisor that is the root of the service tree sup *suture.Supervisor + // Metrics + connCount metric.Int64ObservableGauge + connDurHist metric.Float64Histogram + connAge metric.Float64Histogram + connMedianAge metric.Float64ObservableGauge + // eventCallbacks contains a list of callbacks that are executed when an event is received eventCallbacks []func(ctx context.Context, event *host.TraceEvent) } @@ -123,6 +133,15 @@ func NewNode(cfg *NodeConfig) (*Node, error) { } slog.Info("Initialized new libp2p Host", tele.LogAttrPeerID(h.ID()), "maddrs", h.Addrs()) + disc, err := NewDiscovery(h.Host, &DiscoveryConfig{ + Tracer: cfg.Tracer, + Meter: cfg.Meter, + }) + if err != nil { + return nil, fmt.Errorf("new discovery service: %w", err) + } + slog.Info("Initialized new discovery service") + // initialize the pubsub topic handlers pubSubConfig := &PubSubConfig{ Topics: []string{ @@ -137,6 +156,7 @@ func NewNode(cfg *NodeConfig) (*Node, error) { "/fil/msgs/testnetnet", "/indexer/ingest/mainnet", }, + DataStream: ds, } pubSub, err := NewPubSub(h, pubSubConfig) @@ -148,6 +168,7 @@ func NewNode(cfg *NodeConfig) (*Node, error) { n := &Node{ cfg: cfg, host: h, + disc: disc, ds: ds, pubSub: pubSub, sup: suture.NewSimple("fil"), @@ -162,9 +183,81 @@ func NewNode(cfg *NodeConfig) (*Node, error) { } }) } + + // initialize custom prometheus metrics + if err := n.initMetrics(cfg); err != nil { + return nil, fmt.Errorf("init metrics: %w", err) + } + return n, nil } +// initMetrics initializes various prometheus metrics and stores the meters +// on the [Node] object. +func (n *Node) initMetrics(cfg *NodeConfig) (err error) { + n.connDurHist, err = cfg.Meter.Float64Histogram( + "connection_duration_min", + metric.WithExplicitBucketBoundaries(0.5, 1, 5, 10, 50, 100, 500, 1000), + ) + if err != nil { + return fmt.Errorf("new connection_duration_min histogram: %w", err) + } + + n.connCount, err = cfg.Meter.Int64ObservableGauge("connection_count") + if err != nil { + return fmt.Errorf("new connection_count gauge: %w", err) + } + + _, err = cfg.Meter.RegisterCallback(func(ctx context.Context, obs metric.Observer) error { + obs.ObserveInt64(n.connCount, int64(len(n.host.Network().Peers()))) + return nil + }, n.connCount) + if err != nil { + return fmt.Errorf("register connection_count gauge callback: %w", err) + } + + n.connAge, err = cfg.Meter.Float64Histogram("conn_age", metric.WithDescription("Connection age after disconnect in seconds"), metric.WithUnit("s")) + if err != nil { + return fmt.Errorf("new conn_age histogram: %w", err) + } + + n.connMedianAge, err = cfg.Meter.Float64ObservableGauge("conn_median_age", metric.WithDescription("The median age of all currently active connections"), metric.WithUnit("s")) + if err != nil { + return fmt.Errorf("new conn_median_age gauge: %w", err) + } + _, err = cfg.Meter.RegisterCallback(func(ctx context.Context, obs metric.Observer) error { + // get a reference to all connections + conns := n.host.Network().Conns() + if len(conns) == 0 { + // don't measure anything if we have no active connection + return nil + } + + // calculate connection ages in seconds + ages := make([]float64, len(conns)) + for i, conn := range conns { + ages[i] = time.Since(conn.Stat().Opened).Seconds() + } + + // calculate median + sort.Float64s(ages) + + if len(ages)%2 == 0 { + lo, hi := ages[(len(ages)-1)/2], ages[len(ages)/2] + obs.ObserveFloat64(n.connMedianAge, (lo+hi)/2) + } else { + obs.ObserveFloat64(n.connMedianAge, ages[len(ages)/2]) + } + + return nil + }, n.connMedianAge) + if err != nil { + return fmt.Errorf("register conn_median_age gauge callback: %w", err) + } + + return nil +} + // OnEvent registers a callback that is executed when an event is received. func (n *Node) OnEvent(cb func(ctx context.Context, event *host.TraceEvent)) { n.eventCallbacks = append(n.eventCallbacks, cb) @@ -217,6 +310,9 @@ func (n *Node) Start(ctx context.Context) error { return fmt.Errorf("failed to connect to all bootstrappers") } + // start the discovery service to find peers in the discv5 DHT + n.sup.Add(n.disc) + // start all long-running services return n.sup.Serve(ctx) } diff --git a/fil/node_config.go b/fil/node_config.go index c5ffb70..1630fc1 100644 --- a/fil/node_config.go +++ b/fil/node_config.go @@ -264,6 +264,7 @@ func (n *NodeConfig) pubsubOptions(subFilter pubsub.SubscriptionFilter) []pubsub hash := blake2b.Sum256(pmsg.Data) return string(hash[:]) }), + pubsub.WithPeerExchange(true), pubsub.WithSubscriptionFilter(subFilter), pubsub.WithPeerScore( &pubsub.PeerScoreParams{ diff --git a/fil/node_notifiee.go b/fil/node_notifiee.go index 3abc0ea..1bb15c7 100644 --- a/fil/node_notifiee.go +++ b/fil/node_notifiee.go @@ -1,37 +1,36 @@ package fil import ( + "context" "log/slog" "strings" "time" "github.com/libp2p/go-libp2p/core/network" - "github.com/libp2p/go-libp2p/core/peer" ma "github.com/multiformats/go-multiaddr" "github.com/probe-lab/hermes/tele" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" ) const ( - peerstoreKeyConnectedAt = "connected_at" - peerstoreKeyIsHandshaked = "is_handshaked" + peerstoreKeyConnectedAt = "connected_at" ) // The Hermes Ethereum [Node] implements the [network.Notifiee] interface. // This means it will be notified about new connections. var _ network.Notifiee = (*Node)(nil) +func (n *Node) Listen(net network.Network, maddr ma.Multiaddr) {} + +func (n *Node) ListenClose(net network.Network, maddr ma.Multiaddr) {} + func (n *Node) Connected(net network.Network, c network.Conn) { slog.Debug("Connected with peer", tele.LogAttrPeerID(c.RemotePeer()), "total", len(n.host.Network().Peers()), "dir", c.Stat().Direction) if err := n.host.Peerstore().Put(c.RemotePeer(), peerstoreKeyConnectedAt, time.Now()); err != nil { slog.Warn("Failed to store connection timestamp in peerstore", tele.LogAttrError(err)) } - - if c.Stat().Direction == network.DirOutbound { - // handle the new connection by validating the peer. Needs to happen in a - // go routine because Connected is called synchronously. - go n.handleNewConnection(c.RemotePeer()) - } } func (n *Node) Disconnected(net network.Network, c network.Conn) { @@ -48,24 +47,11 @@ func (n *Node) Disconnected(net network.Network, c network.Conn) { } else { av = "unknown" } - // n.connAge.Record(context.TODO(), time.Since(c.Stat().Opened).Seconds(), metric.WithAttributes(attribute.String("agent", av))) + n.connAge.Record(context.TODO(), time.Since(c.Stat().Opened).Seconds(), metric.WithAttributes(attribute.String("agent", av))) } ps := n.host.Peerstore() - if _, err := ps.Get(c.RemotePeer(), peerstoreKeyIsHandshaked); err == nil { - if val, err := ps.Get(c.RemotePeer(), peerstoreKeyConnectedAt); err == nil { - slog.Info("Disconnected from handshaked peer", tele.LogAttrPeerID(c.RemotePeer())) - // n.connDurHist.Record(context.Background(), time.Since(val.(time.Time)).Hours()) - _ = val - } + if val, err := ps.Get(c.RemotePeer(), peerstoreKeyConnectedAt); err == nil { + n.connDurHist.Record(context.Background(), time.Since(val.(time.Time)).Hours()) } } - -func (n *Node) Listen(net network.Network, maddr ma.Multiaddr) {} - -func (n *Node) ListenClose(net network.Network, maddr ma.Multiaddr) {} - -// handleNewConnection validates the newly established connection to the given -// peer. -func (n *Node) handleNewConnection(pid peer.ID) { -} diff --git a/fil/pubsub.go b/fil/pubsub.go index da00cd3..e1243f3 100644 --- a/fil/pubsub.go +++ b/fil/pubsub.go @@ -1,20 +1,31 @@ package fil import ( + "bytes" "context" + "encoding/hex" "fmt" "log/slog" + "strings" + "time" + "github.com/ipni/go-libipni/announce/message" + + "github.com/filecoin-project/lotus/chain/types" pubsub "github.com/libp2p/go-libp2p-pubsub" pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb" "github.com/libp2p/go-libp2p/core/peer" "github.com/thejerf/suture/v4" "github.com/probe-lab/hermes/host" + "github.com/probe-lab/hermes/tele" ) +const eventTypeHandleMessage = "HANDLE_MESSAGE" + type PubSubConfig struct { - Topics []string + Topics []string + DataStream host.DataStream } func (p PubSubConfig) Validate() error { @@ -75,12 +86,15 @@ func (p *PubSub) Serve(ctx context.Context) error { func (p *PubSub) mapPubSubTopicWithHandlers(topic string) host.TopicHandler { switch { + case strings.HasPrefix(topic, "/f3/manifests/0.0.2"): + return p.handleF3Manifests + case strings.HasPrefix(topic, "/f3/granite/0.0.3/filecoin"): + return p.handleF3Granite + case topic == "/fil/msgs/testnetnet": + return p.handleFilMessage + case topic == "/indexer/ingest/mainnet": + return p.handleIndexerIngest default: - return func(ctx context.Context, msg *pubsub.Message) error { - slog.Info("Handle", slog.String("topic", msg.GetTopic())) - return nil - } - return p.host.TracedTopicHandler(host.NoopHandler) } } @@ -98,3 +112,118 @@ func (n *Node) CanSubscribe(topic string) bool { func (n *Node) FilterIncomingSubscriptions(id peer.ID, subs []*pubsubpb.RPC_SubOpts) ([]*pubsubpb.RPC_SubOpts, error) { return pubsub.FilterSubscriptions(subs, n.CanSubscribe), nil } + +func (p *PubSub) handleFilMessage(ctx context.Context, msg *pubsub.Message) error { + var ( + err error + evt = &host.TraceEvent{ + Type: eventTypeHandleMessage, + Topic: msg.GetTopic(), + PeerID: p.host.ID(), + Timestamp: time.Now(), + } + ) + + m, err := types.DecodeSignedMessage(msg.Message.GetData()) + if err != nil { + return fmt.Errorf("decode signed message: %w", err) + } + + evt.Payload = map[string]any{ + "PeerID": msg.ReceivedFrom, + "Topic": msg.GetTopic(), + "Seq": hex.EncodeToString(msg.GetSeqno()), + "MsgID": hex.EncodeToString([]byte(msg.ID)), + "MsgSize": len(msg.Data), + "Version": m.Message.Version, + "To": m.Message.To, + "From": m.Message.From, + "Nonce": m.Message.Nonce, + "Value": m.Message.Value, + "GasLimit": m.Message.GasLimit, + "GasFeeCap": m.Message.GasFeeCap, + "GasPremium": m.Message.GasPremium, + "Method": m.Message.Method, + //"params": m.Message.Params, TODO: figure out how to parse these params + } + + if err := p.cfg.DataStream.PutRecord(ctx, evt); err != nil { + slog.Warn( + "failed putting topic handler event", "topic", msg.GetTopic(), "err", tele.LogAttrError(err), + ) + } + + return nil +} + +func (p *PubSub) handleIndexerIngest(ctx context.Context, msg *pubsub.Message) error { + // err error + evt := &host.TraceEvent{ + Type: eventTypeHandleMessage, + Topic: msg.GetTopic(), + PeerID: p.host.ID(), + Timestamp: time.Now(), + } + + m := message.Message{} + if err := m.UnmarshalCBOR(bytes.NewBuffer(msg.Data)); err != nil { + return fmt.Errorf("unmarshal cbor: %w", err) + } + + maddrs, _ := m.GetAddrs() + evt.Payload = map[string]any{ + "PeerID": msg.ReceivedFrom, + "Topic": msg.GetTopic(), + "Seq": hex.EncodeToString(msg.GetSeqno()), + "MsgID": hex.EncodeToString([]byte(msg.ID)), + "MsgSize": len(msg.Data), + "Addrs": maddrs, + "CID": m.Cid.String(), + "ExtraData": hex.EncodeToString(m.ExtraData), + "OrigPeer": m.OrigPeer, + } + + if err := p.cfg.DataStream.PutRecord(ctx, evt); err != nil { + slog.Warn( + "failed putting topic handler event", "topic", msg.GetTopic(), "err", tele.LogAttrError(err), + ) + } + + return nil +} + +func (p *PubSub) handleF3Granite(ctx context.Context, msg *pubsub.Message) error { + // err error + evt := &host.TraceEvent{ + Type: eventTypeHandleMessage, + Topic: msg.GetTopic(), + PeerID: p.host.ID(), + Timestamp: time.Now(), + } + + if err := p.cfg.DataStream.PutRecord(ctx, evt); err != nil { + slog.Warn( + "failed putting topic handler event", "topic", msg.GetTopic(), "err", tele.LogAttrError(err), + ) + } + + return nil +} + +func (p *PubSub) handleF3Manifests(ctx context.Context, msg *pubsub.Message) error { + // err error + evt := &host.TraceEvent{ + Type: eventTypeHandleMessage, + Topic: msg.GetTopic(), + PeerID: p.host.ID(), + Timestamp: time.Now(), + } + + if err := p.cfg.DataStream.PutRecord(ctx, evt); err != nil { + slog.Warn( + "failed putting topic handler event", "topic", msg.GetTopic(), "err", tele.LogAttrError(err), + ) + } + + return nil +} diff --git a/go.mod b/go.mod index 1beab8a..8886b86 100644 --- a/go.mod +++ b/go.mod @@ -11,35 +11,39 @@ require ( github.com/aws/aws-sdk-go-v2/credentials v1.17.48 github.com/aws/aws-sdk-go-v2/service/kinesis v1.32.8 github.com/aws/aws-sdk-go-v2/service/s3 v1.72.0 - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 github.com/dennis-tra/go-kinesis v0.0.0-20240326083914-7acf5f8dc24e github.com/ethereum/go-ethereum v1.15.9 github.com/ferranbt/fastssz v0.1.4 + github.com/filecoin-project/lotus v1.32.2 github.com/google/uuid v1.6.0 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/iand/pontium v0.3.15 - github.com/libp2p/go-libp2p v0.38.1 - github.com/libp2p/go-libp2p-mplex v0.9.0 - github.com/libp2p/go-libp2p-pubsub v0.13.0 + github.com/ipni/go-libipni v0.6.18 + github.com/libp2p/go-libp2p v0.41.1 + github.com/libp2p/go-libp2p-kad-dht v0.30.2 + github.com/libp2p/go-libp2p-mplex v0.10.0 + github.com/libp2p/go-libp2p-pubsub v0.13.1 github.com/lmittmann/tint v1.0.6 - github.com/multiformats/go-multiaddr v0.14.0 + github.com/multiformats/go-multiaddr v0.15.0 github.com/parquet-go/parquet-go v0.24.0 - github.com/prometheus/client_golang v1.20.5 + github.com/prometheus/client_golang v1.22.0 github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516 github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 github.com/stretchr/testify v1.10.0 github.com/thejerf/suture/v4 v4.0.6 github.com/urfave/cli/v2 v2.27.5 - go.opentelemetry.io/otel v1.34.0 + go.opentelemetry.io/otel v1.35.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 go.opentelemetry.io/otel/exporters/prometheus v0.55.0 - go.opentelemetry.io/otel/metric v1.34.0 + go.opentelemetry.io/otel/metric v1.35.0 go.opentelemetry.io/otel/sdk v1.34.0 go.opentelemetry.io/otel/sdk/metric v1.33.0 - go.opentelemetry.io/otel/trace v1.34.0 - golang.org/x/time v0.9.0 - google.golang.org/grpc v1.69.4 - google.golang.org/protobuf v1.36.3 + go.opentelemetry.io/otel/trace v1.35.0 + golang.org/x/crypto v0.37.0 + golang.org/x/time v0.11.0 + google.golang.org/grpc v1.70.0 + google.golang.org/protobuf v1.36.6 gopkg.in/yaml.v3 v3.0.1 ) @@ -62,10 +66,12 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 // indirect github.com/aws/smithy-go v1.22.1 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.20.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/consensys/bavard v0.1.25 // indirect @@ -87,6 +93,22 @@ require ( github.com/ethereum/c-kzg-4844/v2 v2.1.1 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/filecoin-project/go-address v1.2.0 // indirect + github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 // indirect + github.com/filecoin-project/go-amt-ipld/v3 v3.1.0 // indirect + github.com/filecoin-project/go-amt-ipld/v4 v4.4.0 // indirect + github.com/filecoin-project/go-bitfield v0.2.4 // indirect + github.com/filecoin-project/go-hamt-ipld v0.1.5 // indirect + github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 // indirect + github.com/filecoin-project/go-hamt-ipld/v3 v3.4.0 // indirect + github.com/filecoin-project/go-state-types v0.16.0 // indirect + github.com/filecoin-project/specs-actors v0.9.15 // indirect + github.com/filecoin-project/specs-actors/v2 v2.3.6 // indirect + github.com/filecoin-project/specs-actors/v3 v3.1.2 // indirect + github.com/filecoin-project/specs-actors/v4 v4.0.2 // indirect + github.com/filecoin-project/specs-actors/v5 v5.0.6 // indirect + github.com/filecoin-project/specs-actors/v6 v6.0.2 // indirect + github.com/filecoin-project/specs-actors/v7 v7.0.1 // indirect github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect @@ -100,44 +122,56 @@ require ( github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.5-0.20231225225746-43d5d4cd4e0e // indirect - github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect + github.com/google/pprof v0.0.0-20250208200701-d0013a598941 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/herumi/bls-eth-go-binary v1.36.1 // indirect github.com/holiman/uint256 v1.3.2 // indirect github.com/huin/goupnp v1.3.0 // indirect - github.com/ipfs/go-cid v0.4.1 // indirect + github.com/invopop/jsonschema v0.12.0 // indirect + github.com/ipfs/boxo v0.29.1 // indirect + github.com/ipfs/go-block-format v0.2.0 // indirect + github.com/ipfs/go-cid v0.5.0 // indirect + github.com/ipfs/go-datastore v0.8.2 // indirect + github.com/ipfs/go-ipfs-util v0.0.3 // indirect + github.com/ipfs/go-ipld-cbor v0.2.0 // indirect + github.com/ipfs/go-ipld-format v0.6.0 // indirect + github.com/ipfs/go-log v1.0.5 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect + github.com/ipld/go-ipld-prime v0.21.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect - github.com/klauspost/compress v1.17.11 // indirect - github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/koron/go-ssdp v0.0.5 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect + github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-flow-metrics v0.2.0 // indirect github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect + github.com/libp2p/go-libp2p-kbucket v0.7.0 // indirect + github.com/libp2p/go-libp2p-record v0.3.1 // indirect + github.com/libp2p/go-libp2p-routing-helpers v0.7.5 // indirect github.com/libp2p/go-mplex v0.7.0 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect - github.com/libp2p/go-nat v0.2.0 // indirect github.com/libp2p/go-netroute v0.2.2 // indirect github.com/libp2p/go-reuseport v0.4.0 // indirect - github.com/libp2p/go-yamux/v4 v4.0.1 // indirect + github.com/libp2p/go-yamux/v5 v5.0.0 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect - github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/miekg/dns v1.1.62 // indirect + github.com/miekg/dns v1.1.63 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/minio/highwayhash v1.0.3 // indirect @@ -162,37 +196,41 @@ require ( github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/onsi/ginkgo/v2 v2.22.2 // indirect github.com/opencontainers/runtime-spec v1.2.0 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pion/datachannel v1.5.10 // indirect github.com/pion/dtls/v2 v2.2.12 // indirect - github.com/pion/ice/v2 v2.3.37 // indirect + github.com/pion/dtls/v3 v3.0.4 // indirect + github.com/pion/ice/v4 v4.0.8 // indirect github.com/pion/interceptor v0.1.37 // indirect - github.com/pion/logging v0.2.2 // indirect - github.com/pion/mdns v0.0.12 // indirect + github.com/pion/logging v0.2.3 // indirect + github.com/pion/mdns/v2 v2.0.7 // indirect github.com/pion/randutil v0.1.0 // indirect github.com/pion/rtcp v1.2.15 // indirect - github.com/pion/rtp v1.8.10 // indirect - github.com/pion/sctp v1.8.35 // indirect - github.com/pion/sdp/v3 v3.0.9 // indirect - github.com/pion/srtp/v2 v2.0.20 // indirect + github.com/pion/rtp v1.8.11 // indirect + github.com/pion/sctp v1.8.37 // indirect + github.com/pion/sdp/v3 v3.0.10 // indirect + github.com/pion/srtp/v3 v3.0.4 // indirect github.com/pion/stun v0.6.1 // indirect + github.com/pion/stun/v3 v3.0.0 // indirect github.com/pion/transport/v2 v2.2.10 // indirect github.com/pion/transport/v3 v3.0.7 // indirect - github.com/pion/turn/v2 v2.1.6 // indirect - github.com/pion/webrtc/v3 v3.3.5 // indirect + github.com/pion/turn/v4 v4.0.0 // indirect + github.com/pion/webrtc/v4 v4.0.10 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.61.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect + github.com/polydawn/refmt v0.89.0 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.63.0 // indirect + github.com/prometheus/procfs v0.16.1 // indirect github.com/prometheus/prom2json v1.4.1 // indirect github.com/prometheus/prometheus v0.301.0 // indirect github.com/prysmaticlabs/gohashtree v0.0.4-beta.0.20240624100937-73632381301b // indirect github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c // indirect github.com/quic-go/qpack v0.5.1 // indirect - github.com/quic-go/quic-go v0.48.2 // indirect + github.com/quic-go/quic-go v0.50.1 // indirect github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect @@ -210,6 +248,9 @@ require ( github.com/tklauser/numcpus v0.9.0 // indirect github.com/trailofbits/go-mutexasserts v0.0.0-20250212181730-4c2b8e9e784b // indirect github.com/wealdtech/go-bytesutil v1.2.1 // indirect + github.com/whyrusleeping/cbor-gen v0.3.1 // indirect + github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/wlynxg/anet v0.0.5 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect @@ -225,25 +266,26 @@ require ( go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.36.0 // indirect - golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/net v0.38.0 // indirect + golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect + golang.org/x/mod v0.24.0 // indirect + golang.org/x/net v0.39.0 // indirect golang.org/x/oauth2 v0.25.0 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/term v0.30.0 // indirect - golang.org/x/text v0.23.0 // indirect - golang.org/x/tools v0.30.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + golang.org/x/sync v0.13.0 // indirect + golang.org/x/sys v0.32.0 // indirect + golang.org/x/term v0.31.0 // indirect + golang.org/x/text v0.24.0 // indirect + golang.org/x/tools v0.32.0 // indirect + golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect + gonum.org/v1/gonum v0.16.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/apimachinery v0.32.0 // indirect k8s.io/client-go v0.32.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect - lukechampine.com/blake3 v1.3.0 // indirect + lukechampine.com/blake3 v1.4.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect diff --git a/go.sum b/go.sum index 4bd8f11..05cea15 100644 --- a/go.sum +++ b/go.sum @@ -7,21 +7,25 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs= github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/OffchainLabs/prysm/v6 v6.0.1 h1:NwFsJTyPVQqhmEz4//GqAs+M6AjcWYqH9x+HvDGxgwk= github.com/OffchainLabs/prysm/v6 v6.0.1/go.mod h1:7QuGy5ol0x0hx1Qmz0XcXJ3CnjWWKHpMiz++bUR0IIg= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s= github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -80,6 +84,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 h1:Xgv/hyNgvLda/M9l9qxXc4UFSgpp github.com/aws/aws-sdk-go-v2/service/sts v1.33.3/go.mod h1:5Gn+d+VaaRgsjewpMvGazt0WfcFO+Md4wLOuBfGR9Bc= github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/bazelbuild/rules_go v0.23.2 h1:Wxu7JjqnF78cKZbsBsARLSXx/jlGaSLCnUV3mTlyHvM= github.com/bazelbuild/rules_go v0.23.2/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -94,9 +100,22 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= +github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= @@ -134,6 +153,7 @@ github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTF github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= @@ -150,8 +170,10 @@ github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHH github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U= github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -160,17 +182,19 @@ github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/deckarep/golang-set/v2 v2.7.0 h1:gIloKvD7yH2oip4VLhsv3JyLLFnC0Y2mlusgcvJYW5k= github.com/deckarep/golang-set/v2 v2.7.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= -github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= -github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= +github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU= github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= github.com/dennis-tra/go-kinesis v0.0.0-20240326083914-7acf5f8dc24e h1:y6QyYh8YZyRQDdfnQqUgC5tRBmEwUFAjavnybKboCm4= github.com/dennis-tra/go-kinesis v0.0.0-20240326083914-7acf5f8dc24e/go.mod h1:5Hm3EOeNP1/lYm9qcFwWgYgjixQilwcZA+hZ05bUz54= +github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE= github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -207,6 +231,59 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2 github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY= github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= +github.com/filecoin-project/go-address v0.0.3/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8= +github.com/filecoin-project/go-address v0.0.5/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8= +github.com/filecoin-project/go-address v1.2.0 h1:NHmWUE/J7Pi2JZX3gZt32XuY69o9StVZeJxdBodIwOE= +github.com/filecoin-project/go-address v1.2.0/go.mod h1:kQEQ4qZ99a51X7DjT9HiMT4yR6UwLJ9kznlxsOIeDAg= +github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 h1:t6qDiuGYYngDqaLc2ZUvdtAg4UNxPeOYaXhBWSNsVaM= +github.com/filecoin-project/go-amt-ipld/v2 v2.1.0/go.mod h1:nfFPoGyX0CU9SkXX8EoCcSuHN1XcbN0c6KBh7yvP5fs= +github.com/filecoin-project/go-amt-ipld/v3 v3.0.0/go.mod h1:Qa95YNAbtoVCTSVtX38aAC1ptBnJfPma1R/zZsKmx4o= +github.com/filecoin-project/go-amt-ipld/v3 v3.1.0 h1:ZNJ9tEG5bE72vBWYiuh5bkxJVM3ViHNOmQ7qew9n6RE= +github.com/filecoin-project/go-amt-ipld/v3 v3.1.0/go.mod h1:UjM2QhDFrrjD5s1CdnkJkat4ga+LqZBZgTMniypABRo= +github.com/filecoin-project/go-amt-ipld/v4 v4.0.0/go.mod h1:gF053YQ4BIpzTNDoEwHZas7U3oAwncDVGvOHyY8oDpE= +github.com/filecoin-project/go-amt-ipld/v4 v4.4.0 h1:6kvvMeSpIy4GTU5t3vPHZgWYIMRzGRKLJ73s/cltsoc= +github.com/filecoin-project/go-amt-ipld/v4 v4.4.0/go.mod h1:msgmUxTyRBZ6iXt+5dnUDnIb7SEFqdPsbB1wyo/G3ts= +github.com/filecoin-project/go-bitfield v0.2.0/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= +github.com/filecoin-project/go-bitfield v0.2.3/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= +github.com/filecoin-project/go-bitfield v0.2.4 h1:uZ7MeE+XfM5lqrHJZ93OnhQKc/rveW8p9au0C68JPgk= +github.com/filecoin-project/go-bitfield v0.2.4/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= +github.com/filecoin-project/go-cbor-util v0.0.1 h1:E1LYZYTtjfAQwCReho0VXvbu8t3CYAVPiMx8EiV/VAs= +github.com/filecoin-project/go-cbor-util v0.0.1/go.mod h1:pqTiPHobNkOVM5thSRsHYjyQfq7O5QSCMhvuu9JoDlg= +github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= +github.com/filecoin-project/go-crypto v0.1.0 h1:Pob2MphoipMbe/ksxZOMcQvmBHAd3sI/WEqcbpIsGI0= +github.com/filecoin-project/go-crypto v0.1.0/go.mod h1:K9UFXvvoyAVvB+0Le7oGlKiT9mgA5FHOJdYQXEE8IhI= +github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM= +github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24= +github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 h1:b3UDemBYN2HNfk3KOXNuxgTTxlWi3xVvbQP0IT38fvM= +github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0/go.mod h1:7aWZdaQ1b16BVoQUYR+eEvrDCGJoPLxFpDynFjYfBjI= +github.com/filecoin-project/go-hamt-ipld/v3 v3.0.1/go.mod h1:gXpNmr3oQx8l3o7qkGyDjJjYSRX7hp/FGOStdqrWyDI= +github.com/filecoin-project/go-hamt-ipld/v3 v3.1.0/go.mod h1:bxmzgT8tmeVQA1/gvBwFmYdT8SOFUwB3ovSUfG1Ux0g= +github.com/filecoin-project/go-hamt-ipld/v3 v3.4.0 h1:nYs6OPUF8KbZ3E8o9p9HJnQaE8iugjHR5WYVMcicDJc= +github.com/filecoin-project/go-hamt-ipld/v3 v3.4.0/go.mod h1:s0qiHRhFyrgW0SvdQMSJFQxNa4xEIG5XvqCBZUEgcbc= +github.com/filecoin-project/go-state-types v0.0.0-20200928172055-2df22083d8ab/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= +github.com/filecoin-project/go-state-types v0.0.0-20201102161440-c8033295a1fc/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= +github.com/filecoin-project/go-state-types v0.1.0/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= +github.com/filecoin-project/go-state-types v0.1.6/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= +github.com/filecoin-project/go-state-types v0.16.0 h1:ajIREDzTGfq71ofIQ29iZR1WXxmkvd2nQNc6ApcP1wI= +github.com/filecoin-project/go-state-types v0.16.0/go.mod h1:YCESyrqnyu17y0MazbV6Uwma5+BrMvEKEQp5QWeIf9g= +github.com/filecoin-project/lotus v1.32.2 h1:UQsJgLeZVKE7dPc171va7LlIBYN5XTSqrCs8hooGcik= +github.com/filecoin-project/lotus v1.32.2/go.mod h1:eNfZ0eXGMckDBFQmL1/MJk/0UgxVKHy74z40uMrGlg4= +github.com/filecoin-project/specs-actors v0.9.13/go.mod h1:TS1AW/7LbG+615j4NsjMK1qlpAwaFsG9w0V2tg2gSao= +github.com/filecoin-project/specs-actors v0.9.15-0.20220514164640-94e0d5e123bd/go.mod h1:pjGEe3QlWtK20ju/aFRsiArbMX6Cn8rqEhhsiCM9xYE= +github.com/filecoin-project/specs-actors v0.9.15 h1:3VpKP5/KaDUHQKAMOg4s35g/syDaEBueKLws0vbsjMc= +github.com/filecoin-project/specs-actors v0.9.15/go.mod h1:pjGEe3QlWtK20ju/aFRsiArbMX6Cn8rqEhhsiCM9xYE= +github.com/filecoin-project/specs-actors/v2 v2.3.6 h1:UxnWTfQd7JsOae39/aHCK0m1IBjdcyymCJfqxuSkn+g= +github.com/filecoin-project/specs-actors/v2 v2.3.6/go.mod h1:DJMpxVRXvev9t8P0XWA26RmTzN+MHiL9IlItVLT0zUc= +github.com/filecoin-project/specs-actors/v3 v3.1.2 h1:Gq3gAbvdGLA/D0GKz1IJfewt9Fh7gA32TPt46Xv+1Cw= +github.com/filecoin-project/specs-actors/v3 v3.1.2/go.mod h1:uOJn+m6W8OW/1mdWMEvxeM1cjQPxmps7s1Z4bJ9V4kY= +github.com/filecoin-project/specs-actors/v4 v4.0.2 h1:VTsv30kIf1Keo8Jlu6Omco+2Ud0pG4EN5UAzyYCibh8= +github.com/filecoin-project/specs-actors/v4 v4.0.2/go.mod h1:zT0GVFxwFS93prGK0b/rMd1sePjRQKfAuodQ9DFAd6Y= +github.com/filecoin-project/specs-actors/v5 v5.0.6 h1:TLtA9hT3pHQF5vB83GmB+m6anw9u6MjdT+VVn/lyC+c= +github.com/filecoin-project/specs-actors/v5 v5.0.6/go.mod h1:myb/UGwESp0V1f1BACXSUrFgTWLvGUoG0ZZH7eqriFM= +github.com/filecoin-project/specs-actors/v6 v6.0.2 h1:K1xPRJoW5PBvb08QF9+4w1AjcnqwR6BjTmeltQFCvWo= +github.com/filecoin-project/specs-actors/v6 v6.0.2/go.mod h1:wnfVvPnYmzPZilNvSqCSSA/ZQX3rdV/U/Vf9EIoQhrI= +github.com/filecoin-project/specs-actors/v7 v7.0.1 h1:w72xCxijK7xs1qzmJiw+WYJaVt2EPHN8oiwpA1Ay3/4= +github.com/filecoin-project/specs-actors/v7 v7.0.1/go.mod h1:tPLEYXoXhcpyLh69Ccq91SOuLXsPWjHiY27CzawjUEk= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= @@ -214,6 +291,8 @@ github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJn github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= @@ -226,6 +305,7 @@ github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -251,6 +331,7 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= @@ -273,6 +354,7 @@ github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200j github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= @@ -298,8 +380,8 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -309,21 +391,26 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc= +github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= +github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= @@ -335,6 +422,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpg github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -373,8 +462,10 @@ github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/iand/pontium v0.3.15 h1:p9ZzSFPuC2gsLoqZJIPh5nrkRRAgi5JDEMYOfatrhws= github.com/iand/pontium v0.3.15/go.mod h1:Fn3hprsfb1nZuVsF0+b92K+HRY0WZcxrHkLUpWOapoI= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -385,15 +476,105 @@ github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSH github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 h1:vilfsDSy7TDxedi9gyBkMvAirat/oRcL0lFdJBf6tdM= github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= -github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= -github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= +github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI= +github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= +github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI= +github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= +github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= +github.com/ipfs/boxo v0.29.1 h1:z61ZT4YDfTHLjXTsu/+3wvJ8aJlExthDSOCpx6Nh8xc= +github.com/ipfs/boxo v0.29.1/go.mod h1:MkDJStXiJS9U99cbAijHdcmwNfVn5DKYBmQCOgjY2NU= +github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= +github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs= +github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= +github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= +github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= +github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= +github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= +github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= +github.com/ipfs/go-cid v0.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg= +github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk= +github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.8.2 h1:Jy3wjqQR6sg/LhyY0NIePZC3Vux19nLtg7dx0TVqr6U= +github.com/ipfs/go-datastore v0.8.2/go.mod h1:W+pI1NsUsz3tcsAACMtfC+IZdnQTnC/7VfPoJBQuts0= +github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= +github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= +github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= +github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= +github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= +github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= +github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo= +github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM= +github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= +github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= +github.com/ipfs/go-ipfs-files v0.0.4/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= +github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A= +github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= +github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= +github.com/ipfs/go-ipfs-util v0.0.3 h1:2RFdGez6bu2ZlZdI+rWfIdbQb1KudQp3VGwPtdNCmE0= +github.com/ipfs/go-ipfs-util v0.0.3/go.mod h1:LHzG1a0Ig4G+iZ26UUOMjHd+lfM84LZCrn17xAKWBvs= +github.com/ipfs/go-ipld-cbor v0.0.2/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= +github.com/ipfs/go-ipld-cbor v0.0.4/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-cbor v0.0.6-0.20211211231443-5d9b9e1f6fa8/go.mod h1:ssdxxaLJPXH7OjF5V4NSjBbcfh+evoR4ukuru0oPXMA= +github.com/ipfs/go-ipld-cbor v0.0.6/go.mod h1:ssdxxaLJPXH7OjF5V4NSjBbcfh+evoR4ukuru0oPXMA= +github.com/ipfs/go-ipld-cbor v0.2.0 h1:VHIW3HVIjcMd8m4ZLZbrYpwjzqlVUfjLM7oK4T5/YF0= +github.com/ipfs/go-ipld-cbor v0.2.0/go.mod h1:Cp8T7w1NKcu4AQJLqK0tWpd1nkgTxEVB5C6kVpLW6/0= +github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= +github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= +github.com/ipfs/go-ipld-format v0.6.0 h1:VEJlA2kQ3LqFSIm5Vu6eIlSxD/Ze90xtc4Meten1F5U= +github.com/ipfs/go-ipld-format v0.6.0/go.mod h1:g4QVMTn3marU3qXchwjpKPKgJv+zF+OlaKMyhJ4LHPg= +github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= +github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= +github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= +github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= +github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= +github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= +github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= +github.com/ipfs/go-merkledag v0.2.4/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= +github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= +github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU= +github.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY= +github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= +github.com/ipfs/go-test v0.2.1 h1:/D/a8xZ2JzkYqcVcV/7HYlCnc7bv/pKHQiX5TdClkPE= +github.com/ipfs/go-test v0.2.1/go.mod h1:dzu+KB9cmWjuJnXFDYJwC25T3j1GcN57byN+ixmK39M= +github.com/ipfs/go-unixfs v0.2.2-0.20190827150610-868af2e9e5cb/go.mod h1:IwAAgul1UQIcNZzKPYZWOCijryFBeCV79cNubPzol+k= +github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= +github.com/ipld/go-car v0.1.0/go.mod h1:RCWzaUh2i4mOEkB3W45Vc+9jnS/M6Qay5ooytiBHl3g= +github.com/ipld/go-ipld-prime v0.0.2-0.20191108012745-28a82f04c785/go.mod h1:bDDSvVz7vaK12FNvMeRYnpRFkSUPNQOiCYQezMD/P3w= +github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E= +github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ= +github.com/ipld/go-ipld-prime-proto v0.0.0-20191113031812-e32bd156a1e5/go.mod h1:gcvzoEDBjwycpXt3LBE061wT9f46szXGHAmj9uoP6fU= +github.com/ipni/go-libipni v0.6.18 h1:x8X6y0QoMmSKtwRlczWdWEYedoLUGCEek2TttfDKPk4= +github.com/ipni/go-libipni v0.6.18/go.mod h1:qUObcCVXMx3byEGn/g2alGlsqY79tTZBzWoNPCwYFOE= +github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52/go.mod h1:fdg+/X9Gg4AsAIzWpEHwnqd+QY3b7lajxyjE1m4hkq4= +github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= +github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c/go.mod h1:sdx1xVM9UuLw1tXnhJWN3piypTUO3vCIHYmG15KE/dU= +github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= +github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= @@ -403,6 +584,7 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -410,6 +592,8 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= @@ -419,16 +603,19 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= -github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= -github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= github.com/koron/go-ssdp v0.0.5 h1:E1iSMxIs4WqxTbIBLtmNBeOOC+1sCIXQeqTWVnpmwhk= github.com/koron/go-ssdp v0.0.5/go.mod h1:Qm59B7hpKpDqfyRNWRNr00jGwLdXjDyZh6y7rH6VS0w= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -441,32 +628,86 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= +github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= +github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= +github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= +github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= +github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= +github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= github.com/libp2p/go-flow-metrics v0.2.0 h1:EIZzjmeOE6c8Dav0sNv35vhZxATIXWZg6j/C08XmmDw= github.com/libp2p/go-flow-metrics v0.2.0/go.mod h1:st3qqfu8+pMfh+9Mzqb2GTiwrAGjIPszEjZmtksN8Jc= -github.com/libp2p/go-libp2p v0.38.1 h1:aT1K7IFWi+gZUsQGCzTHBTlKX5QVZQOahng8DnOr6tQ= -github.com/libp2p/go-libp2p v0.38.1/go.mod h1:QWV4zGL3O9nXKdHirIC59DoRcZ446dfkjbOJ55NEWFo= +github.com/libp2p/go-libp2p v0.1.0/go.mod h1:6D/2OBauqLUoqcADOJpn9WbKqvaM07tDw68qHM0BxUM= +github.com/libp2p/go-libp2p v0.1.1/go.mod h1:I00BRo1UuUSdpuc8Q2mN7yDF/oTUTRAX6JWpTiK9Rp8= +github.com/libp2p/go-libp2p v0.41.1 h1:8ecNQVT5ev/jqALTvisSJeVNvXYJyK4NhQx1nNRXQZE= +github.com/libp2p/go-libp2p v0.41.1/go.mod h1:DcGTovJzQl/I7HMrby5ZRjeD0kQkGiy+9w6aEkSZpRI= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= -github.com/libp2p/go-libp2p-mplex v0.9.0 h1:R58pDRAmuBXkYugbSSXR9wrTX3+1pFM1xP2bLuodIq8= -github.com/libp2p/go-libp2p-mplex v0.9.0/go.mod h1:ro1i4kuwiFT+uMPbIDIFkcLs1KRbNp0QwnUXM+P64Og= -github.com/libp2p/go-libp2p-pubsub v0.13.0 h1:RmFQ2XAy3zQtbt2iNPy7Tt0/3fwTnHpCQSSnmGnt1Ps= -github.com/libp2p/go-libp2p-pubsub v0.13.0/go.mod h1:m0gpUOyrXKXdE7c8FNQ9/HLfWbxaEw7xku45w+PaqZo= +github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= +github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= +github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= +github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= +github.com/libp2p/go-libp2p-core v0.0.2/go.mod h1:9dAcntw/n46XycV4RnlBq3BpgrmyUi9LuoTNdPrbUco= +github.com/libp2p/go-libp2p-core v0.0.3/go.mod h1:j+YQMNz9WNSkNezXOsahp9kwZBKBvxLpKD316QWSJXE= +github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= +github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g= +github.com/libp2p/go-libp2p-kad-dht v0.30.2 h1:K0LJPdXynQ+u3rx6uFlrfNy0i11LE6SOCDzwAAaahys= +github.com/libp2p/go-libp2p-kad-dht v0.30.2/go.mod h1:UV0mxF4ufh/ht05jNg5mcjOMrjK82uecgANa+GKi4y0= +github.com/libp2p/go-libp2p-kbucket v0.7.0 h1:vYDvRjkyJPeWunQXqcW2Z6E93Ywx7fX0jgzb/dGOKCs= +github.com/libp2p/go-libp2p-kbucket v0.7.0/go.mod h1:blOINGIj1yiPYlVEX0Rj9QwEkmVnz3EP8LK1dRKBC6g= +github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= +github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= +github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= +github.com/libp2p/go-libp2p-mplex v0.10.0 h1:6NKusNu1cw1A/RKb+Lm5aPGFk7HWVIXxl2azpwWqUxc= +github.com/libp2p/go-libp2p-mplex v0.10.0/go.mod h1:7RT3qPFhDqz4yp5K5QwZB5vE902N8DmED3+e453fNrg= +github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= +github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= +github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= +github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= +github.com/libp2p/go-libp2p-pubsub v0.13.1 h1:tV3ttzzZSCk0EtEXnxVmWIXgjVxXx+20Jwjbs/Ctzjo= +github.com/libp2p/go-libp2p-pubsub v0.13.1/go.mod h1:MKPU5vMI8RRFyTP0HfdsF9cLmL1nHAeJm44AxJGJx44= +github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= +github.com/libp2p/go-libp2p-record v0.3.1 h1:cly48Xi5GjNw5Wq+7gmjfBiG9HCzQVkiZOUZ8kUl+Fg= +github.com/libp2p/go-libp2p-record v0.3.1/go.mod h1:T8itUkLcWQLCYMqtX7Th6r7SexyUJpIyPgks757td/E= +github.com/libp2p/go-libp2p-routing-helpers v0.7.5 h1:HdwZj9NKovMx0vqq6YNPTh6aaNzey5zHD7HeLJtq6fI= +github.com/libp2p/go-libp2p-routing-helpers v0.7.5/go.mod h1:3YaxrwP0OBPDD7my3D0KxfR89FlcX/IEbxDEDfAmj98= +github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= +github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= +github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= +github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= +github.com/libp2p/go-libp2p-yamux v0.2.1/go.mod h1:1FBXiHDk1VyRM1C0aez2bCfHQ4vMZKkAQzZbkSQt5fI= +github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= +github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= github.com/libp2p/go-mplex v0.7.0 h1:BDhFZdlk5tbr0oyFq/xv/NPGfjbnrsDam1EvutpBDbY= github.com/libp2p/go-mplex v0.7.0/go.mod h1:rW8ThnRcYWft/Jb2jeORBmPd6xuG3dGxWN/W168L9EU= +github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= -github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= -github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= +github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= github.com/libp2p/go-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8= github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE= +github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= -github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= -github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= +github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= +github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= +github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= +github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= +github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc= +github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo= +github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux/v5 v5.0.0 h1:2djUh96d3Jiac/JpGkKs4TO49YhsfLopAoryfPmf+Po= +github.com/libp2p/go-yamux/v5 v5.0.0/go.mod h1:en+3cdX51U0ZslwRdRLrvQsdayFt3TSUKvBGErzpWbU= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lmittmann/tint v1.0.6 h1:vkkuDAZXc0EFGNzYjWcV0h7eEX+uujH48f/ifSkJWgc= @@ -481,10 +722,14 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= @@ -497,18 +742,24 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zk github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= -github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= +github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= +github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -536,29 +787,50 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= +github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= +github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.14.0 h1:bfrHrJhrRuh/NXH5mCnemjpbGjzRw/b+tJFOD41g2tU= -github.com/multiformats/go-multiaddr v0.14.0/go.mod h1:6EkVAxtznq2yC3QT5CM1UTAwG0GTP3EWAIcjHuzQ+r4= +github.com/multiformats/go-multiaddr v0.15.0 h1:zB/HeaI/apcZiTDwhY5YqMvNVl/oQYvs3XySU+qeAVo= +github.com/multiformats/go-multiaddr v0.15.0/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0= +github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.4.1 h1:whi/uCLbDS3mSEUMb1MsoT4uzUeZB0N32yzufqS0i5M= github.com/multiformats/go-multiaddr-dns v0.4.1/go.mod h1:7hfthtB4E4pQwirrz+J0CcDUfbWzTqEzVyYKKIKpgkc= +github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= +github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= +github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/multiformats/go-multistream v0.6.0 h1:ZaHKbsL404720283o4c/IHQXiS6gb8qAN5EIJ4PN5EA= github.com/multiformats/go-multistream v0.6.0/go.mod h1:MOyoG5otO24cHIg8kf9QW2/NozURlkP/rvi2FQJyCPg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -584,6 +856,7 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= @@ -591,6 +864,7 @@ github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042 github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= @@ -631,45 +905,45 @@ github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oL github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= -github.com/pion/ice/v2 v2.3.37 h1:ObIdaNDu1rCo7hObhs34YSBcO7fjslJMZV0ux+uZWh0= -github.com/pion/ice/v2 v2.3.37/go.mod h1:mBF7lnigdqgtB+YHkaY/Y6s6tsyRyo4u4rPGRuOjUBQ= +github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U= +github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg= +github.com/pion/ice/v4 v4.0.8 h1:ajNx0idNG+S+v9Phu4LSn2cs8JEfTsA1/tEjkkAVpFY= +github.com/pion/ice/v4 v4.0.8/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI= github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y= -github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= -github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= -github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= +github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI= +github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90= +github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM= +github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA= github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= -github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= -github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/rtp v1.8.10 h1:puphjdbjPB+L+NFaVuZ5h6bt1g5q4kFIoI+r5q/g0CU= -github.com/pion/rtp v1.8.10/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4= -github.com/pion/sctp v1.8.35 h1:qwtKvNK1Wc5tHMIYgTDJhfZk7vATGVHhXbUDfHbYwzA= -github.com/pion/sctp v1.8.35/go.mod h1:EcXP8zCYVTRy3W9xtOF7wJm1L1aXfKRQzaM33SjQlzg= -github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= -github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= -github.com/pion/srtp/v2 v2.0.20 h1:HNNny4s+OUmG280ETrCdgFndp4ufx3/uy85EawYEhTk= -github.com/pion/srtp/v2 v2.0.20/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/rtp v1.8.11 h1:17xjnY5WO5hgO6SD3/NTIUPvSFw/PbLsIJyz1r1yNIk= +github.com/pion/rtp v1.8.11/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4= +github.com/pion/sctp v1.8.37 h1:ZDmGPtRPX9mKCiVXtMbTWybFw3z/hVKAZgU81wcOrqs= +github.com/pion/sctp v1.8.37/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= +github.com/pion/sdp/v3 v3.0.10 h1:6MChLE/1xYB+CjumMw+gZ9ufp2DPApuVSnDT8t5MIgA= +github.com/pion/sdp/v3 v3.0.10/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= +github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M= +github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ= github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= +github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw= +github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU= github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= -github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= -github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= -github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= -github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/webrtc/v3 v3.3.5 h1:ZsSzaMz/i9nblPdiAkZoP+E6Kmjw+jnyq3bEmU3EtRg= -github.com/pion/webrtc/v3 v3.3.5/go.mod h1:liNa+E1iwyzyXqNUwvoMRNQ10x8h8FOeJKL8RkIbamE= +github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM= +github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA= +github.com/pion/webrtc/v4 v4.0.10 h1:Hq/JLjhqLxi+NmCtE8lnRPDr8H4LcNvwg8OxVcdv56Q= +github.com/pion/webrtc/v4 v4.0.10/go.mod h1:ViHLVaNpiuvaH8pdiuQxuA9awuE6KVzAXx3vVWilOck= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -679,6 +953,12 @@ github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6J github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= +github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -687,24 +967,24 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU= -github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ= -github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s= +github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= +github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -712,8 +992,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/prometheus/prom2json v1.4.1 h1:7McxdrHgPEOtMwWjkKtd0v5AhpR2Q6QAnlHKVxq0+tQ= github.com/prometheus/prom2json v1.4.1/go.mod h1:CzOQykSKFxXuC7ELUZHOHQvwKesQ3eN0p2PWLhFitQM= github.com/prometheus/prometheus v0.301.0 h1:0z8dgegmILivNomCd79RKvVkIols8vBGPKmcIBc7OyY= @@ -730,10 +1010,12 @@ github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20230228205207-28762a7b9294 h github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20230228205207-28762a7b9294/go.mod h1:ZVEbRdnMkGhp/pu35zq4SXxtvUwWK0J1MATtekZpH2Y= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE= -github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs= +github.com/quic-go/quic-go v0.50.1 h1:unsgjFIUqW8a2oopkY7YNONpV1gYND6Nt9hnt1PN94Q= +github.com/quic-go/quic-go v0.50.1/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E= github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 h1:4WFk6u3sOT6pLa1kQ50ZVdm8BQFgJNA117cepZxtLIg= github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66/go.mod h1:Vp72IJajgeOL6ddqrAhmp7IM9zbTcgkQxD/YdxrVwMw= +github.com/raulk/clock v1.1.0 h1:dpb29+UKMbLqiU/jqIJptgLR1nn23HLgMY0sTCDza5Y= +github.com/raulk/clock v1.1.0/go.mod h1:3MpVxdZ/ODBQDxbN+kzshf5OSZwPjtMDx6BBXBmOeY0= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -789,11 +1071,23 @@ github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/assertions v1.13.0 h1:Dx1kYM01xsSqKPno3aqLnrwac2LetPvN23diwyr69Qs= +github.com/smartystreets/assertions v1.13.0/go.mod h1:wDmR7qL282YbGsPy6H/yAsesrxfxaaSlJazyFLYVFx8= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= +github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= @@ -809,20 +1103,20 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/supranational/blst v0.3.14 h1:xNMoHRJOTwMn63ip6qoWJ2Ymgvj7E2b9jY2FAwY+qRo= github.com/supranational/blst v0.3.14/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= @@ -840,18 +1134,47 @@ github.com/trailofbits/go-mutexasserts v0.0.0-20250212181730-4c2b8e9e784b/go.mod github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= +github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= +github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/wealdtech/go-bytesutil v1.2.1 h1:TjuRzcG5KaPwaR5JB7L/OgJqMQWvlrblA1n0GfcXFSY= github.com/wealdtech/go-bytesutil v1.2.1/go.mod h1:RhUDUGT1F4UP4ydqbYp2MWJbAel3M+mKd057Pad7oag= +github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg= +github.com/whyrusleeping/cbor-gen v0.0.0-20200715143311-227fab5a2377/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20200723185710-6a3894a6352b/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20200806213330-63aa96ca5488/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20200810223238-211df3b9e24c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20200812213548-958ddffe352c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20210118024343-169e9d70c0c2/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.3.1 h1:82ioxmhEYut7LBVGhGq8xoRkXPLElVuh5mV67AFfdv0= +github.com/whyrusleeping/cbor-gen v0.3.1/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so= +github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8= +github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= +github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= +github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8= +github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= +github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xorcare/golden v0.6.0/go.mod h1:7T39/ZMvaSEZlBPoYfVFmsBLmUl3uz9IuzWj/U6FtvQ= +github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 h1:oWgZJmC1DorFZDpfMfWg7xk29yEOZiXmo/wZl+utTI8= +github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542/go.mod h1:7T39/ZMvaSEZlBPoYfVFmsBLmUl3uz9IuzWj/U6FtvQ= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= @@ -862,6 +1185,10 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA= +gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8= +gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q= +gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02/go.mod h1:JTnUj0mpYiAsuZLmKjTx/ex3AtMowcCgnE7YNyCEP0I= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= @@ -871,12 +1198,14 @@ go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I= -go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= -go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 h1:5pojmb1U1AogINhN3SurB+zm/nIcusopeBNp42f45QM= @@ -885,18 +1214,19 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 h1:BEj3S go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0/go.mod h1:9cKLGBDzI/F3NoHLQGm4ZrYdIHsvGt6ej6hUowxY0J4= go.opentelemetry.io/otel/exporters/prometheus v0.55.0 h1:sSPw658Lk2NWAv74lkD3B/RSDb+xRFx46GjkrL3VUZo= go.opentelemetry.io/otel/exporters/prometheus v0.55.0/go.mod h1:nC00vyCmQixoeaxF6KNyP42II/RHa9UdruK02qBmHvI= -go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= -go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= go.opentelemetry.io/otel/sdk/metric v1.33.0 h1:Gs5VK9/WUJhNXZgn8MR6ITatvAmKeIuCtNbsP3JkNqU= go.opentelemetry.io/otel/sdk/metric v1.33.0/go.mod h1:dL5ykHZmm1B1nVRk9dDjChwDmt81MjVp3gLkQRwKf/Q= -go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= -go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/dig v1.18.0 h1:imUL1UiY0Mg4bqbFfsRQO5G4CGRBec/ZujWTvSVp3pw= go.uber.org/dig v1.18.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= @@ -909,23 +1239,32 @@ go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -936,11 +1275,11 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= -golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -955,11 +1294,12 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -969,10 +1309,13 @@ golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -990,8 +1333,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1009,8 +1352,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1022,10 +1365,17 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190524122548-abf6ff778158/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1058,12 +1408,11 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -1071,8 +1420,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= -golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= +golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -1082,13 +1431,13 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= -golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1111,12 +1460,16 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= +golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= @@ -1134,10 +1487,10 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA= -google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b h1:i+d0RZa8Hs2L/MuaOQYI+krthcxdEbEM2N+Tf3kJ4zk= +google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b/go.mod h1:iYONQfRdizDB8JJBybql13nArx91jcUk7zCXEsOofM4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b h1:FQtJ1MxbXoIIrZHZ33M+w5+dAP9o86rgpjoKr/ZmT7k= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1149,16 +1502,16 @@ google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= -google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= +google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= -google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1210,8 +1563,10 @@ k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJ k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= -lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +lukechampine.com/blake3 v1.4.0 h1:xDbKOZCVbnZsfzM6mHSYcGRHZ3YrLDzqz8XnV4uaD5w= +lukechampine.com/blake3 v1.4.0/go.mod h1:MQJNQCTnR+kwOP/JEZSxj3MaQjp80FOFSNMMHXcSeX0= +lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= +lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= diff --git a/host/pubsub.go b/host/pubsub.go index b6061cd..b702a7a 100644 --- a/host/pubsub.go +++ b/host/pubsub.go @@ -39,7 +39,6 @@ func (t *TopicSubscription) Serve(ctx context.Context) error { return fmt.Errorf("failed to read next gossip message for topic %s: %w", t.Sub.Topic(), err) } - slog.Error("MESSAGE!") // check if it's our own event if msg.ReceivedFrom == t.LocalID { From 3400b12738519892125c406bd4ff73cd57532aa9 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Fri, 25 Apr 2025 17:32:23 +0200 Subject: [PATCH 04/65] filecoin: parse f3 messages --- fil/pubsub.go | 40 ++++++++++++++++++++++++++++++++++++++-- go.mod | 2 ++ go.sum | 6 ++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/fil/pubsub.go b/fil/pubsub.go index e1243f3..7215639 100644 --- a/fil/pubsub.go +++ b/fil/pubsub.go @@ -9,12 +9,14 @@ import ( "strings" "time" - "github.com/ipni/go-libipni/announce/message" - + "github.com/filecoin-project/go-f3/gpbft" + "github.com/filecoin-project/go-f3/manifest" "github.com/filecoin-project/lotus/chain/types" + "github.com/ipni/go-libipni/announce/message" pubsub "github.com/libp2p/go-libp2p-pubsub" pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb" "github.com/libp2p/go-libp2p/core/peer" + "github.com/sirupsen/logrus" "github.com/thejerf/suture/v4" "github.com/probe-lab/hermes/host" @@ -200,6 +202,23 @@ func (p *PubSub) handleF3Granite(ctx context.Context, msg *pubsub.Message) error PeerID: p.host.ID(), Timestamp: time.Now(), } + m := gpbft.GMessage{} + if err := m.UnmarshalCBOR(bytes.NewBuffer(msg.Data)); err != nil { + logrus.WithError(err).Error("failed to unmarshal manifest f3 granite message") + return fmt.Errorf("unmarshal cbor: %w", err) + } + + evt.Payload = map[string]any{ + "PeerID": msg.ReceivedFrom, + "Topic": msg.GetTopic(), + "Seq": hex.EncodeToString(msg.GetSeqno()), + "MsgID": hex.EncodeToString([]byte(msg.ID)), + "MsgSize": len(msg.Data), + "Sender": m.Sender, + "Justification": m.Justification, + "Ticket": m.Ticket, + "Vote": m.Vote, + } if err := p.cfg.DataStream.PutRecord(ctx, evt); err != nil { slog.Warn( @@ -219,6 +238,23 @@ func (p *PubSub) handleF3Manifests(ctx context.Context, msg *pubsub.Message) err Timestamp: time.Now(), } + var update manifest.ManifestUpdateMessage + err := update.Unmarshal(bytes.NewReader(msg.Data)) + if err != nil { + logrus.WithError(err).Error("failed to unmarshal f3 manifest update message") + return fmt.Errorf("unmarshal cbor: %w", err) + } + + evt.Payload = map[string]any{ + "PeerID": msg.ReceivedFrom, + "Topic": msg.GetTopic(), + "Seq": hex.EncodeToString(msg.GetSeqno()), + "MsgID": hex.EncodeToString([]byte(msg.ID)), + "MsgSize": len(msg.Data), + "Manifest": update.Manifest, + "MsgSeq": update.MessageSequence, + } + if err := p.cfg.DataStream.PutRecord(ctx, evt); err != nil { slog.Warn( "failed putting topic handler event", "topic", msg.GetTopic(), "err", tele.LogAttrError(err), diff --git a/go.mod b/go.mod index 8886b86..cc3a43f 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/dennis-tra/go-kinesis v0.0.0-20240326083914-7acf5f8dc24e github.com/ethereum/go-ethereum v1.15.9 github.com/ferranbt/fastssz v0.1.4 + github.com/filecoin-project/go-f3 v0.8.3 github.com/filecoin-project/lotus v1.32.2 github.com/google/uuid v1.6.0 github.com/hashicorp/golang-lru/v2 v2.0.7 @@ -98,6 +99,7 @@ require ( github.com/filecoin-project/go-amt-ipld/v3 v3.1.0 // indirect github.com/filecoin-project/go-amt-ipld/v4 v4.4.0 // indirect github.com/filecoin-project/go-bitfield v0.2.4 // indirect + github.com/filecoin-project/go-clock v0.1.0 // indirect github.com/filecoin-project/go-hamt-ipld v0.1.5 // indirect github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 // indirect github.com/filecoin-project/go-hamt-ipld/v3 v3.4.0 // indirect diff --git a/go.sum b/go.sum index 05cea15..d76f354 100644 --- a/go.sum +++ b/go.sum @@ -249,9 +249,13 @@ github.com/filecoin-project/go-bitfield v0.2.4 h1:uZ7MeE+XfM5lqrHJZ93OnhQKc/rveW github.com/filecoin-project/go-bitfield v0.2.4/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= github.com/filecoin-project/go-cbor-util v0.0.1 h1:E1LYZYTtjfAQwCReho0VXvbu8t3CYAVPiMx8EiV/VAs= github.com/filecoin-project/go-cbor-util v0.0.1/go.mod h1:pqTiPHobNkOVM5thSRsHYjyQfq7O5QSCMhvuu9JoDlg= +github.com/filecoin-project/go-clock v0.1.0 h1:SFbYIM75M8NnFm1yMHhN9Ahy3W5bEZV9gd6MPfXbKVU= +github.com/filecoin-project/go-clock v0.1.0/go.mod h1:4uB/O4PvOjlx1VCMdZ9MyDZXRm//gkj1ELEbxfI1AZs= github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= github.com/filecoin-project/go-crypto v0.1.0 h1:Pob2MphoipMbe/ksxZOMcQvmBHAd3sI/WEqcbpIsGI0= github.com/filecoin-project/go-crypto v0.1.0/go.mod h1:K9UFXvvoyAVvB+0Le7oGlKiT9mgA5FHOJdYQXEE8IhI= +github.com/filecoin-project/go-f3 v0.8.3 h1:0ToWoqJDsunr+Jf945Upvk6rdXn8It5B5LcyiY1Ry1k= +github.com/filecoin-project/go-f3 v0.8.3/go.mod h1:KWksfw7CabMuL4ple/J52gK4soYBpTsL6i5WAgtJDqw= github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM= github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24= github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 h1:b3UDemBYN2HNfk3KOXNuxgTTxlWi3xVvbQP0IT38fvM= @@ -1103,6 +1107,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= From 69e709a17b5afc4235b43a3721ecee31625a0479 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 28 Apr 2025 12:26:06 +0200 Subject: [PATCH 05/65] filecoin: remove dial concurrency parameter --- cmd/hermes/cmd_fil.go | 9 --------- fil/node_config.go | 10 ---------- 2 files changed, 19 deletions(-) diff --git a/cmd/hermes/cmd_fil.go b/cmd/hermes/cmd_fil.go index ae5ce67..4d7ccfc 100644 --- a/cmd/hermes/cmd_fil.go +++ b/cmd/hermes/cmd_fil.go @@ -21,7 +21,6 @@ var filConfig = &struct { Libp2pPort int Libp2pPeerscoreSnapshotFreq time.Duration BootrapperMaddrs *cli.StringSlice - DialConcurrency int DialTimeout time.Duration }{ PrivateKeyStr: "", // unset means it'll be generated @@ -29,7 +28,6 @@ var filConfig = &struct { Libp2pPort: 0, Libp2pPeerscoreSnapshotFreq: 60 * time.Second, BootrapperMaddrs: cli.NewStringSlice(), - DialConcurrency: 16, DialTimeout: 5 * time.Second, } @@ -52,13 +50,6 @@ var cmdFilFlags = []cli.Flag{ Destination: &filConfig.PrivateKeyStr, Action: validateKeyFlag, }, - &cli.IntFlag{ - Name: "dial.concurrency", - EnvVars: []string{"HERMES_FIL_DIAL_CONCURRENCY"}, - Usage: "The maximum number of parallel workers dialing other peers in the network", - Value: filConfig.DialConcurrency, - Destination: &filConfig.DialConcurrency, - }, &cli.DurationFlag{ Name: "dial.timeout", EnvVars: []string{"HERMES_FIL_DIAL_TIMEOUT"}, diff --git a/fil/node_config.go b/fil/node_config.go index 1630fc1..e09dffc 100644 --- a/fil/node_config.go +++ b/fil/node_config.go @@ -50,12 +50,6 @@ type NodeConfig struct { KinesisRegion string KinesisStream string - // Limits the number of concurrent connection establishment routines. When - // we discover peers over discv5 and are not at our MaxPeers limit we try - // to establish a connection to a peer. However, we limit the concurrency to - // this DialConcurrency value. - DialConcurrency int - // Telemetry accessors Tracer trace.Tracer Meter metric.Meter @@ -79,10 +73,6 @@ func (n *NodeConfig) Validate() error { return fmt.Errorf("no valid bootstrapper multiaddresses provided, please check the --bootstrappers flag") } - if n.DialConcurrency <= 0 { - return fmt.Errorf("dialer count must be positive, got %d", n.DialConcurrency) - } - // ensure that if the data stream is AWS, the parameters where given if n.DataStreamType == host.DataStreamTypeKinesis { if n.AWSConfig != nil { From 9ce82efb7e56ad9663645c301479adcbd6771213 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 28 Apr 2025 12:26:21 +0200 Subject: [PATCH 06/65] filecoin: use configuration profiles --- cmd/hermes/cmd_fil.go | 51 ++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/cmd/hermes/cmd_fil.go b/cmd/hermes/cmd_fil.go index 4d7ccfc..00527b7 100644 --- a/cmd/hermes/cmd_fil.go +++ b/cmd/hermes/cmd_fil.go @@ -20,14 +20,14 @@ var filConfig = &struct { Libp2pHost string Libp2pPort int Libp2pPeerscoreSnapshotFreq time.Duration - BootrapperMaddrs *cli.StringSlice + Network string DialTimeout time.Duration }{ PrivateKeyStr: "", // unset means it'll be generated Libp2pHost: "127.0.0.1", Libp2pPort: 0, Libp2pPeerscoreSnapshotFreq: 60 * time.Second, - BootrapperMaddrs: cli.NewStringSlice(), + Network: "mainnet", DialTimeout: 5 * time.Second, } @@ -37,7 +37,6 @@ var cmdFil = &cli.Command{ Usage: "Listen to gossipsub topics of the Filecoin network", Flags: cmdFilFlags, Action: cmdFilAction, - Before: cmdFilBefore, } var cmdFilFlags = []cli.Flag{ @@ -72,13 +71,12 @@ var cmdFilFlags = []cli.Flag{ Destination: &filConfig.Libp2pPort, DefaultText: "random", }, - &cli.StringSliceFlag{ - Name: "bootstrappers", - EnvVars: []string{"HERMES_FIL_BOOTSTRAPPERS"}, - Usage: "The peer multi addresses to use for connecting to the Filecoin network", - Value: filConfig.BootrapperMaddrs, - Destination: filConfig.BootrapperMaddrs, - DefaultText: "mainnet", + &cli.StringFlag{ + Name: "network", + EnvVars: []string{"HERMES_FIL_NETWORK"}, + Usage: "Which network hermes should connect to. Currently only 'mainnet' is supported.", + Value: filConfig.Network, + Destination: &filConfig.Network, }, &cli.DurationFlag{ Name: "libp2p.peerscore.snapshot.frequency", @@ -90,9 +88,17 @@ var cmdFilFlags = []cli.Flag{ }, } -func cmdFilBefore(c *cli.Context) error { - if !c.IsSet("bootstrappers") { - filConfig.BootrapperMaddrs = cli.NewStringSlice( +func cmdFilAction(c *cli.Context) error { + slog.Info("Starting Hermes for Filecoin...") + defer slog.Info("Stopped Hermes for Filecoin.") + + // Print hermes configuration for debugging purposes + printFilConfig() + + var bootstrapperMaddrStrs []string + switch filConfig.Network { + case "mainnet": + bootstrapperMaddrStrs = []string{ "/dns/node.glif.io/tcp/1235/p2p/12D3KooWBF8cpp65hp2u9LK5mh19x67ftAam84z9LsfaquTDSBpt", "/dns/bootstrap-venus.mainnet.filincubator.com/tcp/8888/p2p/QmQu8C6deXwKvJP2D8B6QGyhngc3ZiDnFzEHBDx8yeBXST", "/dns/bootstrap-mainnet-0.chainsafe-fil.io/tcp/34000/p2p/12D3KooWKKkCZbcigsWTEu1cgNetNbZJqeNtysRtFpq7DTqw3eqH", @@ -101,21 +107,13 @@ func cmdFilBefore(c *cli.Context) error { "/dns/n1.mainnet.fil.devtty.eu/udp/443/quic-v1/p2p/12D3KooWAke3M2ji7tGNKx3BQkTHCyxVhtV1CN68z6Fkrpmfr37F", "/dns/n1.mainnet.fil.devtty.eu/tcp/443/p2p/12D3KooWAke3M2ji7tGNKx3BQkTHCyxVhtV1CN68z6Fkrpmfr37F", "/dns/n1.mainnet.fil.devtty.eu/udp/443/quic-v1/webtransport/certhash/uEiAWlgd8EqbNhYLv86OdRvXHMosaUWFFDbhgGZgCkcmKnQ/certhash/uEiAvtq6tvZOZf_sIuityDDTyAXDJPfXSRRDK2xy9UVPsqA/p2p/12D3KooWAke3M2ji7tGNKx3BQkTHCyxVhtV1CN68z6Fkrpmfr37F", - ) + } + default: + return fmt.Errorf("unknown network: %s", filConfig.Network) } - return nil -} - -func cmdFilAction(c *cli.Context) error { - slog.Info("Starting Hermes for Filecoin...") - defer slog.Info("Stopped Hermes for Filecoin.") - - // Print hermes configuration for debugging purposes - printFilConfig() - - bootstrappers := make([]peer.AddrInfo, len(filConfig.BootrapperMaddrs.Value())) - for i, maddrStr := range filConfig.BootrapperMaddrs.Value() { + bootstrappers := make([]peer.AddrInfo, len(bootstrapperMaddrStrs)) + for i, maddrStr := range bootstrapperMaddrStrs { bp, err := peer.AddrInfoFromString(maddrStr) if err != nil { slog.Warn("Failed parsing bootstrapper multiaddress", slog.String("maddr", maddrStr), tele.LogAttrError(err)) @@ -136,7 +134,6 @@ func cmdFilAction(c *cli.Context) error { S3Config: rootConfig.s3Config, KinesisRegion: rootConfig.KinesisRegion, KinesisStream: rootConfig.KinesisStream, - DialConcurrency: filConfig.DialConcurrency, Tracer: otel.GetTracerProvider().Tracer("hermes"), Meter: otel.GetMeterProvider().Meter("hermes"), } From c44837186de2b99c7f5c308a5253402bb4368927 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 28 Apr 2025 14:13:45 +0200 Subject: [PATCH 07/65] fix: typos --- README.md | 4 ++-- cmd/hermes/cmd.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 04eb720..ae0fd13 100644 --- a/README.md +++ b/README.md @@ -73,8 +73,8 @@ GLOBAL OPTIONS: --data.stream.type value Format where the traces will be submitted: logger, kinesis, or callback. (default: "logger") [$HERMES_DATA_STREAM_TYPE] --kinesis.region value The region of the AWS Kinesis Data Stream [$HERMES_KINESIS_REGION] --kinesis.stream value The name of the AWS Kinesis Data Stream [$HERMES_KINESIS_DATA_STREAM] - --s3.bucket value name of the S3 bucket that will be used as reference to submit the traces (default: "hermes") [$HERMES_S3_BUCKET] - --s3.byte.limit value Soft upper limite of bytes for the S3 dumps (default: 10485760) [$HERMES_S3_BYTE_LIMIT] + --s3.bucket value Name of the S3 bucket that will be used as reference to submit the traces (default: "hermes") [$HERMES_S3_BUCKET] + --s3.byte.limit value Soft upper limit of bytes for the S3 dumps (default: 10485760) [$HERMES_S3_BYTE_LIMIT] --s3.endpoint value The endpoint of our custom S3 instance to override the AWS defaults [$HERMES_S3_CUSTOM_ENDPOINT] --s3.flush.interval value Minimum time interval at which the batched traces will be dump in S3 (default: 2s) [$HERMES_S3_FLUSH_INTERVAL] --s3.flushers value Number of flushers that will be spawned to dump traces into S3 (default: 2) [$HERMES_S3_FLUSHERS] diff --git a/cmd/hermes/cmd.go b/cmd/hermes/cmd.go index 76c154b..c3e2fa0 100644 --- a/cmd/hermes/cmd.go +++ b/cmd/hermes/cmd.go @@ -238,7 +238,7 @@ var rootFlags = []cli.Flag{ &cli.StringFlag{ Name: "s3.bucket", EnvVars: []string{"HERMES_S3_BUCKET"}, - Usage: "name of the S3 bucket that will be used as reference to submit the traces", + Usage: "Name of the S3 bucket that will be used as reference to submit the traces", Value: rootConfig.S3Bucket, Destination: &rootConfig.S3Bucket, Category: flagCategoryDataStream, @@ -246,7 +246,7 @@ var rootFlags = []cli.Flag{ &cli.StringFlag{ Name: "s3.tag", EnvVars: []string{"HERMES_S3_TAG"}, - Usage: "tag within the S3 bucket that will be used as reference to submit the traces", + Usage: "Tag within the S3 bucket that will be used as reference to submit the traces", Value: rootConfig.S3Tag, Destination: &rootConfig.S3Tag, Category: flagCategoryDataStream, @@ -254,7 +254,7 @@ var rootFlags = []cli.Flag{ &cli.IntFlag{ Name: "s3.byte.limit", EnvVars: []string{"HERMES_S3_BYTE_LIMIT"}, - Usage: "Soft upper limite of bytes for the S3 dumps", + Usage: "Soft upper limit of bytes for the S3 dumps", Value: rootConfig.S3ByteLimit, Destination: &rootConfig.S3ByteLimit, Category: flagCategoryDataStream, From a6e7de26e2623d36c06be991d0bd6cb4ce478efa Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 28 Apr 2025 14:13:50 +0200 Subject: [PATCH 08/65] go mod tidy --- go.mod | 2 +- go.sum | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/go.mod b/go.mod index cc3a43f..9c8ec37 100644 --- a/go.mod +++ b/go.mod @@ -31,6 +31,7 @@ require ( github.com/prometheus/client_golang v1.22.0 github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516 github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 + github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.10.0 github.com/thejerf/suture/v4 v4.0.6 github.com/urfave/cli/v2 v2.27.5 @@ -240,7 +241,6 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/progressbar/v3 v3.17.1 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/supranational/blst v0.3.14 // indirect diff --git a/go.sum b/go.sum index d76f354..3cb654f 100644 --- a/go.sum +++ b/go.sum @@ -1569,8 +1569,6 @@ k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJ k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -lukechampine.com/blake3 v1.4.0 h1:xDbKOZCVbnZsfzM6mHSYcGRHZ3YrLDzqz8XnV4uaD5w= -lukechampine.com/blake3 v1.4.0/go.mod h1:MQJNQCTnR+kwOP/JEZSxj3MaQjp80FOFSNMMHXcSeX0= lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= From feabc209b208d50dd1d76f6a069c65c4b7c32c2d Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 28 Apr 2025 16:08:05 +0200 Subject: [PATCH 09/65] filecoin: remove log message --- fil/discovery.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fil/discovery.go b/fil/discovery.go index 6a121b5..81034cf 100644 --- a/fil/discovery.go +++ b/fil/discovery.go @@ -68,7 +68,7 @@ func (d *Discovery) Serve(ctx context.Context) (err error) { return fmt.Errorf("failed to generate random key: %w", err) } start := time.Now() - slog.Info("NEW LOOKUP") + peers, err := dht.GetClosestPeers(ctx, string(k)) if errors.Is(err, context.Canceled) { return nil From baa83b17b3257af8c1b11db5a76ea78734fa4d29 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Tue, 29 Apr 2025 14:52:20 +0200 Subject: [PATCH 10/65] filecoin: update message validation and metrics --- cmd/hermes/cmd_fil.go | 2 +- fil/encoding.go | 120 +++++++++++++++++++++++++++++++++ fil/node.go | 23 +++---- fil/psutil.go | 150 ++++++++++++++++++++++++++++++++++++++++++ fil/pubsub.go | 99 +++++++++++++++++++++++----- host/host.go | 84 ++++++++++++++++++++++- 6 files changed, 447 insertions(+), 31 deletions(-) create mode 100644 fil/encoding.go create mode 100644 fil/psutil.go diff --git a/cmd/hermes/cmd_fil.go b/cmd/hermes/cmd_fil.go index 00527b7..6897437 100644 --- a/cmd/hermes/cmd_fil.go +++ b/cmd/hermes/cmd_fil.go @@ -26,7 +26,7 @@ var filConfig = &struct { PrivateKeyStr: "", // unset means it'll be generated Libp2pHost: "127.0.0.1", Libp2pPort: 0, - Libp2pPeerscoreSnapshotFreq: 60 * time.Second, + Libp2pPeerscoreSnapshotFreq: 15 * time.Second, Network: "mainnet", DialTimeout: 5 * time.Second, } diff --git a/fil/encoding.go b/fil/encoding.go new file mode 100644 index 0000000..bdbea83 --- /dev/null +++ b/fil/encoding.go @@ -0,0 +1,120 @@ +package fil + +// Taken from: https://github.com/filecoin-project/go-f3/blob/main/internal/encoding/encoding.go +// Permalink: https://github.com/filecoin-project/go-f3/blob/fd3ef15f457bf01a01f10ac6748acdfbd7657ed6/internal/encoding/encoding.go#L1 + +import ( + "bytes" + "fmt" + "reflect" + "sync" + + "github.com/klauspost/compress/zstd" + cbg "github.com/whyrusleeping/cbor-gen" + "go.opentelemetry.io/otel/attribute" +) + +// maxDecompressedSize is the default maximum amount of memory allocated by the +// zstd decoder. The limit of 1MiB is chosen based on the default maximum message +// size in GossipSub. +const maxDecompressedSize = 1 << 20 + +var bufferPool = sync.Pool{ + New: func() any { + buf := make([]byte, maxDecompressedSize) + return &buf + }, +} + +type CBORMarshalUnmarshaler interface { + cbg.CBORMarshaler + cbg.CBORUnmarshaler +} + +type EncodeDecoder[T CBORMarshalUnmarshaler] interface { + Encode(v T) ([]byte, error) + Decode([]byte, T) error +} + +type CBOR[T CBORMarshalUnmarshaler] struct{} + +func NewCBOR[T CBORMarshalUnmarshaler]() *CBOR[T] { + return &CBOR[T]{} +} + +func (c *CBOR[T]) Encode(m T) (_ []byte, _err error) { + var out bytes.Buffer + if err := m.MarshalCBOR(&out); err != nil { + return nil, err + } + return out.Bytes(), nil +} + +func (c *CBOR[T]) Decode(v []byte, t T) (_err error) { + r := bytes.NewReader(v) + return t.UnmarshalCBOR(r) +} + +type ZSTD[T CBORMarshalUnmarshaler] struct { + cborEncoding *CBOR[T] + compressor *zstd.Encoder + decompressor *zstd.Decoder + + metricAttr attribute.KeyValue + metricAttrLoader sync.Once +} + +func NewZSTD[T CBORMarshalUnmarshaler]() (*ZSTD[T], error) { + writer, err := zstd.NewWriter(nil) + if err != nil { + return nil, err + } + reader, err := zstd.NewReader(nil, + zstd.WithDecoderMaxMemory(maxDecompressedSize), + zstd.WithDecodeAllCapLimit(true)) + if err != nil { + return nil, err + } + return &ZSTD[T]{ + cborEncoding: &CBOR[T]{}, + compressor: writer, + decompressor: reader, + }, nil +} + +func (c *ZSTD[T]) Encode(t T) (_ []byte, _err error) { + decompressed, err := c.cborEncoding.Encode(t) + if len(decompressed) > maxDecompressedSize { + // Error out early if the encoded value is too large to be decompressed. + return nil, fmt.Errorf("encoded value cannot exceed maximum size: %d > %d", len(decompressed), maxDecompressedSize) + } + if err != nil { + return nil, err + } + maxCompressedSize := c.compressor.MaxEncodedSize(len(decompressed)) + compressed := c.compressor.EncodeAll(decompressed, make([]byte, 0, maxCompressedSize)) + return compressed, nil +} + +func (c *ZSTD[T]) Decode(compressed []byte, t T) (_err error) { + buf := bufferPool.Get().(*[]byte) + defer bufferPool.Put(buf) + decompressed, err := c.decompressor.DecodeAll(compressed, (*buf)[:0]) + if err != nil { + return err + } + return c.cborEncoding.Decode(decompressed, t) +} + +func (c *ZSTD[T]) getMetricAttribute() attribute.KeyValue { + c.metricAttrLoader.Do(func() { + const key = "type" + switch target := reflect.TypeFor[T](); { + case target.Kind() == reflect.Ptr: + c.metricAttr = attribute.String(key, target.Elem().Name()) + default: + c.metricAttr = attribute.String(key, target.Name()) + } + }) + return c.metricAttr +} diff --git a/fil/node.go b/fil/node.go index c54995a..93b157c 100644 --- a/fil/node.go +++ b/fil/node.go @@ -12,6 +12,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/kinesis" gk "github.com/dennis-tra/go-kinesis" + pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/thejerf/suture/v4" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" @@ -144,17 +145,17 @@ func NewNode(cfg *NodeConfig) (*Node, error) { // initialize the pubsub topic handlers pubSubConfig := &PubSubConfig{ - Topics: []string{ - "/drand/pubsub/v0.0.0/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971", - "/drand/pubsub/v0.0.0/80c8b872c714f4c00fdd3daa465d5514049f457f01f85a4caf68cdcd394ba039", - "/drand/pubsub/v0.0.0/8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce", - "/f3/chainexchange/0.0.1/filecoin/62", - "/f3/granite/0.0.3/filecoin/62", - "/f3/manifests/0.0.1", - "/f3/manifests/0.0.2", - "/fil/blocks/testnetnet", - "/fil/msgs/testnetnet", - "/indexer/ingest/mainnet", + Topics: map[string][]pubsub.TopicOpt{ + "/f3/granite/0.0.3/filecoin": {pubsub.WithTopicMessageIdFn(GPBFTMessageIdFn)}, + "/f3/chainexchange/0.0.1/filecoin": {pubsub.WithTopicMessageIdFn(ChainExchangeMessageIdFn)}, + "/f3/manifests/0.0.1": {pubsub.WithTopicMessageIdFn(ManifestMessageIdFn)}, + "/f3/manifests/0.0.2": {pubsub.WithTopicMessageIdFn(ManifestMessageIdFn)}, + "/drand/pubsub/v0.0.0/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971": {}, + "/drand/pubsub/v0.0.0/80c8b872c714f4c00fdd3daa465d5514049f457f01f85a4caf68cdcd394ba039": {}, + "/drand/pubsub/v0.0.0/8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce": {}, + "/fil/blocks/testnetnet": {}, + "/fil/msgs/testnetnet": {}, + "/indexer/ingest/mainnet": {}, }, DataStream: ds, } diff --git a/fil/psutil.go b/fil/psutil.go new file mode 100644 index 0000000..0bc4b17 --- /dev/null +++ b/fil/psutil.go @@ -0,0 +1,150 @@ +package fil + +// Taken from: https://github.com/filecoin-project/go-f3/blob/main/internal/psutil/psutil.go +// Permalink: https://github.com/filecoin-project/go-f3/blob/fd3ef15f457bf01a01f10ac6748acdfbd7657ed6/internal/psutil/psutil.go#L1 + +import ( + "encoding/binary" + "time" + + "github.com/libp2p/go-libp2p/core/peer" + "golang.org/x/crypto/blake2b" + + pubsub "github.com/libp2p/go-libp2p-pubsub" + pubsub_pb "github.com/libp2p/go-libp2p-pubsub/pb" +) + +var ( + ManifestMessageIdFn = pubsubMsgIdHashDataAndSender + GPBFTMessageIdFn = pubsubMsgIdHashData + ChainExchangeMessageIdFn = pubsubMsgIdHashData +) + +// Generate a pubsub ID from the message topic + data. +func pubsubMsgIdHashData(m *pubsub_pb.Message) string { + hasher, err := blake2b.New256(nil) + if err != nil { + panic("failed to construct hasher") + } + + topic := []byte(m.GetTopic()) + if err := binary.Write(hasher, binary.BigEndian, uint32(len(topic))); err != nil { + panic(err) + } + if _, err := hasher.Write(topic); err != nil { + panic(err) + } + if _, err := hasher.Write(m.Data); err != nil { + panic(err) + } + hash := hasher.Sum(nil) + return string(hash[:]) +} + +// Generate a pubsub ID from the message topic + sender + data. +func pubsubMsgIdHashDataAndSender(m *pubsub_pb.Message) string { + hasher, err := blake2b.New256(nil) + if err != nil { + panic("failed to construct hasher") + } + + topic := []byte(m.GetTopic()) + if err := binary.Write(hasher, binary.BigEndian, uint32(len(topic))); err != nil { + panic(err) + } + if _, err := hasher.Write(topic); err != nil { + panic(err) + } + if err := binary.Write(hasher, binary.BigEndian, uint32(len(m.From))); err != nil { + panic(err) + } + if _, err := hasher.Write(m.From); err != nil { + panic(err) + } + if _, err := hasher.Write(m.Data); err != nil { + panic(err) + } + hash := hasher.Sum(nil) + return string(hash[:]) +} + +// Borrowed from lotus +var PubsubTopicScoreParams = &pubsub.TopicScoreParams{ + // expected > 400 msgs/second on average. + // + TopicWeight: 0.1, // max cap is 5, single invalid message is -100 + + // 1 tick per second, maxes at 1 hour + // XXX + TimeInMeshWeight: 0.0002778, // ~1/3600 + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 1, + + // NOTE: Gives weight to the peer that tends to deliver first. + // deliveries decay after 10min, cap at 100 tx + FirstMessageDeliveriesWeight: 0.5, // max value is 50 + FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(10 * time.Minute), + FirstMessageDeliveriesCap: 100, // 100 messages in 10 minutes + + // Mesh Delivery Failure is currently turned off for messages + // This is on purpose as the network is still too small, which results in + // asymmetries and potential unmeshing from negative scores. + // // tracks deliveries in the last minute + // // penalty activates at 1 min and expects 2.5 txs + // MeshMessageDeliveriesWeight: -16, // max penalty is -100 + // MeshMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Minute), + // MeshMessageDeliveriesCap: 100, // 100 txs in a minute + // MeshMessageDeliveriesThreshold: 2.5, // 60/12/2 txs/minute + // MeshMessageDeliveriesWindow: 10 * time.Millisecond, + // MeshMessageDeliveriesActivation: time.Minute, + + // // decays after 5min + // MeshFailurePenaltyWeight: -16, + // MeshFailurePenaltyDecay: pubsub.ScoreParameterDecay(5 * time.Minute), + + // invalid messages decay after 1 hour + InvalidMessageDeliveriesWeight: -1000, + InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), +} + +// Borrowed from lotus +var PubsubPeerScoreParams = &pubsub.PeerScoreParams{ + AppSpecificScore: func(p peer.ID) float64 { return 0 }, + AppSpecificWeight: 1, + + // This sets the IP colocation threshold to 5 peers before we apply penalties + IPColocationFactorThreshold: 5, + IPColocationFactorWeight: -100, + IPColocationFactorWhitelist: nil, + + // P7: behavioural penalties, decay after 1hr + BehaviourPenaltyThreshold: 6, + BehaviourPenaltyWeight: -10, + BehaviourPenaltyDecay: pubsub.ScoreParameterDecay(time.Hour), + + DecayInterval: pubsub.DefaultDecayInterval, + DecayToZero: pubsub.DefaultDecayToZero, + + // this retains non-positive scores for 6 hours + RetainScore: 6 * time.Hour, + + // topic parameters + Topics: make(map[string]*pubsub.TopicScoreParams), +} + +var PubsubPeerScoreThresholds = &pubsub.PeerScoreThresholds{ + GossipThreshold: GossipScoreThreshold, + PublishThreshold: PublishScoreThreshold, + GraylistThreshold: GraylistScoreThreshold, + AcceptPXThreshold: AcceptPXScoreThreshold, + OpportunisticGraftThreshold: OpportunisticGraftScoreThreshold, +} + +// Borrowed from lotus +const ( + GossipScoreThreshold = -500 + PublishScoreThreshold = -1000 + GraylistScoreThreshold = -2500 + AcceptPXScoreThreshold = 1000 + OpportunisticGraftScoreThreshold = 3.5 +) diff --git a/fil/pubsub.go b/fil/pubsub.go index 7215639..bb81c46 100644 --- a/fil/pubsub.go +++ b/fil/pubsub.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "github.com/filecoin-project/go-f3/chainexchange" "github.com/filecoin-project/go-f3/gpbft" "github.com/filecoin-project/go-f3/manifest" "github.com/filecoin-project/lotus/chain/types" @@ -26,7 +27,7 @@ import ( const eventTypeHandleMessage = "HANDLE_MESSAGE" type PubSubConfig struct { - Topics []string + Topics map[string][]pubsub.TopicOpt DataStream host.DataStream } @@ -58,8 +59,20 @@ func (p *PubSub) Serve(ctx context.Context) error { supervisor := suture.NewSimple("pubsub") - for _, topicName := range p.cfg.Topics { - topic, err := p.gs.Join(topicName) + for topicName, topicOpts := range p.cfg.Topics { + + var err error + switch { + case strings.HasPrefix(topicName, "/f3/granite"): + err = p.gs.RegisterTopicValidator(topicName, p.validateF3Granite) + case strings.HasPrefix(topicName, "/f3/chainexchange"): + err = p.gs.RegisterTopicValidator(topicName, p.validateF3ChainExchange) + } + if err != nil { + return fmt.Errorf("register topic validator %s: %w", topicName, err) + } + + topic, err := p.gs.Join(topicName, topicOpts...) if err != nil { return fmt.Errorf("join pubsub topic %s: %w", topicName, err) } @@ -88,10 +101,12 @@ func (p *PubSub) Serve(ctx context.Context) error { func (p *PubSub) mapPubSubTopicWithHandlers(topic string) host.TopicHandler { switch { - case strings.HasPrefix(topic, "/f3/manifests/0.0.2"): + case strings.HasPrefix(topic, "/f3/manifests"): return p.handleF3Manifests - case strings.HasPrefix(topic, "/f3/granite/0.0.3/filecoin"): + case strings.HasPrefix(topic, "/f3/granite"): return p.handleF3Granite + case strings.HasPrefix(topic, "/f3/chainexchange"): + return p.handleF3ChainExchange case topic == "/fil/msgs/testnetnet": return p.handleFilMessage case topic == "/indexer/ingest/mainnet": @@ -194,19 +209,23 @@ func (p *PubSub) handleIndexerIngest(ctx context.Context, msg *pubsub.Message) e return nil } +func (p *PubSub) validateF3Granite(ctx context.Context, _ peer.ID, msg *pubsub.Message) pubsub.ValidationResult { + var gmsg gpbft.GMessage + if err := gmsg.UnmarshalCBOR(bytes.NewReader(msg.Data)); err != nil { + return pubsub.ValidationReject + } + msg.ValidatorData = gmsg + return pubsub.ValidationAccept +} + func (p *PubSub) handleF3Granite(ctx context.Context, msg *pubsub.Message) error { - // err error evt := &host.TraceEvent{ Type: eventTypeHandleMessage, Topic: msg.GetTopic(), PeerID: p.host.ID(), Timestamp: time.Now(), } - m := gpbft.GMessage{} - if err := m.UnmarshalCBOR(bytes.NewBuffer(msg.Data)); err != nil { - logrus.WithError(err).Error("failed to unmarshal manifest f3 granite message") - return fmt.Errorf("unmarshal cbor: %w", err) - } + gmsg := msg.ValidatorData.(gpbft.GMessage) evt.Payload = map[string]any{ "PeerID": msg.ReceivedFrom, @@ -214,10 +233,10 @@ func (p *PubSub) handleF3Granite(ctx context.Context, msg *pubsub.Message) error "Seq": hex.EncodeToString(msg.GetSeqno()), "MsgID": hex.EncodeToString([]byte(msg.ID)), "MsgSize": len(msg.Data), - "Sender": m.Sender, - "Justification": m.Justification, - "Ticket": m.Ticket, - "Vote": m.Vote, + "Sender": gmsg.Sender, + "Justification": gmsg.Justification, + "Ticket": gmsg.Ticket, + "Vote": gmsg.Vote, } if err := p.cfg.DataStream.PutRecord(ctx, evt); err != nil { @@ -230,7 +249,6 @@ func (p *PubSub) handleF3Granite(ctx context.Context, msg *pubsub.Message) error } func (p *PubSub) handleF3Manifests(ctx context.Context, msg *pubsub.Message) error { - // err error evt := &host.TraceEvent{ Type: eventTypeHandleMessage, Topic: msg.GetTopic(), @@ -255,6 +273,55 @@ func (p *PubSub) handleF3Manifests(ctx context.Context, msg *pubsub.Message) err "MsgSeq": update.MessageSequence, } + if err = p.cfg.DataStream.PutRecord(ctx, evt); err != nil { + slog.Warn( + "failed putting topic handler event", "topic", msg.GetTopic(), "err", tele.LogAttrError(err), + ) + } + + return nil +} + +func (p *PubSub) validateF3ChainExchange(ctx context.Context, _ peer.ID, msg *pubsub.Message) pubsub.ValidationResult { + var cmsg chainexchange.Message + enc := NewCBOR[*chainexchange.Message]() + if err := enc.Decode(msg.Data, &cmsg); err != nil { + return pubsub.ValidationReject + } + + if cmsg.Chain.IsZero() { + return pubsub.ValidationReject + } + + if err := cmsg.Chain.Validate(); err != nil { + return pubsub.ValidationReject + } + + msg.ValidatorData = cmsg + return pubsub.ValidationAccept +} + +func (p *PubSub) handleF3ChainExchange(ctx context.Context, msg *pubsub.Message) error { + evt := &host.TraceEvent{ + Type: eventTypeHandleMessage, + Topic: msg.GetTopic(), + PeerID: p.host.ID(), + Timestamp: time.Now(), + } + + cmsg := msg.ValidatorData.(chainexchange.Message) + + evt.Payload = map[string]any{ + "PeerID": msg.ReceivedFrom, + "Topic": msg.GetTopic(), + "Seq": hex.EncodeToString(msg.GetSeqno()), + "MsgID": hex.EncodeToString([]byte(msg.ID)), + "MsgSize": len(msg.Data), + "Chain": cmsg.Chain, + "Instance": cmsg.Instance, + "Timestamp": cmsg.Timestamp, + } + if err := p.cfg.DataStream.PutRecord(ctx, evt); err != nil { slog.Warn( "failed putting topic handler event", "topic", msg.GetTopic(), "err", tele.LogAttrError(err), diff --git a/host/host.go b/host/host.go index 8cc7f61..1d23116 100644 --- a/host/host.go +++ b/host/host.go @@ -19,6 +19,7 @@ import ( ma "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr/net" "github.com/thejerf/suture/v4" + "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" @@ -42,6 +43,10 @@ type Host struct { sk *ScoreKeeper meterSubmittedTraces metric.Int64Counter + meterMeshSize metric.Int64Gauge + meterAvgMeshAge metric.Float64Gauge + meterAvgMeshScore metric.Float64Gauge + meterAvgMeshAppScore metric.Float64Gauge } func New(cfg *Config, opts ...libp2p.Option) (*Host, error) { @@ -67,6 +72,26 @@ func New(cfg *Config, opts ...libp2p.Option) (*Host, error) { return nil, fmt.Errorf("new submitted_traces counter: %w", err) } + hermesHost.meterMeshSize, err = cfg.Meter.Int64Gauge("mesh_size") + if err != nil { + return nil, fmt.Errorf("new mesh_size gauge: %w", err) + } + + hermesHost.meterAvgMeshAge, err = cfg.Meter.Float64Gauge("avg_mesh_age") + if err != nil { + return nil, fmt.Errorf("new avg_mesh_age gauge: %w", err) + } + + hermesHost.meterAvgMeshScore, err = cfg.Meter.Float64Gauge("avg_mesh_score") + if err != nil { + return nil, fmt.Errorf("new avg_mesh_score gauge: %w", err) + } + + hermesHost.meterAvgMeshAppScore, err = cfg.Meter.Float64Gauge("avg_mesh_app_score") + if err != nil { + return nil, fmt.Errorf("new avg_mesh_app_score gauge: %w", err) + } + return hermesHost, nil } @@ -321,6 +346,7 @@ func MaddrFrom(ip string, port uint) (ma.Multiaddr, error) { func (h *Host) UpdatePeerScore(scores map[peer.ID]*pubsub.PeerScoreSnapshot) { // get the event time t := time.Now() + ctx := context.Background() slog.Debug("updating local peerscore:", tele.LogAttrPeerScoresLen(scores)) @@ -332,15 +358,67 @@ func (h *Host) UpdatePeerScore(scores map[peer.ID]*pubsub.PeerScoreSnapshot) { for pid, score := range scores { // get the traceEvent from the raw score mapping scoreData := composePeerScoreEventFromRawMap(pid, score) - trace := &TraceEvent{ + evt := &TraceEvent{ Type: PeerScoreEventType, PeerID: h.ID(), Timestamp: t, Payload: scoreData, } - traceCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + traceCtx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() - h.cfg.DataStream.PutRecord(traceCtx, trace) + if err := h.cfg.DataStream.PutRecord(traceCtx, evt); err != nil { + slog.Warn("failed putting peer score event", tele.LogAttrError(err)) + } + } + + type topicState struct { + meshSize int + meshTimes []float64 + scores []float64 + appScores []float64 + } + + states := map[string]*topicState{} + + for _, pss := range scores { // pss: peer score snapshot + for topic, tss := range pss.Topics { // tss: topic score snapshot + + // Not sure if the peer score map also includes peers that were + // kicked out of the meshes. Therefore, if the time in mesh is 0, + // we don't track that peer. + if tss.TimeInMesh == 0 { + continue + } + + if _, ok := states[topic]; !ok { + states[topic] = &topicState{ + meshSize: 0, + meshTimes: []float64{}, + scores: []float64{}, + appScores: []float64{}, + } + } + + states[topic].meshSize += 1 + states[topic].meshTimes = append(states[topic].meshTimes, tss.TimeInMesh.Seconds()) + states[topic].scores = append(states[topic].scores, pss.Score) + states[topic].appScores = append(states[topic].appScores, pss.AppSpecificScore) + } + } + + for topic, state := range states { + h.meterMeshSize.Record(ctx, int64(state.meshSize), metric.WithAttributes(attribute.String("topic", topic))) + h.meterAvgMeshAge.Record(ctx, avg(state.meshTimes), metric.WithAttributes(attribute.String("topic", topic))) + h.meterAvgMeshScore.Record(ctx, avg(state.scores), metric.WithAttributes(attribute.String("topic", topic))) + h.meterAvgMeshAppScore.Record(ctx, avg(state.appScores), metric.WithAttributes(attribute.String("topic", topic))) + } +} + +func avg(values []float64) float64 { + sum := 0.0 + for _, v := range values { + sum += v } + return sum / float64(len(values)) } From 90a542f3459f35e950aa32a90999a2957e42c49b Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Wed, 30 Apr 2025 13:32:29 +0200 Subject: [PATCH 11/65] add: noop datastream --- cmd/hermes/cmd.go | 2 +- eth/node.go | 4 ++++ host/noop.go | 31 +++++++++++++++++++++++++++++++ host/producer.go | 5 +++++ 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 host/noop.go diff --git a/cmd/hermes/cmd.go b/cmd/hermes/cmd.go index c3e2fa0..0b89f3a 100644 --- a/cmd/hermes/cmd.go +++ b/cmd/hermes/cmd.go @@ -198,7 +198,7 @@ var rootFlags = []cli.Flag{ &cli.StringFlag{ Name: "data.stream.type", EnvVars: []string{"HERMES_DATA_STREAM_TYPE"}, - Usage: "Format where the traces will be submitted: logger, kinesis, or callback.", + Usage: "Format where the traces will be submitted: logger, kinesis, noop, s3 or callback.", Value: rootConfig.DataStreamType, Destination: &rootConfig.DataStreamType, Category: flagCategoryDataStream, diff --git a/eth/node.go b/eth/node.go index 5a9c9fe..bcded24 100644 --- a/eth/node.go +++ b/eth/node.go @@ -127,6 +127,10 @@ func NewNode(cfg *NodeConfig) (*Node, error) { if err != nil { return nil, fmt.Errorf("new s3 producer %w", err) } + + case host.DataStreamTypeNoop: + ds = new(host.NoopDataStream) + default: return nil, fmt.Errorf("not recognised data-stream (%s)", cfg.DataStreamType) } diff --git a/host/noop.go b/host/noop.go new file mode 100644 index 0000000..aa62595 --- /dev/null +++ b/host/noop.go @@ -0,0 +1,31 @@ +package host + +import ( + "context" +) + +type NoopDataStream struct{} + +var _ DataStream = (*NoopDataStream)(nil) + +func (ds *NoopDataStream) Start(ctx context.Context) error { + <-ctx.Done() + return nil +} + +func (ds *NoopDataStream) Stop(ctx context.Context) error { + return nil +} + +func (ds *NoopDataStream) PutRecord(ctx context.Context, event *TraceEvent) error { + return nil +} + +func (ds *NoopDataStream) Type() DataStreamType { + return DataStreamTypeNoop +} + +// OutputType returns the output type to be used by this data stream. +func (ds *NoopDataStream) OutputType() DataStreamOutputType { + return DataStreamOutputTypeKinesis +} diff --git a/host/producer.go b/host/producer.go index 8b331ce..f367b58 100644 --- a/host/producer.go +++ b/host/producer.go @@ -32,6 +32,8 @@ func (ds DataStreamType) String() string { return "callback" case DataStreamTypeS3: return "s3" + case DataStreamTypeNoop: + return "noop" default: return "logger" } @@ -42,6 +44,7 @@ const ( DataStreamTypeCallback DataStreamTypeLogger DataStreamTypeS3 + DataStreamTypeNoop ) func DataStreamtypeFromStr(str string) DataStreamType { @@ -54,6 +57,8 @@ func DataStreamtypeFromStr(str string) DataStreamType { return DataStreamTypeCallback case "s3": return DataStreamTypeS3 + case "noop": + return DataStreamTypeNoop default: return DataStreamTypeLogger } From 0670c47e820673d18991d73cc30e24dadef8c33a Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Wed, 30 Apr 2025 13:32:56 +0200 Subject: [PATCH 12/65] filecoin: update config plumbing --- cmd/hermes/cmd_fil.go | 79 +++++++++++++++++++++++++++++++++++++++++++ fil/discovery.go | 12 +++---- fil/node.go | 25 +++++--------- fil/node_config.go | 74 ++++++---------------------------------- fil/pubsub.go | 25 +++++++++----- 5 files changed, 121 insertions(+), 94 deletions(-) diff --git a/cmd/hermes/cmd_fil.go b/cmd/hermes/cmd_fil.go index 6897437..95b1974 100644 --- a/cmd/hermes/cmd_fil.go +++ b/cmd/hermes/cmd_fil.go @@ -6,6 +6,7 @@ import ( "log/slog" "time" + pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/libp2p/go-libp2p/core/peer" "github.com/urfave/cli/v2" "go.opentelemetry.io/otel" @@ -20,6 +21,7 @@ var filConfig = &struct { Libp2pHost string Libp2pPort int Libp2pPeerscoreSnapshotFreq time.Duration + LookupInterval time.Duration Network string DialTimeout time.Duration }{ @@ -27,6 +29,7 @@ var filConfig = &struct { Libp2pHost: "127.0.0.1", Libp2pPort: 0, Libp2pPeerscoreSnapshotFreq: 15 * time.Second, + LookupInterval: time.Minute, Network: "mainnet", DialTimeout: 5 * time.Second, } @@ -86,6 +89,13 @@ var cmdFilFlags = []cli.Flag{ Destination: &filConfig.Libp2pPeerscoreSnapshotFreq, DefaultText: "random", }, + &cli.DurationFlag{ + Name: "lookup.interval", + EnvVars: []string{"HERMES_FIL_LOOKUP_INTERVAL"}, + Usage: "Time difference between the start time of two consecutive lookups to discover peers", + Value: filConfig.LookupInterval, + Destination: &filConfig.LookupInterval, + }, } func cmdFilAction(c *cli.Context) error { @@ -128,6 +138,8 @@ func cmdFilAction(c *cli.Context) error { Libp2pHost: filConfig.Libp2pHost, Libp2pPort: filConfig.Libp2pPort, Libp2pPeerscoreSnapshotFreq: filConfig.Libp2pPeerscoreSnapshotFreq, + LookupInterval: filConfig.LookupInterval, + TopicConfigs: topicConfigs(), Bootstrappers: bootstrappers, DataStreamType: host.DataStreamtypeFromStr(rootConfig.DataStreamType), AWSConfig: rootConfig.awsConfig, @@ -161,3 +173,70 @@ func printFilConfig() { slog.Info("Config:") slog.Info(string(dat)) } + +func topicConfigs() map[string]*fil.TopicConfig { + // copied from lotus: https://github.com/filecoin-project/lotus/blob/7c4ed2189e3562dcf37861b8e9a15b5fae7d66bd/node/modules/lp2p/pubsub.go#L119 + drandTopicParams := &pubsub.TopicScoreParams{ + TopicWeight: 0.5, + TimeInMeshWeight: 0.00027, // ~1/3600 + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 1, + FirstMessageDeliveriesWeight: 5, + FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + FirstMessageDeliveriesCap: 25, + InvalidMessageDeliveriesWeight: -1000, + InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + } + + // copied from lotus: https://github.com/filecoin-project/lotus/blob/7c4ed2189e3562dcf37861b8e9a15b5fae7d66bd/node/modules/lp2p/pubsub.go#L151 + lotusTopicParams := &pubsub.TopicScoreParams{ + TopicWeight: 0.1, + TimeInMeshWeight: 0.00027, // ~1/3600 + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 1, + FirstMessageDeliveriesWeight: 5, // max value is 500 + FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + FirstMessageDeliveriesCap: 100, + InvalidMessageDeliveriesWeight: -1000, + InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + } + + return map[string]*fil.TopicConfig{ + "/f3/manifests/0.0.2": { + ScoreParams: fil.PubsubTopicScoreParams, + Options: []pubsub.TopicOpt{pubsub.WithTopicMessageIdFn(fil.ManifestMessageIdFn)}, + }, + "/f3/chainexchange/0.0.1/filecoin": { + ScoreParams: fil.PubsubTopicScoreParams, + Options: []pubsub.TopicOpt{pubsub.WithTopicMessageIdFn(fil.ChainExchangeMessageIdFn)}, + }, + "/f3/granite/0.0.3/filecoin": { + ScoreParams: fil.PubsubTopicScoreParams, + Options: []pubsub.TopicOpt{pubsub.WithTopicMessageIdFn(fil.GPBFTMessageIdFn)}, + }, + "/fil/blocks/testnetnet": { + ScoreParams: lotusTopicParams, + Options: []pubsub.TopicOpt{}, + }, + "/fil/msgs/testnetnet": { + ScoreParams: lotusTopicParams, + Options: []pubsub.TopicOpt{}, + }, + "/indexer/ingest/mainnet": { + ScoreParams: fil.PubsubTopicScoreParams, + Options: []pubsub.TopicOpt{}, + }, + "/drand/pubsub/v0.0.0/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971": { + ScoreParams: drandTopicParams, + Options: []pubsub.TopicOpt{}, + }, + "/drand/pubsub/v0.0.0/80c8b872c714f4c00fdd3daa465d5514049f457f01f85a4caf68cdcd394ba039": { + ScoreParams: drandTopicParams, + Options: []pubsub.TopicOpt{}, + }, + "/drand/pubsub/v0.0.0/8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce": { + ScoreParams: drandTopicParams, + Options: []pubsub.TopicOpt{}, + }, + } +} diff --git a/fil/discovery.go b/fil/discovery.go index 81034cf..12d5e82 100644 --- a/fil/discovery.go +++ b/fil/discovery.go @@ -15,8 +15,9 @@ import ( ) type DiscoveryConfig struct { - Tracer trace.Tracer - Meter metric.Meter + Interval time.Duration + Tracer trace.Tracer + Meter metric.Meter } type Discovery struct { @@ -72,15 +73,14 @@ func (d *Discovery) Serve(ctx context.Context) (err error) { peers, err := dht.GetClosestPeers(ctx, string(k)) if errors.Is(err, context.Canceled) { return nil - } else if err != nil { - slog.Warn("error", "err", err) + } else if err == nil { + slog.Debug("Found peers", "count", len(peers)) } - slog.Info("Found peers", "peers", len(peers)) select { case <-ctx.Done(): return nil - case <-time.After(10*time.Second - time.Since(start)): + case <-time.After(d.cfg.Interval - time.Since(start)): continue } } diff --git a/fil/node.go b/fil/node.go index 93b157c..deb027b 100644 --- a/fil/node.go +++ b/fil/node.go @@ -12,7 +12,6 @@ import ( "github.com/aws/aws-sdk-go-v2/service/kinesis" gk "github.com/dennis-tra/go-kinesis" - pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/thejerf/suture/v4" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" @@ -111,6 +110,10 @@ func NewNode(cfg *NodeConfig) (*Node, error) { if err != nil { return nil, fmt.Errorf("new s3 producer %w", err) } + + case host.DataStreamTypeNoop: + ds = new(host.NoopDataStream) + default: return nil, fmt.Errorf("not recognised data-stream (%s)", cfg.DataStreamType) } @@ -135,8 +138,9 @@ func NewNode(cfg *NodeConfig) (*Node, error) { slog.Info("Initialized new libp2p Host", tele.LogAttrPeerID(h.ID()), "maddrs", h.Addrs()) disc, err := NewDiscovery(h.Host, &DiscoveryConfig{ - Tracer: cfg.Tracer, - Meter: cfg.Meter, + Interval: cfg.LookupInterval, + Tracer: cfg.Tracer, + Meter: cfg.Meter, }) if err != nil { return nil, fmt.Errorf("new discovery service: %w", err) @@ -145,19 +149,8 @@ func NewNode(cfg *NodeConfig) (*Node, error) { // initialize the pubsub topic handlers pubSubConfig := &PubSubConfig{ - Topics: map[string][]pubsub.TopicOpt{ - "/f3/granite/0.0.3/filecoin": {pubsub.WithTopicMessageIdFn(GPBFTMessageIdFn)}, - "/f3/chainexchange/0.0.1/filecoin": {pubsub.WithTopicMessageIdFn(ChainExchangeMessageIdFn)}, - "/f3/manifests/0.0.1": {pubsub.WithTopicMessageIdFn(ManifestMessageIdFn)}, - "/f3/manifests/0.0.2": {pubsub.WithTopicMessageIdFn(ManifestMessageIdFn)}, - "/drand/pubsub/v0.0.0/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971": {}, - "/drand/pubsub/v0.0.0/80c8b872c714f4c00fdd3daa465d5514049f457f01f85a4caf68cdcd394ba039": {}, - "/drand/pubsub/v0.0.0/8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce": {}, - "/fil/blocks/testnetnet": {}, - "/fil/msgs/testnetnet": {}, - "/indexer/ingest/mainnet": {}, - }, - DataStream: ds, + TopicConfigs: cfg.TopicConfigs, + DataStream: ds, } pubSub, err := NewPubSub(h, pubSubConfig) diff --git a/fil/node_config.go b/fil/node_config.go index e09dffc..230c03a 100644 --- a/fil/node_config.go +++ b/fil/node_config.go @@ -38,11 +38,17 @@ type NodeConfig struct { // General timeout when communicating with other network participants DialTimeout time.Duration + // Topic configurations to subscribe to + TopicConfigs map[string]*TopicConfig + // The address information of the local libp2p host Libp2pHost string Libp2pPort int Libp2pPeerscoreSnapshotFreq time.Duration + // Pause between two discovery lookups + LookupInterval time.Duration + // The Data Stream configuration DataStreamType host.DataStreamType AWSConfig *aws.Config @@ -202,54 +208,12 @@ func (n *NodeConfig) libp2pOptions() ([]libp2p.Option, error) { } func (n *NodeConfig) pubsubOptions(subFilter pubsub.SubscriptionFilter) []pubsub.Option { - //drandTopicParams := &pubsub.TopicScoreParams{ - // TopicWeight: 0.5, // 5x block topic; max cap is 62.5 - // TimeInMeshWeight: 0.00027, // ~1/3600 - // TimeInMeshQuantum: time.Second, - // TimeInMeshCap: 1, - // FirstMessageDeliveriesWeight: 5, // max value is 125 - // FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), - // FirstMessageDeliveriesCap: 25, // the maximum expected in an hour is ~26, including the decay - // InvalidMessageDeliveriesWeight: -1000, - // InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), - //} - - topicParams := map[string]*pubsub.TopicScoreParams{ - "/fil/blocks/mainnet": { - TopicWeight: 0.1, // max cap is 50, max mesh penalty is -10, single invalid message is -100 - TimeInMeshWeight: 0.00027, // ~1/3600 - TimeInMeshQuantum: time.Second, - TimeInMeshCap: 1, - FirstMessageDeliveriesWeight: 5, // max value is 500 - FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), - FirstMessageDeliveriesCap: 100, // 100 blocks in an hour - InvalidMessageDeliveriesWeight: -1000, - InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), - }, - "/fil/msgs/mainnet": { - TopicWeight: 0.1, // max cap is 5, single invalid message is -100 - TimeInMeshWeight: 0.0002778, // ~1/3600 - TimeInMeshQuantum: time.Second, - TimeInMeshCap: 1, - FirstMessageDeliveriesWeight: 0.5, // max value is 50 - FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(10 * time.Minute), - FirstMessageDeliveriesCap: 100, // 100 messages in 10 minutes - InvalidMessageDeliveriesWeight: -1000, - InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), - }, + topicParams := make(map[string]*pubsub.TopicScoreParams, len(n.TopicConfigs)) + for topic, topicConfig := range n.TopicConfigs { + topicParams[topic] = topicConfig.ScoreParams } - const ( - GossipScoreThreshold = -500 - PublishScoreThreshold = -1000 - GraylistScoreThreshold = -2500 - AcceptPXScoreThreshold = 1000 - OpportunisticGraftScoreThreshold = 3.5 - ) - psOpts := []pubsub.Option{ - // pubsub.WithMessageSignaturePolicy(pubsub.StrictSign), - // pubsub.WithNoAuthor(), pubsub.WithMessageIdFn(func(pmsg *pubsubpb.Message) string { hash := blake2b.Sum256(pmsg.Data) return string(hash[:]) @@ -258,26 +222,10 @@ func (n *NodeConfig) pubsubOptions(subFilter pubsub.SubscriptionFilter) []pubsub pubsub.WithSubscriptionFilter(subFilter), pubsub.WithPeerScore( &pubsub.PeerScoreParams{ - AppSpecificScore: func(p peer.ID) float64 { - // return a heavy positive score for bootstrappers so that we don't unilaterally prune - // them and accept PX from them. - // we don't do that in the bootstrappers themselves to avoid creating a closed mesh - // between them (however we might want to consider doing just that) - //_, ok := bootstrappers[p] - //if ok && !isBootstrapNode { - // return 2500 - //} - // - //_, ok = drandBootstrappers[p] - //if ok && !isBootstrapNode { - // return 1500 - //} - - return 0 - }, + AppSpecificScore: func(p peer.ID) float64 { return 0 }, AppSpecificWeight: 1, IPColocationFactorThreshold: 5, - IPColocationFactorWeight: -100, + IPColocationFactorWeight: 0, BehaviourPenaltyThreshold: 6, BehaviourPenaltyWeight: -10, BehaviourPenaltyDecay: pubsub.ScoreParameterDecay(time.Hour), diff --git a/fil/pubsub.go b/fil/pubsub.go index bb81c46..4e1d67b 100644 --- a/fil/pubsub.go +++ b/fil/pubsub.go @@ -9,8 +9,8 @@ import ( "strings" "time" + f3 "github.com/filecoin-project/go-f3" "github.com/filecoin-project/go-f3/chainexchange" - "github.com/filecoin-project/go-f3/gpbft" "github.com/filecoin-project/go-f3/manifest" "github.com/filecoin-project/lotus/chain/types" "github.com/ipni/go-libipni/announce/message" @@ -26,9 +26,14 @@ import ( const eventTypeHandleMessage = "HANDLE_MESSAGE" +type TopicConfig struct { + ScoreParams *pubsub.TopicScoreParams + Options []pubsub.TopicOpt +} + type PubSubConfig struct { - Topics map[string][]pubsub.TopicOpt - DataStream host.DataStream + TopicConfigs map[string]*TopicConfig + DataStream host.DataStream } func (p PubSubConfig) Validate() error { @@ -59,7 +64,7 @@ func (p *PubSub) Serve(ctx context.Context) error { supervisor := suture.NewSimple("pubsub") - for topicName, topicOpts := range p.cfg.Topics { + for topicName, topicCfg := range p.cfg.TopicConfigs { var err error switch { @@ -72,7 +77,7 @@ func (p *PubSub) Serve(ctx context.Context) error { return fmt.Errorf("register topic validator %s: %w", topicName, err) } - topic, err := p.gs.Join(topicName, topicOpts...) + topic, err := p.gs.Join(topicName, topicCfg.Options...) if err != nil { return fmt.Errorf("join pubsub topic %s: %w", topicName, err) } @@ -210,11 +215,13 @@ func (p *PubSub) handleIndexerIngest(ctx context.Context, msg *pubsub.Message) e } func (p *PubSub) validateF3Granite(ctx context.Context, _ peer.ID, msg *pubsub.Message) pubsub.ValidationResult { - var gmsg gpbft.GMessage - if err := gmsg.UnmarshalCBOR(bytes.NewReader(msg.Data)); err != nil { + var pgmsg f3.PartialGMessage + enc := NewCBOR[*f3.PartialGMessage]() + if err := enc.Decode(msg.Data, &pgmsg); err != nil { return pubsub.ValidationReject } - msg.ValidatorData = gmsg + msg.ValidatorData = pgmsg + return pubsub.ValidationAccept } @@ -225,7 +232,7 @@ func (p *PubSub) handleF3Granite(ctx context.Context, msg *pubsub.Message) error PeerID: p.host.ID(), Timestamp: time.Now(), } - gmsg := msg.ValidatorData.(gpbft.GMessage) + gmsg := msg.ValidatorData.(f3.PartialGMessage) evt.Payload = map[string]any{ "PeerID": msg.ReceivedFrom, From 802d42f9fbeb5fe88c9d4ee439ede9c16e2a9ae4 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Wed, 30 Apr 2025 14:31:18 +0200 Subject: [PATCH 13/65] go mod tidy --- go.mod | 4 ++-- go.sum | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 9c8ec37..c6dcb95 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/iand/pontium v0.3.15 github.com/ipni/go-libipni v0.6.18 + github.com/klauspost/compress v1.18.0 github.com/libp2p/go-libp2p v0.41.1 github.com/libp2p/go-libp2p-kad-dht v0.30.2 github.com/libp2p/go-libp2p-mplex v0.10.0 @@ -35,6 +36,7 @@ require ( github.com/stretchr/testify v1.10.0 github.com/thejerf/suture/v4 v4.0.6 github.com/urfave/cli/v2 v2.27.5 + github.com/whyrusleeping/cbor-gen v0.3.1 go.opentelemetry.io/otel v1.35.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 go.opentelemetry.io/otel/exporters/prometheus v0.55.0 @@ -151,7 +153,6 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect - github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/koron/go-ssdp v0.0.5 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -250,7 +251,6 @@ require ( github.com/tklauser/numcpus v0.9.0 // indirect github.com/trailofbits/go-mutexasserts v0.0.0-20250212181730-4c2b8e9e784b // indirect github.com/wealdtech/go-bytesutil v1.2.1 // indirect - github.com/whyrusleeping/cbor-gen v0.3.1 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/wlynxg/anet v0.0.5 // indirect diff --git a/go.sum b/go.sum index 3cb654f..f6647f4 100644 --- a/go.sum +++ b/go.sum @@ -1195,6 +1195,8 @@ gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRyS gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8= gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q= gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02/go.mod h1:JTnUj0mpYiAsuZLmKjTx/ex3AtMowcCgnE7YNyCEP0I= +go.dedis.ch/kyber/v4 v4.0.0-pre2.0.20240924132404-4de33740016e h1:BAGc1ommHzlhqHktWyRmoldVONj3QHMzdfGLW4ItltA= +go.dedis.ch/kyber/v4 v4.0.0-pre2.0.20240924132404-4de33740016e/go.mod h1:tg6jwKTYEjm94VxkFwiQy+ec9hoQvccIU989wNjXWVI= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= From 5e430111ff1963ae7fe62e111698e32b8175626b Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Wed, 30 Apr 2025 14:45:47 +0200 Subject: [PATCH 14/65] staticcheck: remove unused code --- fil/encoding.go | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/fil/encoding.go b/fil/encoding.go index bdbea83..0a418b7 100644 --- a/fil/encoding.go +++ b/fil/encoding.go @@ -6,12 +6,10 @@ package fil import ( "bytes" "fmt" - "reflect" "sync" "github.com/klauspost/compress/zstd" cbg "github.com/whyrusleeping/cbor-gen" - "go.opentelemetry.io/otel/attribute" ) // maxDecompressedSize is the default maximum amount of memory allocated by the @@ -59,9 +57,6 @@ type ZSTD[T CBORMarshalUnmarshaler] struct { cborEncoding *CBOR[T] compressor *zstd.Encoder decompressor *zstd.Decoder - - metricAttr attribute.KeyValue - metricAttrLoader sync.Once } func NewZSTD[T CBORMarshalUnmarshaler]() (*ZSTD[T], error) { @@ -105,16 +100,3 @@ func (c *ZSTD[T]) Decode(compressed []byte, t T) (_err error) { } return c.cborEncoding.Decode(decompressed, t) } - -func (c *ZSTD[T]) getMetricAttribute() attribute.KeyValue { - c.metricAttrLoader.Do(func() { - const key = "type" - switch target := reflect.TypeFor[T](); { - case target.Kind() == reflect.Ptr: - c.metricAttr = attribute.String(key, target.Elem().Name()) - default: - c.metricAttr = attribute.String(key, target.Name()) - } - }) - return c.metricAttr -} From a8a0076ac883e1415227ef905e83e82184e35fcd Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Wed, 30 Apr 2025 14:50:34 +0200 Subject: [PATCH 15/65] filecoin: update agent version parsing --- fil/node_notifiee.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/fil/node_notifiee.go b/fil/node_notifiee.go index 1bb15c7..c3245f2 100644 --- a/fil/node_notifiee.go +++ b/fil/node_notifiee.go @@ -36,15 +36,16 @@ func (n *Node) Connected(net network.Network, c network.Conn) { func (n *Node) Disconnected(net network.Network, c network.Conn) { if !c.Stat().Opened.IsZero() { av := n.host.AgentVersion(c.RemotePeer()) - parts := strings.Split(av, "/") - if len(parts) > 0 { - switch strings.ToLower(parts[0]) { - case "prysm", "lighthouse", "nimbus", "lodestar", "grandine", "teku", "erigon": - av = strings.ToLower(parts[0]) - default: - av = "other" - } - } else { + switch { + case strings.Contains(av, "lotus"): + av = "lotus" + case strings.Contains(av, "boost"): + av = "boost" + case strings.Contains(av, "venus"): + av = "venus" + case strings.Contains(av, "forest"): + av = "forest" + default: av = "unknown" } n.connAge.Record(context.TODO(), time.Since(c.Stat().Opened).Seconds(), metric.WithAttributes(attribute.String("agent", av))) From e907e0e03dca4ff31b1d4d3c5ad5cbce5944d65d Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Wed, 30 Apr 2025 15:13:18 +0200 Subject: [PATCH 16/65] filecoin: improve discovery error handling --- fil/discovery.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fil/discovery.go b/fil/discovery.go index 12d5e82..e9aa3b4 100644 --- a/fil/discovery.go +++ b/fil/discovery.go @@ -73,7 +73,13 @@ func (d *Discovery) Serve(ctx context.Context) (err error) { peers, err := dht.GetClosestPeers(ctx, string(k)) if errors.Is(err, context.Canceled) { return nil - } else if err == nil { + } else if err != nil { + // could be that we don't have any DHT peers in our peer store + // -> bootstrap again + for _, addrInfo := range kaddht.GetDefaultBootstrapPeerAddrInfos() { + _ = d.host.Connect(ctx, addrInfo) + } + } else { slog.Debug("Found peers", "count", len(peers)) } From 85e73ef5dc0dfc27ef641d85508cd1150b145152 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Wed, 30 Apr 2025 15:13:35 +0200 Subject: [PATCH 17/65] lower S3 submission log level --- host/s3.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/host/s3.go b/host/s3.go index 7583eca..ec4b2e2 100644 --- a/host/s3.go +++ b/host/s3.go @@ -508,12 +508,12 @@ func (s3ds *S3DataStream) startS3Flusher( int64(totBytes/(1024*1024)), metric.WithAttributes(attribute.String("event_type", eventT.EventType.String())), ) - slog.Info("submitted file to s3", + slog.Debug("submitted file to s3", "MB", float32(totBytes)/(1024.0*1024.0), "s3key", eventT.S3Key, - "formating-time", formatT, - "upload-time", uploadT, - "total-time", totalT, + "formating-time", formatT.String(), + "upload-time", uploadT.String(), + "total-time", totalT.String(), ) case <-ctx.Done(): From 2165eff2312f9b272ef3c30146abd92ddb408b46 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Wed, 30 Apr 2025 21:48:29 +0200 Subject: [PATCH 18/65] fix: filecoin f3 message decoding --- fil/pubsub.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/fil/pubsub.go b/fil/pubsub.go index 4e1d67b..0281f16 100644 --- a/fil/pubsub.go +++ b/fil/pubsub.go @@ -216,8 +216,13 @@ func (p *PubSub) handleIndexerIngest(ctx context.Context, msg *pubsub.Message) e func (p *PubSub) validateF3Granite(ctx context.Context, _ peer.ID, msg *pubsub.Message) pubsub.ValidationResult { var pgmsg f3.PartialGMessage - enc := NewCBOR[*f3.PartialGMessage]() - if err := enc.Decode(msg.Data, &pgmsg); err != nil { + zstd, err := NewZSTD[*f3.PartialGMessage]() + if err != nil { + slog.Warn("new zstd cbor decoder for *f3.PartialGMessage failed: ", tele.LogAttrError(err)) + return pubsub.ValidationIgnore + } + + if err := zstd.Decode(msg.Data, &pgmsg); err != nil { return pubsub.ValidationReject } msg.ValidatorData = pgmsg @@ -291,8 +296,13 @@ func (p *PubSub) handleF3Manifests(ctx context.Context, msg *pubsub.Message) err func (p *PubSub) validateF3ChainExchange(ctx context.Context, _ peer.ID, msg *pubsub.Message) pubsub.ValidationResult { var cmsg chainexchange.Message - enc := NewCBOR[*chainexchange.Message]() - if err := enc.Decode(msg.Data, &cmsg); err != nil { + zstd, err := NewZSTD[*chainexchange.Message]() + if err != nil { + slog.Warn("new zstd cbor decoder for *chainexchange.Message failed: ", tele.LogAttrError(err)) + return pubsub.ValidationIgnore + } + + if err := zstd.Decode(msg.Data, &cmsg); err != nil { return pubsub.ValidationReject } From f1bef7a7fc02b34389699c7c3e6d5d130ae9910b Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Wed, 30 Apr 2025 22:32:38 +0200 Subject: [PATCH 19/65] filecoin: increase validation queue size --- fil/node_config.go | 1 + 1 file changed, 1 insertion(+) diff --git a/fil/node_config.go b/fil/node_config.go index 230c03a..3d5f791 100644 --- a/fil/node_config.go +++ b/fil/node_config.go @@ -220,6 +220,7 @@ func (n *NodeConfig) pubsubOptions(subFilter pubsub.SubscriptionFilter) []pubsub }), pubsub.WithPeerExchange(true), pubsub.WithSubscriptionFilter(subFilter), + pubsub.WithValidateQueueSize(128), // default is 32 pubsub.WithPeerScore( &pubsub.PeerScoreParams{ AppSpecificScore: func(p peer.ID) float64 { return 0 }, From e53c982a4bef2b272fd39e0ad991ad4f33593ff6 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 5 May 2025 10:32:31 +0200 Subject: [PATCH 20/65] filecoin: limit lookup duration --- fil/discovery.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fil/discovery.go b/fil/discovery.go index e9aa3b4..9a33814 100644 --- a/fil/discovery.go +++ b/fil/discovery.go @@ -70,8 +70,10 @@ func (d *Discovery) Serve(ctx context.Context) (err error) { } start := time.Now() - peers, err := dht.GetClosestPeers(ctx, string(k)) + timeoutCtx, timeoutCancel := context.WithTimeout(ctx, time.Minute) + peers, err := dht.GetClosestPeers(timeoutCtx, string(k)) if errors.Is(err, context.Canceled) { + timeoutCancel() return nil } else if err != nil { // could be that we don't have any DHT peers in our peer store @@ -82,6 +84,7 @@ func (d *Discovery) Serve(ctx context.Context) (err error) { } else { slog.Debug("Found peers", "count", len(peers)) } + timeoutCancel() select { case <-ctx.Done(): From d29f1780209059b417e23a83dbef97ed9d42633d Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 5 May 2025 10:32:44 +0200 Subject: [PATCH 21/65] filecoin: add lookups counter metric --- fil/discovery.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fil/discovery.go b/fil/discovery.go index 9a33814..492edff 100644 --- a/fil/discovery.go +++ b/fil/discovery.go @@ -10,6 +10,7 @@ import ( kaddht "github.com/libp2p/go-libp2p-kad-dht" "github.com/libp2p/go-libp2p/core/host" "github.com/thejerf/suture/v4" + "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" ) @@ -25,7 +26,7 @@ type Discovery struct { host host.Host // Metrics - MeterDiscoveredPeers metric.Int64Counter + MeterLookups metric.Int64Counter } var _ suture.Service = (*Discovery)(nil) @@ -39,9 +40,9 @@ func NewDiscovery(h host.Host, cfg *DiscoveryConfig) (*Discovery, error) { } var err error - d.MeterDiscoveredPeers, err = cfg.Meter.Int64Counter("discovered_peers", metric.WithDescription("Total number of discovered peers")) + d.MeterLookups, err = cfg.Meter.Int64Counter("lookups", metric.WithDescription("Total number of performed lookups")) if err != nil { - return nil, fmt.Errorf("discovered_peers counter: %w", err) + return nil, fmt.Errorf("lookups counter: %w", err) } return d, nil @@ -72,6 +73,7 @@ func (d *Discovery) Serve(ctx context.Context) (err error) { timeoutCtx, timeoutCancel := context.WithTimeout(ctx, time.Minute) peers, err := dht.GetClosestPeers(timeoutCtx, string(k)) + d.MeterLookups.Add(ctx, 1, metric.WithAttributes(attribute.Bool("success", err == nil))) if errors.Is(err, context.Canceled) { timeoutCancel() return nil From d5d76f41285775f773e7b1ac7f14a1013f7df232 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 5 May 2025 11:07:11 +0200 Subject: [PATCH 22/65] require fork version and root hash --- cmd/hermes/cmd_eth_fork_digest.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/hermes/cmd_eth_fork_digest.go b/cmd/hermes/cmd_eth_fork_digest.go index 6dc49aa..eac83fc 100644 --- a/cmd/hermes/cmd_eth_fork_digest.go +++ b/cmd/hermes/cmd_eth_fork_digest.go @@ -29,6 +29,7 @@ var cmdEthForkDigest = &cli.Command{ Usage: "Fork version that will be used to compute the fork-digest (hex encoded string).", Value: forkDigestConfig.forkVersion, Destination: &forkDigestConfig.forkVersion, + Required: true, }, &cli.StringFlag{ Name: "genesis.validator.root", @@ -36,6 +37,7 @@ var cmdEthForkDigest = &cli.Command{ Usage: "The root of all the validators at the genesis (hex encoded string).", Value: forkDigestConfig.genesisValidatorsRoot, Destination: &forkDigestConfig.genesisValidatorsRoot, + Required: true, }, }, } From 7301fb78819d077a345a4214f1b08b1cf101e5ac Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 5 May 2025 11:11:04 +0200 Subject: [PATCH 23/65] config: update gnosis electra epoch --- eth/network_config.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/eth/network_config.go b/eth/network_config.go index 3413b4e..658fc9c 100644 --- a/eth/network_config.go +++ b/eth/network_config.go @@ -68,7 +68,8 @@ func DeriveKnownNetworkConfig(ctx context.Context, network string) (*NetworkConf {0x02, 0x00, 0x00, 0x64}: primitives.Epoch(385536), {0x03, 0x00, 0x00, 0x64}: primitives.Epoch(648704), {0x04, 0x00, 0x00, 0x64}: primitives.Epoch(889856), - {0x05, 0x00, 0x00, 0x64}: primitives.Epoch(18446744073709551615), // temporary + {0x05, 0x00, 0x00, 0x64}: primitives.Epoch(1337856), + {0x06, 0x00, 0x00, 0x64}: primitives.Epoch(18446744073709551615), // temporary }, ForkVersionNames: map[[4]byte]string{ {0x00, 0x00, 0x00, 0x64}: "phase0", @@ -77,6 +78,7 @@ func DeriveKnownNetworkConfig(ctx context.Context, network string) (*NetworkConf {0x03, 0x00, 0x00, 0x64}: "capella", {0x04, 0x00, 0x00, 0x64}: "deneb", {0x05, 0x00, 0x00, 0x64}: "electra", + {0x06, 0x00, 0x00, 0x64}: "fulu", }, }, Network: ¶ms.NetworkConfig{ From 5eed416d5d76929eeffd8bd3ba83e5c02886df52 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 5 May 2025 13:59:59 +0200 Subject: [PATCH 24/65] filecoin: fix discovery logic --- fil/discovery.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fil/discovery.go b/fil/discovery.go index 492edff..aead12a 100644 --- a/fil/discovery.go +++ b/fil/discovery.go @@ -73,11 +73,12 @@ func (d *Discovery) Serve(ctx context.Context) (err error) { timeoutCtx, timeoutCancel := context.WithTimeout(ctx, time.Minute) peers, err := dht.GetClosestPeers(timeoutCtx, string(k)) + timeoutCancel() + d.MeterLookups.Add(ctx, 1, metric.WithAttributes(attribute.Bool("success", err == nil))) - if errors.Is(err, context.Canceled) { - timeoutCancel() + if errors.Is(ctx.Err(), context.Canceled) { return nil - } else if err != nil { + } else if err != nil || len(peers) == 0 { // could be that we don't have any DHT peers in our peer store // -> bootstrap again for _, addrInfo := range kaddht.GetDefaultBootstrapPeerAddrInfos() { From f373a4b6c4e97d347d1625733ff1b1909eade0e6 Mon Sep 17 00:00:00 2001 From: Mikel Cortes <45786396+cortze@users.noreply.github.com> Date: Fri, 9 May 2025 14:24:27 +0200 Subject: [PATCH 25/65] add gossip px --- host/parquet_traces.go | 43 ++++++++++++++++++++++++++++++++++++- host/parquet_traces_test.go | 43 +++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/host/parquet_traces.go b/host/parquet_traces.go index 9a734a8..894db04 100644 --- a/host/parquet_traces.go +++ b/host/parquet_traces.go @@ -21,6 +21,8 @@ const ( // Gossip-mesh EventTypeAddRemovePeer EventTypeGraftPrune + // PeerExchange + EventTypeGossipPx // Gossip RPCs EventTypeControlRPC EventTypeIhave @@ -48,6 +50,8 @@ func (e EventType) String() string { return "add_remove" case EventTypeGraftPrune: return "graft_prune" + case EventTypeGossipPx: + return "peer_exchange" case EventTypeControlRPC: return "control_rpc" case EventTypeIhave: @@ -73,6 +77,7 @@ var allEventTypes = []EventType{ EventTypeGenericEvent, EventTypeAddRemovePeer, EventTypeGraftPrune, + EventTypeGossipPx, EventTypeControlRPC, EventTypeIhave, EventTypeIwant, @@ -253,6 +258,12 @@ type GossipIdontwantEvent struct { Msgs int `parquet:"msgs"` } +type GossipPeerExchangeEvent struct { + BaseRPCEvent + Topic string `parquet:"topic"` + PxPeers []string `parquet:"px_peers"` +} + type GossipSentMsgEvent struct { BaseRPCEvent MsgID string `parquet:"msg_id"` @@ -307,7 +318,8 @@ func sendRecvDropRPCFromEvent(rpcDirection RPCdirection, rawEvent *TraceEvent) ( rpcMeta := rawEvent.Payload.(*RpcMeta) remoteID := rpcMeta.PeerID eventSubevents := make(map[EventType][]any) - // if no control event, nor out-going messages, continue + + // if no control event, nor out-going messages, nor prune messages, continue // only track messages if the they are outgoing - prevent spam of traces as we already trace down arrival ones if (rpcMeta.Messages == nil || (rpcMeta.Messages != nil && rpcDirection != RPCdirectionOut)) && rpcMeta.Control == nil { return eventSubevents, nil @@ -351,6 +363,35 @@ func sendRecvDropRPCFromEvent(rpcDirection RPCdirection, rawEvent *TraceEvent) ( } } + // PeerExchange + if rpcMeta.Control != nil { + if len(rpcMeta.Control.Prune) > 0 { + pruneMsgs := make([]any, len(rpcMeta.Control.Prune)) + for idx, prune := range rpcMeta.Control.Prune { + peerIDs := make([]string, len(prune.PeerIDs)) + for i, ids := range prune.PeerIDs { + peerIDs[i] = ids.String() + } + event := &GossipPeerExchangeEvent{ + BaseRPCEvent: BaseRPCEvent{ + BaseEvent: BaseEvent{ + Timestamp: timestamp, + Type: EventTypeSentMsg.String(), + ProducerID: producerID, + }, + IsOg: false, + Direction: rpcDirection.String(), + RemotePeerID: remoteID.String(), + }, + Topic: prune.TopicID, + PxPeers: peerIDs, + } + pruneMsgs[idx] = event + } + eventSubevents[EventTypeGossipPx] = pruneMsgs + } + } + // Ihaves if rpcMeta.Control != nil { if len(rpcMeta.Control.IHave) > 0 { diff --git a/host/parquet_traces_test.go b/host/parquet_traces_test.go index 3d18265..91b7818 100644 --- a/host/parquet_traces_test.go +++ b/host/parquet_traces_test.go @@ -209,6 +209,14 @@ func TestParquetFormating(t *testing.T) { }, }, }, + Prune: []RpcControlPrune{ + { + TopicID: testTopic, + PeerIDs: []peer.ID{ + dummyRemoteID, + }, + }, + }, }, Messages: []RpcMetaMsg{ { @@ -222,6 +230,7 @@ func TestParquetFormating(t *testing.T) { EventTypeIhave: &GossipIhaveEvent{}, EventTypeIwant: &GossipIwantEvent{}, EventTypeIdontwant: &GossipIdontwantEvent{}, + EventTypeGossipPx: &GossipPeerExchangeEvent{}, EventTypeControlRPC: &SendRecvRPCEvent{}, }, }, @@ -255,6 +264,14 @@ func TestParquetFormating(t *testing.T) { }, }, }, + Prune: []RpcControlPrune{ + { + TopicID: testTopic, + PeerIDs: []peer.ID{ + dummyRemoteID, + }, + }, + }, }, Messages: []RpcMetaMsg{ { @@ -268,6 +285,7 @@ func TestParquetFormating(t *testing.T) { EventTypeIhave: &GossipIhaveEvent{}, EventTypeIwant: &GossipIwantEvent{}, EventTypeIdontwant: &GossipIdontwantEvent{}, + EventTypeGossipPx: &GossipPeerExchangeEvent{}, EventTypeSentMsg: &GossipSentMsgEvent{}, EventTypeControlRPC: &SendRecvRPCEvent{}, }, @@ -302,6 +320,14 @@ func TestParquetFormating(t *testing.T) { }, }, }, + Prune: []RpcControlPrune{ + { + TopicID: testTopic, + PeerIDs: []peer.ID{ + dummyRemoteID, + }, + }, + }, }, Messages: []RpcMetaMsg{ { @@ -315,6 +341,7 @@ func TestParquetFormating(t *testing.T) { EventTypeIhave: &GossipIhaveEvent{}, EventTypeIwant: &GossipIwantEvent{}, EventTypeIdontwant: &GossipIdontwantEvent{}, + EventTypeGossipPx: &GossipPeerExchangeEvent{}, EventTypeControlRPC: &SendRecvRPCEvent{}, }, }, @@ -453,6 +480,13 @@ func TestParquetFormating(t *testing.T) { requireBaseRPCEvent(t, direction, false, e.BaseRPCEvent) requireSentMsgEvent(t, e) + case *GossipPeerExchangeEvent: + requireBaseEvent(t, EventTypeSentMsg, e.BaseEvent) + direction, err := directionFromRPC(test.rawEvent.Type) + require.NoError(t, err) + requireBaseRPCEvent(t, direction, false, e.BaseRPCEvent) + requirePeerExEvent(t, e) + case *GossipMsgArrivalEvent: requireBaseEvent(t, EventTypeMsgArrivals, e.BaseEvent) switch test.rawEvent.Type { @@ -568,6 +602,15 @@ func requireIdontwantEvent(t *testing.T, event *GossipIdontwantEvent) { require.Equal(t, event.Msgs, 1) } +func requirePeerExEvent(t *testing.T, event *GossipPeerExchangeEvent) { + require.Equal(t, event.RemotePeerID, dummyRemoteID.String()) + // TODO: hardcoded so far + for _, p := range event.PxPeers { + require.Equal(t, p, dummyRemoteID.String()) + } + require.Equal(t, event.Topic, testTopic) +} + func requireSentMsgEvent(t *testing.T, event *GossipSentMsgEvent) { require.Equal(t, event.RemotePeerID, dummyRemoteID.String()) // TODO: hardcoded so far From f3f403fdb2870b4b1af834471389203c2ab5aa8b Mon Sep 17 00:00:00 2001 From: Mikel Cortes <45786396+cortze@users.noreply.github.com> Date: Fri, 9 May 2025 16:47:34 +0200 Subject: [PATCH 26/65] add Px event to s3 types --- host/parquet_traces.go | 4 ++-- host/s3.go | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/host/parquet_traces.go b/host/parquet_traces.go index 894db04..a1a7aaa 100644 --- a/host/parquet_traces.go +++ b/host/parquet_traces.go @@ -261,7 +261,7 @@ type GossipIdontwantEvent struct { type GossipPeerExchangeEvent struct { BaseRPCEvent Topic string `parquet:"topic"` - PxPeers []string `parquet:"px_peers"` + PxPeers []string `parquet:"px_peers,list"` } type GossipSentMsgEvent struct { @@ -376,7 +376,7 @@ func sendRecvDropRPCFromEvent(rpcDirection RPCdirection, rawEvent *TraceEvent) ( BaseRPCEvent: BaseRPCEvent{ BaseEvent: BaseEvent{ Timestamp: timestamp, - Type: EventTypeSentMsg.String(), + Type: EventTypeGossipPx.String(), ProducerID: producerID, }, IsOg: false, diff --git a/host/s3.go b/host/s3.go index ec4b2e2..ee76013 100644 --- a/host/s3.go +++ b/host/s3.go @@ -442,6 +442,13 @@ func (s3ds *S3DataStream) startS3Flusher( continue } + case EventTypeGossipPx: + totBytes, buf, err = EventsToBytes[GossipPeerExchangeEvent](eventT.Events, parquetOpts...) + if err != nil { + slog.Error(err.Error()) + continue + } + case EventTypeSentMsg: totBytes, buf, err = EventsToBytes[GossipSentMsgEvent](eventT.Events, parquetOpts...) if err != nil { From ee67e6ebfdb88f7b3b238bc81a2040e2510e1a6c Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Tue, 13 May 2025 10:21:57 +0200 Subject: [PATCH 27/65] filecoin: add discovery log messages --- fil/discovery.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/fil/discovery.go b/fil/discovery.go index aead12a..85be814 100644 --- a/fil/discovery.go +++ b/fil/discovery.go @@ -2,6 +2,7 @@ package fil import ( "context" + "encoding/hex" "errors" "fmt" "log/slog" @@ -50,7 +51,7 @@ func NewDiscovery(h host.Host, cfg *DiscoveryConfig) (*Discovery, error) { func (d *Discovery) Serve(ctx context.Context) (err error) { slog.Info("Starting discv5 Discovery Service") - defer slog.Info("Stopped disv5 Discovery Service") + defer slog.Info("Stopped discv5 Discovery Service") defer func() { err = terminateSupervisorTreeOnErr(err) }() opts := []kaddht.Option{ @@ -69,8 +70,9 @@ func (d *Discovery) Serve(ctx context.Context) (err error) { if err != nil { return fmt.Errorf("failed to generate random key: %w", err) } - start := time.Now() + slog.Info("Looking up random key", "key", hex.EncodeToString(k)) + start := time.Now() timeoutCtx, timeoutCancel := context.WithTimeout(ctx, time.Minute) peers, err := dht.GetClosestPeers(timeoutCtx, string(k)) timeoutCancel() @@ -81,13 +83,15 @@ func (d *Discovery) Serve(ctx context.Context) (err error) { } else if err != nil || len(peers) == 0 { // could be that we don't have any DHT peers in our peer store // -> bootstrap again + slog.Info("Failed to find random key", "key", hex.EncodeToString(k)) for _, addrInfo := range kaddht.GetDefaultBootstrapPeerAddrInfos() { - _ = d.host.Connect(ctx, addrInfo) + timeoutCtx, timeoutCancel := context.WithTimeout(ctx, 5*time.Second) + _ = d.host.Connect(timeoutCtx, addrInfo) + timeoutCancel() } } else { - slog.Debug("Found peers", "count", len(peers)) + slog.Info("Found peers", "count", len(peers)) } - timeoutCancel() select { case <-ctx.Done(): From fbdb834d6c3cc0f7d3b211a4809ead01adaf34f3 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Wed, 14 May 2025 17:27:10 +0200 Subject: [PATCH 28/65] filecoin: refactor discovery logging --- fil/discovery.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fil/discovery.go b/fil/discovery.go index 85be814..d2f906e 100644 --- a/fil/discovery.go +++ b/fil/discovery.go @@ -71,10 +71,11 @@ func (d *Discovery) Serve(ctx context.Context) (err error) { return fmt.Errorf("failed to generate random key: %w", err) } - slog.Info("Looking up random key", "key", hex.EncodeToString(k)) start := time.Now() timeoutCtx, timeoutCancel := context.WithTimeout(ctx, time.Minute) + slog.Info("Looking up random key", "key", hex.EncodeToString(k)) peers, err := dht.GetClosestPeers(timeoutCtx, string(k)) + slog.Info("Finished lookup", "count", len(peers), "err", err, "took", time.Since(start).String()) timeoutCancel() d.MeterLookups.Add(ctx, 1, metric.WithAttributes(attribute.Bool("success", err == nil))) @@ -83,14 +84,11 @@ func (d *Discovery) Serve(ctx context.Context) (err error) { } else if err != nil || len(peers) == 0 { // could be that we don't have any DHT peers in our peer store // -> bootstrap again - slog.Info("Failed to find random key", "key", hex.EncodeToString(k)) for _, addrInfo := range kaddht.GetDefaultBootstrapPeerAddrInfos() { timeoutCtx, timeoutCancel := context.WithTimeout(ctx, 5*time.Second) _ = d.host.Connect(timeoutCtx, addrInfo) timeoutCancel() } - } else { - slog.Info("Found peers", "count", len(peers)) } select { From 49593b5d18c5b513a57f9efcb86a7f2c50930245 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Thu, 15 May 2025 11:58:25 +0200 Subject: [PATCH 29/65] update: go-libp2p --- go.mod | 51 ++++++++++++------------ go.sum | 120 +++++++++++++++++++++++++++------------------------------ 2 files changed, 82 insertions(+), 89 deletions(-) diff --git a/go.mod b/go.mod index c6dcb95..cf7cc15 100644 --- a/go.mod +++ b/go.mod @@ -44,7 +44,7 @@ require ( go.opentelemetry.io/otel/sdk v1.34.0 go.opentelemetry.io/otel/sdk/metric v1.33.0 go.opentelemetry.io/otel/trace v1.35.0 - golang.org/x/crypto v0.37.0 + golang.org/x/crypto v0.38.0 golang.org/x/time v0.11.0 google.golang.org/grpc v1.70.0 google.golang.org/protobuf v1.36.6 @@ -130,7 +130,7 @@ require ( github.com/google/go-cmp v0.7.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20250208200701-d0013a598941 // indirect + github.com/google/pprof v0.0.0-20250501235452-c0086092b71a // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect @@ -146,7 +146,7 @@ require ( github.com/ipfs/go-ipld-cbor v0.2.0 // indirect github.com/ipfs/go-ipld-format v0.6.0 // indirect github.com/ipfs/go-log v1.0.5 // indirect - github.com/ipfs/go-log/v2 v2.5.1 // indirect + github.com/ipfs/go-log/v2 v2.6.0 // indirect github.com/ipld/go-ipld-prime v0.21.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect @@ -154,7 +154,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect - github.com/koron/go-ssdp v0.0.5 // indirect + github.com/koron/go-ssdp v0.0.6 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect @@ -175,7 +175,7 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/miekg/dns v1.1.63 // indirect + github.com/miekg/dns v1.1.66 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/minio/highwayhash v1.0.3 // indirect @@ -198,31 +198,31 @@ require ( github.com/multiformats/go-varint v0.0.7 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/onsi/ginkgo/v2 v2.22.2 // indirect - github.com/opencontainers/runtime-spec v1.2.0 // indirect + github.com/onsi/ginkgo/v2 v2.23.4 // indirect + github.com/opencontainers/runtime-spec v1.2.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pion/datachannel v1.5.10 // indirect github.com/pion/dtls/v2 v2.2.12 // indirect - github.com/pion/dtls/v3 v3.0.4 // indirect - github.com/pion/ice/v4 v4.0.8 // indirect + github.com/pion/dtls/v3 v3.0.6 // indirect + github.com/pion/ice/v4 v4.0.10 // indirect github.com/pion/interceptor v0.1.37 // indirect github.com/pion/logging v0.2.3 // indirect github.com/pion/mdns/v2 v2.0.7 // indirect github.com/pion/randutil v0.1.0 // indirect github.com/pion/rtcp v1.2.15 // indirect - github.com/pion/rtp v1.8.11 // indirect - github.com/pion/sctp v1.8.37 // indirect - github.com/pion/sdp/v3 v3.0.10 // indirect + github.com/pion/rtp v1.8.15 // indirect + github.com/pion/sctp v1.8.39 // indirect + github.com/pion/sdp/v3 v3.0.11 // indirect github.com/pion/srtp/v3 v3.0.4 // indirect github.com/pion/stun v0.6.1 // indirect github.com/pion/stun/v3 v3.0.0 // indirect github.com/pion/transport/v2 v2.2.10 // indirect github.com/pion/transport/v3 v3.0.7 // indirect - github.com/pion/turn/v4 v4.0.0 // indirect - github.com/pion/webrtc/v4 v4.0.10 // indirect + github.com/pion/turn/v4 v4.0.1 // indirect + github.com/pion/webrtc/v4 v4.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/polydawn/refmt v0.89.0 // indirect @@ -234,7 +234,7 @@ require ( github.com/prysmaticlabs/gohashtree v0.0.4-beta.0.20240624100937-73632381301b // indirect github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c // indirect github.com/quic-go/qpack v0.5.1 // indirect - github.com/quic-go/quic-go v0.50.1 // indirect + github.com/quic-go/quic-go v0.51.0 // indirect github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect @@ -263,20 +263,21 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 // indirect go.opentelemetry.io/proto/otlp v1.5.0 // indirect - go.uber.org/dig v1.18.0 // indirect - go.uber.org/fx v1.23.0 // indirect - go.uber.org/mock v0.5.0 // indirect + go.uber.org/automaxprocs v1.6.0 // indirect + go.uber.org/dig v1.19.0 // indirect + go.uber.org/fx v1.24.0 // indirect + go.uber.org/mock v0.5.2 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect + golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect golang.org/x/mod v0.24.0 // indirect - golang.org/x/net v0.39.0 // indirect + golang.org/x/net v0.40.0 // indirect golang.org/x/oauth2 v0.25.0 // indirect - golang.org/x/sync v0.13.0 // indirect - golang.org/x/sys v0.32.0 // indirect - golang.org/x/term v0.31.0 // indirect - golang.org/x/text v0.24.0 // indirect - golang.org/x/tools v0.32.0 // indirect + golang.org/x/sync v0.14.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/term v0.32.0 // indirect + golang.org/x/text v0.25.0 // indirect + golang.org/x/tools v0.33.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gonum.org/v1/gonum v0.16.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b // indirect diff --git a/go.sum b/go.sum index f6647f4..693323d 100644 --- a/go.sum +++ b/go.sum @@ -88,7 +88,6 @@ github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPn github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/bazelbuild/rules_go v0.23.2 h1:Wxu7JjqnF78cKZbsBsARLSXx/jlGaSLCnUV3mTlyHvM= github.com/bazelbuild/rules_go v0.23.2/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -395,8 +394,8 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc= -github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20250501235452-c0086092b71a h1:rDA3FfmxwXR+BVKKdz55WwMJ1pD2hJQNW31d+l3mPk4= +github.com/google/pprof v0.0.0-20250501235452-c0086092b71a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -545,8 +544,8 @@ github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= -github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= -github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= +github.com/ipfs/go-log/v2 v2.6.0 h1:2Nu1KKQQ2ayonKp4MPo6pXCjqw1ULc9iohRqWV5EYqg= +github.com/ipfs/go-log/v2 v2.6.0/go.mod h1:p+Efr3qaY5YXpx9TX7MoLCSEZX5boSWj9wh86P5HJa8= github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= github.com/ipfs/go-merkledag v0.2.4/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= @@ -615,8 +614,8 @@ github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQe github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= -github.com/koron/go-ssdp v0.0.5 h1:E1iSMxIs4WqxTbIBLtmNBeOOC+1sCIXQeqTWVnpmwhk= -github.com/koron/go-ssdp v0.0.5/go.mod h1:Qm59B7hpKpDqfyRNWRNr00jGwLdXjDyZh6y7rH6VS0w= +github.com/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU= +github.com/koron/go-ssdp v0.0.6/go.mod h1:0R9LfRJGek1zWTjN3JUNlm5INCDYGpRDfAptnct63fI= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -734,7 +733,6 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -747,8 +745,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfr github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= -github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= +github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE= +github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= @@ -865,18 +863,18 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= -github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= +github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= +github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU= +github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= -github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww= +github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -909,10 +907,10 @@ github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oL github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= -github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U= -github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg= -github.com/pion/ice/v4 v4.0.8 h1:ajNx0idNG+S+v9Phu4LSn2cs8JEfTsA1/tEjkkAVpFY= -github.com/pion/ice/v4 v4.0.8/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= +github.com/pion/dtls/v3 v3.0.6 h1:7Hkd8WhAJNbRgq9RgdNh1aaWlZlGpYTzdqjy9x9sK2E= +github.com/pion/dtls/v3 v3.0.6/go.mod h1:iJxNQ3Uhn1NZWOMWlLxEEHAN5yX7GyPvvKw04v9bzYU= +github.com/pion/ice/v4 v4.0.10 h1:P59w1iauC/wPk9PdY8Vjl4fOFL5B+USq1+xbDcN6gT4= +github.com/pion/ice/v4 v4.0.10/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI= github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= @@ -924,12 +922,12 @@ github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= -github.com/pion/rtp v1.8.11 h1:17xjnY5WO5hgO6SD3/NTIUPvSFw/PbLsIJyz1r1yNIk= -github.com/pion/rtp v1.8.11/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4= -github.com/pion/sctp v1.8.37 h1:ZDmGPtRPX9mKCiVXtMbTWybFw3z/hVKAZgU81wcOrqs= -github.com/pion/sctp v1.8.37/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= -github.com/pion/sdp/v3 v3.0.10 h1:6MChLE/1xYB+CjumMw+gZ9ufp2DPApuVSnDT8t5MIgA= -github.com/pion/sdp/v3 v3.0.10/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= +github.com/pion/rtp v1.8.15 h1:MuhuGn1cxpVCPLNY1lI7F1tQ8Spntpgf12ob+pOYT8s= +github.com/pion/rtp v1.8.15/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk= +github.com/pion/sctp v1.8.39 h1:PJma40vRHa3UTO3C4MyeJDQ+KIobVYRZQZ0Nt7SjQnE= +github.com/pion/sctp v1.8.39/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= +github.com/pion/sdp/v3 v3.0.11 h1:VhgVSopdsBKwhCFoyyPmT1fKMeV9nLMrEKxNOdy3IVI= +github.com/pion/sdp/v3 v3.0.11/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M= github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ= github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= @@ -944,10 +942,10 @@ github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQp github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= -github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM= -github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA= -github.com/pion/webrtc/v4 v4.0.10 h1:Hq/JLjhqLxi+NmCtE8lnRPDr8H4LcNvwg8OxVcdv56Q= -github.com/pion/webrtc/v4 v4.0.10/go.mod h1:ViHLVaNpiuvaH8pdiuQxuA9awuE6KVzAXx3vVWilOck= +github.com/pion/turn/v4 v4.0.1 h1:01UTBhYToe8PDC8piB++i66q1mmctfhhoeguaFqB84c= +github.com/pion/turn/v4 v4.0.1/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7IToA1zs= +github.com/pion/webrtc/v4 v4.1.0 h1:yq/p0G5nKGbHISf0YKNA8Yk+kmijbblBvuSLwaJ4QYg= +github.com/pion/webrtc/v4 v4.1.0/go.mod h1:cgEGkcpxGkT6Di2ClBYO5lP9mFXbCfEOrkYUpjjCQO4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -964,6 +962,8 @@ github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXx github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= @@ -1014,8 +1014,8 @@ github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20230228205207-28762a7b9294 h github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20230228205207-28762a7b9294/go.mod h1:ZVEbRdnMkGhp/pu35zq4SXxtvUwWK0J1MATtekZpH2Y= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.50.1 h1:unsgjFIUqW8a2oopkY7YNONpV1gYND6Nt9hnt1PN94Q= -github.com/quic-go/quic-go v0.50.1/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E= +github.com/quic-go/quic-go v0.51.0 h1:K8exxe9zXxeRKxaXxi/GpUqYiTrtdiWP8bo1KFya6Wc= +github.com/quic-go/quic-go v0.51.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ= github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 h1:4WFk6u3sOT6pLa1kQ50ZVdm8BQFgJNA117cepZxtLIg= github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66/go.mod h1:Vp72IJajgeOL6ddqrAhmp7IM9zbTcgkQxD/YdxrVwMw= github.com/raulk/clock v1.1.0 h1:dpb29+UKMbLqiU/jqIJptgLR1nn23HLgMY0sTCDza5Y= @@ -1187,7 +1187,6 @@ github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZ github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= @@ -1236,15 +1235,16 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/dig v1.18.0 h1:imUL1UiY0Mg4bqbFfsRQO5G4CGRBec/ZujWTvSVp3pw= -go.uber.org/dig v1.18.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= -go.uber.org/fx v1.23.0 h1:lIr/gYWQGfTwGcSXWXu4vP5Ws6iqnNEIY+F/aFzCKTg= -go.uber.org/fx v1.23.0/go.mod h1:o/D9n+2mLP6v1EG+qsdT1O8wKopYAsqZasju97SDFCU= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= +go.uber.org/dig v1.19.0 h1:BACLhebsYdpQ7IROQ1AGPjrXcP5dF80U3gKoFzbaq/4= +go.uber.org/dig v1.19.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +go.uber.org/fx v1.24.0 h1:wE8mruvpg2kiiL1Vqd0CC+tr0/24XIB10Iwp2lLWzkg= +go.uber.org/fx v1.24.0/go.mod h1:AmDeGyS+ZARGKM4tlH4FY2Jr63VjbEDJHtqXTGP5hbo= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= -go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= +go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -1256,7 +1256,6 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= @@ -1283,11 +1282,11 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= -golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= +golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= +golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -1299,7 +1298,6 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= @@ -1334,15 +1332,14 @@ golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1360,8 +1357,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1404,10 +1401,7 @@ golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1419,8 +1413,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -1428,8 +1422,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= -golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -1439,8 +1433,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1465,11 +1459,10 @@ golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= -golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= +golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1550,7 +1543,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= From ef0eeacaa144e551284ede6bd90024d408cf0631 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Thu, 15 May 2025 11:58:53 +0200 Subject: [PATCH 30/65] update: go-libp2p-kad-dht --- go.mod | 4 ++-- go.sum | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index cf7cc15..e3c414f 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/ipni/go-libipni v0.6.18 github.com/klauspost/compress v1.18.0 github.com/libp2p/go-libp2p v0.41.1 - github.com/libp2p/go-libp2p-kad-dht v0.30.2 + github.com/libp2p/go-libp2p-kad-dht v0.33.0 github.com/libp2p/go-libp2p-mplex v0.10.0 github.com/libp2p/go-libp2p-pubsub v0.13.1 github.com/lmittmann/tint v1.0.6 @@ -138,7 +138,7 @@ require ( github.com/holiman/uint256 v1.3.2 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/invopop/jsonschema v0.12.0 // indirect - github.com/ipfs/boxo v0.29.1 // indirect + github.com/ipfs/boxo v0.30.0 // indirect github.com/ipfs/go-block-format v0.2.0 // indirect github.com/ipfs/go-cid v0.5.0 // indirect github.com/ipfs/go-datastore v0.8.2 // indirect diff --git a/go.sum b/go.sum index 693323d..9b71081 100644 --- a/go.sum +++ b/go.sum @@ -486,6 +486,8 @@ github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= github.com/ipfs/boxo v0.29.1 h1:z61ZT4YDfTHLjXTsu/+3wvJ8aJlExthDSOCpx6Nh8xc= github.com/ipfs/boxo v0.29.1/go.mod h1:MkDJStXiJS9U99cbAijHdcmwNfVn5DKYBmQCOgjY2NU= +github.com/ipfs/boxo v0.30.0 h1:7afsoxPGGqfoH7Dum/wOTGUB9M5fb8HyKPMlLfBvIEQ= +github.com/ipfs/boxo v0.30.0/go.mod h1:BPqgGGyHB9rZZcPSzah2Dc9C+5Or3U1aQe7EH1H7370= github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs= github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= @@ -658,6 +660,8 @@ github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxn github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g= github.com/libp2p/go-libp2p-kad-dht v0.30.2 h1:K0LJPdXynQ+u3rx6uFlrfNy0i11LE6SOCDzwAAaahys= github.com/libp2p/go-libp2p-kad-dht v0.30.2/go.mod h1:UV0mxF4ufh/ht05jNg5mcjOMrjK82uecgANa+GKi4y0= +github.com/libp2p/go-libp2p-kad-dht v0.33.0 h1:lB6JFgLpsfEKTmcy27sPFulexEZMeN40zRsmIx8aFcw= +github.com/libp2p/go-libp2p-kad-dht v0.33.0/go.mod h1:CdmNk4VeGJa9EXM9SLNyNVySEvduKvb+5rSC/H4pLAo= github.com/libp2p/go-libp2p-kbucket v0.7.0 h1:vYDvRjkyJPeWunQXqcW2Z6E93Ywx7fX0jgzb/dGOKCs= github.com/libp2p/go-libp2p-kbucket v0.7.0/go.mod h1:blOINGIj1yiPYlVEX0Rj9QwEkmVnz3EP8LK1dRKBC6g= github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= From 8d22fca3ac4bf10335563be36cdad5a919ccbf0d Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 19 May 2025 20:32:41 +0200 Subject: [PATCH 31/65] use: go-yamux fork --- go.mod | 2 ++ go.sum | 8 ++------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index e3c414f..7cc509d 100644 --- a/go.mod +++ b/go.mod @@ -294,3 +294,5 @@ require ( sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) + +replace github.com/libp2p/go-yamux/v5 => github.com/dennis-tra/go-yamux/v5 v5.0.0-20250519183055-dde4b3083558 diff --git a/go.sum b/go.sum index 9b71081..acd55b4 100644 --- a/go.sum +++ b/go.sum @@ -189,6 +189,8 @@ github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbz github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= github.com/dennis-tra/go-kinesis v0.0.0-20240326083914-7acf5f8dc24e h1:y6QyYh8YZyRQDdfnQqUgC5tRBmEwUFAjavnybKboCm4= github.com/dennis-tra/go-kinesis v0.0.0-20240326083914-7acf5f8dc24e/go.mod h1:5Hm3EOeNP1/lYm9qcFwWgYgjixQilwcZA+hZ05bUz54= +github.com/dennis-tra/go-yamux/v5 v5.0.0-20250519183055-dde4b3083558 h1:N0mn/xSyVdXgfM493L8j38ukJme3ktY2Hf6L9UnR5vQ= +github.com/dennis-tra/go-yamux/v5 v5.0.0-20250519183055-dde4b3083558/go.mod h1:tgIQ07ObtRR/I0IWsFOyQIL9/dR5UXgc2s8xKmNZv1o= github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE= github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU= @@ -484,8 +486,6 @@ github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uO github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.29.1 h1:z61ZT4YDfTHLjXTsu/+3wvJ8aJlExthDSOCpx6Nh8xc= -github.com/ipfs/boxo v0.29.1/go.mod h1:MkDJStXiJS9U99cbAijHdcmwNfVn5DKYBmQCOgjY2NU= github.com/ipfs/boxo v0.30.0 h1:7afsoxPGGqfoH7Dum/wOTGUB9M5fb8HyKPMlLfBvIEQ= github.com/ipfs/boxo v0.30.0/go.mod h1:BPqgGGyHB9rZZcPSzah2Dc9C+5Or3U1aQe7EH1H7370= github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= @@ -658,8 +658,6 @@ github.com/libp2p/go-libp2p-core v0.0.2/go.mod h1:9dAcntw/n46XycV4RnlBq3BpgrmyUi github.com/libp2p/go-libp2p-core v0.0.3/go.mod h1:j+YQMNz9WNSkNezXOsahp9kwZBKBvxLpKD316QWSJXE= github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g= -github.com/libp2p/go-libp2p-kad-dht v0.30.2 h1:K0LJPdXynQ+u3rx6uFlrfNy0i11LE6SOCDzwAAaahys= -github.com/libp2p/go-libp2p-kad-dht v0.30.2/go.mod h1:UV0mxF4ufh/ht05jNg5mcjOMrjK82uecgANa+GKi4y0= github.com/libp2p/go-libp2p-kad-dht v0.33.0 h1:lB6JFgLpsfEKTmcy27sPFulexEZMeN40zRsmIx8aFcw= github.com/libp2p/go-libp2p-kad-dht v0.33.0/go.mod h1:CdmNk4VeGJa9EXM9SLNyNVySEvduKvb+5rSC/H4pLAo= github.com/libp2p/go-libp2p-kbucket v0.7.0 h1:vYDvRjkyJPeWunQXqcW2Z6E93Ywx7fX0jgzb/dGOKCs= @@ -713,8 +711,6 @@ github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjV github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo= github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux/v5 v5.0.0 h1:2djUh96d3Jiac/JpGkKs4TO49YhsfLopAoryfPmf+Po= -github.com/libp2p/go-yamux/v5 v5.0.0/go.mod h1:en+3cdX51U0ZslwRdRLrvQsdayFt3TSUKvBGErzpWbU= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lmittmann/tint v1.0.6 h1:vkkuDAZXc0EFGNzYjWcV0h7eEX+uujH48f/ifSkJWgc= From b809b4437fe0b97bb1e88855820d902a9711cb95 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Sun, 8 Jun 2025 13:50:20 +0200 Subject: [PATCH 32/65] fix: don't measure own score --- host/host.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/host/host.go b/host/host.go index 1d23116..cbe25c5 100644 --- a/host/host.go +++ b/host/host.go @@ -381,7 +381,13 @@ func (h *Host) UpdatePeerScore(scores map[peer.ID]*pubsub.PeerScoreSnapshot) { states := map[string]*topicState{} - for _, pss := range scores { // pss: peer score snapshot + for pid, pss := range scores { // pss: peer score snapshot + + // don't measure own scores + if pid == h.ID() { + continue + } + for topic, tss := range pss.Topics { // tss: topic score snapshot // Not sure if the peer score map also includes peers that were From a6b459338a3bde81f73099d1f4c85232793ef219 Mon Sep 17 00:00:00 2001 From: Steph Samson Date: Tue, 10 Jun 2025 14:26:30 +0900 Subject: [PATCH 33/65] chore: add cli cmd to disable disc actor --- cmd/hermes/cmd_fil.go | 10 ++++++++++ fil/node.go | 28 ++++++++++++++++++---------- fil/node_config.go | 2 ++ 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/cmd/hermes/cmd_fil.go b/cmd/hermes/cmd_fil.go index 95b1974..37e801f 100644 --- a/cmd/hermes/cmd_fil.go +++ b/cmd/hermes/cmd_fil.go @@ -24,6 +24,7 @@ var filConfig = &struct { LookupInterval time.Duration Network string DialTimeout time.Duration + DiscoveryActorEnabled bool }{ PrivateKeyStr: "", // unset means it'll be generated Libp2pHost: "127.0.0.1", @@ -32,6 +33,7 @@ var filConfig = &struct { LookupInterval: time.Minute, Network: "mainnet", DialTimeout: 5 * time.Second, + DiscoveryActorEnabled: true, } var cmdFil = &cli.Command{ @@ -96,6 +98,13 @@ var cmdFilFlags = []cli.Flag{ Value: filConfig.LookupInterval, Destination: &filConfig.LookupInterval, }, + &cli.BoolFlag{ + Name: "discovery.actor.enabled", + EnvVars: []string{"HERMES_FIL_DISCOVERY_ACTOR_ENABLED"}, + Usage: "Enables the discovery actor", + Value: false, + Destination: &filConfig.DiscoveryActorEnabled, + }, } func cmdFilAction(c *cli.Context) error { @@ -148,6 +157,7 @@ func cmdFilAction(c *cli.Context) error { KinesisStream: rootConfig.KinesisStream, Tracer: otel.GetTracerProvider().Tracer("hermes"), Meter: otel.GetMeterProvider().Meter("hermes"), + DiscoveryActorEnabled: filConfig.DiscoveryActorEnabled, } n, err := fil.NewNode(cfg) diff --git a/fil/node.go b/fil/node.go index deb027b..c2e92c4 100644 --- a/fil/node.go +++ b/fil/node.go @@ -137,15 +137,21 @@ func NewNode(cfg *NodeConfig) (*Node, error) { } slog.Info("Initialized new libp2p Host", tele.LogAttrPeerID(h.ID()), "maddrs", h.Addrs()) - disc, err := NewDiscovery(h.Host, &DiscoveryConfig{ - Interval: cfg.LookupInterval, - Tracer: cfg.Tracer, - Meter: cfg.Meter, - }) - if err != nil { - return nil, fmt.Errorf("new discovery service: %w", err) + var disc *Discovery + if cfg.DiscoveryActorEnabled { + var err error + disc, err = NewDiscovery(h.Host, &DiscoveryConfig{ + Interval: cfg.LookupInterval, + Tracer: cfg.Tracer, + Meter: cfg.Meter, + }) + if err != nil { + return nil, fmt.Errorf("new discovery service: %w", err) + } + slog.Info("Initialized new discovery service") + } else { + slog.Info("Discovery actor is disabled") } - slog.Info("Initialized new discovery service") // initialize the pubsub topic handlers pubSubConfig := &PubSubConfig{ @@ -304,8 +310,10 @@ func (n *Node) Start(ctx context.Context) error { return fmt.Errorf("failed to connect to all bootstrappers") } - // start the discovery service to find peers in the discv5 DHT - n.sup.Add(n.disc) + if n.disc != nil { + slog.Info("Starting discovery actor") + n.sup.Add(n.disc) + } // start all long-running services return n.sup.Serve(ctx) diff --git a/fil/node_config.go b/fil/node_config.go index 3d5f791..8b83e00 100644 --- a/fil/node_config.go +++ b/fil/node_config.go @@ -35,6 +35,8 @@ type NodeConfig struct { // regenerating the key over and over again. privateKey *crypto.Secp256k1PrivateKey + DiscoveryActorEnabled bool + // General timeout when communicating with other network participants DialTimeout time.Duration From c3bf65f7eea748804d4f15737050e41b177b95e9 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Tue, 10 Jun 2025 16:47:20 +0200 Subject: [PATCH 34/65] filecoin: update bootstrappers --- cmd/hermes/cmd_fil.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/hermes/cmd_fil.go b/cmd/hermes/cmd_fil.go index 37e801f..a0c9ec6 100644 --- a/cmd/hermes/cmd_fil.go +++ b/cmd/hermes/cmd_fil.go @@ -118,7 +118,7 @@ func cmdFilAction(c *cli.Context) error { switch filConfig.Network { case "mainnet": bootstrapperMaddrStrs = []string{ - "/dns/node.glif.io/tcp/1235/p2p/12D3KooWBF8cpp65hp2u9LK5mh19x67ftAam84z9LsfaquTDSBpt", + "/dns/bootstrap.filecoin.chain.love/tcp/1235/p2p/12D3KooWBF8cpp65hp2u9LK5mh19x67ftAam84z9LsfaquTDSBpt", "/dns/bootstrap-venus.mainnet.filincubator.com/tcp/8888/p2p/QmQu8C6deXwKvJP2D8B6QGyhngc3ZiDnFzEHBDx8yeBXST", "/dns/bootstrap-mainnet-0.chainsafe-fil.io/tcp/34000/p2p/12D3KooWKKkCZbcigsWTEu1cgNetNbZJqeNtysRtFpq7DTqw3eqH", "/dns/bootstrap-mainnet-1.chainsafe-fil.io/tcp/34000/p2p/12D3KooWGnkd9GQKo3apkShQDaq1d6cKJJmsVe6KiQkacUk1T8oZ", From 406ff15341b4632338426cff0baeb52ed197b6c5 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Tue, 10 Jun 2025 16:47:36 +0200 Subject: [PATCH 35/65] host: log mesh metrics peers --- host/host.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/host/host.go b/host/host.go index cbe25c5..42b44f3 100644 --- a/host/host.go +++ b/host/host.go @@ -381,6 +381,7 @@ func (h *Host) UpdatePeerScore(scores map[peer.ID]*pubsub.PeerScoreSnapshot) { states := map[string]*topicState{} + slog.Debug("Tracking mesh metrics") for pid, pss := range scores { // pss: peer score snapshot // don't measure own scores @@ -388,6 +389,7 @@ func (h *Host) UpdatePeerScore(scores map[peer.ID]*pubsub.PeerScoreSnapshot) { continue } + topics := make([]string, 0, len(pss.Topics)) for topic, tss := range pss.Topics { // tss: topic score snapshot // Not sure if the peer score map also includes peers that were @@ -397,6 +399,9 @@ func (h *Host) UpdatePeerScore(scores map[peer.ID]*pubsub.PeerScoreSnapshot) { continue } + // track topics for the log message below + topics = append(topics, topic) + if _, ok := states[topic]; !ok { states[topic] = &topicState{ meshSize: 0, @@ -411,6 +416,8 @@ func (h *Host) UpdatePeerScore(scores map[peer.ID]*pubsub.PeerScoreSnapshot) { states[topic].scores = append(states[topic].scores, pss.Score) states[topic].appScores = append(states[topic].appScores, pss.AppSpecificScore) } + + slog.Debug(" tracked mesh metric for peer", "peerID", pid.String(), "topics", topics) } for topic, state := range states { From 29ca6731f3087fcc0e6cce800a360d4cc57d4443 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Tue, 10 Jun 2025 16:55:55 +0200 Subject: [PATCH 36/65] fix(filecoin): default discovery actor value --- cmd/hermes/cmd_fil.go | 2 +- fil/node_config.go | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd/hermes/cmd_fil.go b/cmd/hermes/cmd_fil.go index a0c9ec6..aec2179 100644 --- a/cmd/hermes/cmd_fil.go +++ b/cmd/hermes/cmd_fil.go @@ -102,7 +102,7 @@ var cmdFilFlags = []cli.Flag{ Name: "discovery.actor.enabled", EnvVars: []string{"HERMES_FIL_DISCOVERY_ACTOR_ENABLED"}, Usage: "Enables the discovery actor", - Value: false, + Value: filConfig.DiscoveryActorEnabled, Destination: &filConfig.DiscoveryActorEnabled, }, } diff --git a/fil/node_config.go b/fil/node_config.go index 8b83e00..0ad41c9 100644 --- a/fil/node_config.go +++ b/fil/node_config.go @@ -35,8 +35,6 @@ type NodeConfig struct { // regenerating the key over and over again. privateKey *crypto.Secp256k1PrivateKey - DiscoveryActorEnabled bool - // General timeout when communicating with other network participants DialTimeout time.Duration @@ -48,6 +46,9 @@ type NodeConfig struct { Libp2pPort int Libp2pPeerscoreSnapshotFreq time.Duration + // Whether to enable the periodic lookups + DiscoveryActorEnabled bool + // Pause between two discovery lookups LookupInterval time.Duration From 32b73a0ad301ec0c7719bea28cac04cfe4d9b93a Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Tue, 10 Jun 2025 17:41:21 +0200 Subject: [PATCH 37/65] filecoin: remove manifests subscription --- cmd/hermes/cmd_fil.go | 4 ---- fil/psutil.go | 1 - fil/pubsub.go | 38 -------------------------------------- 3 files changed, 43 deletions(-) diff --git a/cmd/hermes/cmd_fil.go b/cmd/hermes/cmd_fil.go index aec2179..a7ff58a 100644 --- a/cmd/hermes/cmd_fil.go +++ b/cmd/hermes/cmd_fil.go @@ -212,10 +212,6 @@ func topicConfigs() map[string]*fil.TopicConfig { } return map[string]*fil.TopicConfig{ - "/f3/manifests/0.0.2": { - ScoreParams: fil.PubsubTopicScoreParams, - Options: []pubsub.TopicOpt{pubsub.WithTopicMessageIdFn(fil.ManifestMessageIdFn)}, - }, "/f3/chainexchange/0.0.1/filecoin": { ScoreParams: fil.PubsubTopicScoreParams, Options: []pubsub.TopicOpt{pubsub.WithTopicMessageIdFn(fil.ChainExchangeMessageIdFn)}, diff --git a/fil/psutil.go b/fil/psutil.go index 0bc4b17..2d5eb8d 100644 --- a/fil/psutil.go +++ b/fil/psutil.go @@ -15,7 +15,6 @@ import ( ) var ( - ManifestMessageIdFn = pubsubMsgIdHashDataAndSender GPBFTMessageIdFn = pubsubMsgIdHashData ChainExchangeMessageIdFn = pubsubMsgIdHashData ) diff --git a/fil/pubsub.go b/fil/pubsub.go index 0281f16..73789a9 100644 --- a/fil/pubsub.go +++ b/fil/pubsub.go @@ -11,13 +11,11 @@ import ( f3 "github.com/filecoin-project/go-f3" "github.com/filecoin-project/go-f3/chainexchange" - "github.com/filecoin-project/go-f3/manifest" "github.com/filecoin-project/lotus/chain/types" "github.com/ipni/go-libipni/announce/message" pubsub "github.com/libp2p/go-libp2p-pubsub" pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb" "github.com/libp2p/go-libp2p/core/peer" - "github.com/sirupsen/logrus" "github.com/thejerf/suture/v4" "github.com/probe-lab/hermes/host" @@ -106,8 +104,6 @@ func (p *PubSub) Serve(ctx context.Context) error { func (p *PubSub) mapPubSubTopicWithHandlers(topic string) host.TopicHandler { switch { - case strings.HasPrefix(topic, "/f3/manifests"): - return p.handleF3Manifests case strings.HasPrefix(topic, "/f3/granite"): return p.handleF3Granite case strings.HasPrefix(topic, "/f3/chainexchange"): @@ -260,40 +256,6 @@ func (p *PubSub) handleF3Granite(ctx context.Context, msg *pubsub.Message) error return nil } -func (p *PubSub) handleF3Manifests(ctx context.Context, msg *pubsub.Message) error { - evt := &host.TraceEvent{ - Type: eventTypeHandleMessage, - Topic: msg.GetTopic(), - PeerID: p.host.ID(), - Timestamp: time.Now(), - } - - var update manifest.ManifestUpdateMessage - err := update.Unmarshal(bytes.NewReader(msg.Data)) - if err != nil { - logrus.WithError(err).Error("failed to unmarshal f3 manifest update message") - return fmt.Errorf("unmarshal cbor: %w", err) - } - - evt.Payload = map[string]any{ - "PeerID": msg.ReceivedFrom, - "Topic": msg.GetTopic(), - "Seq": hex.EncodeToString(msg.GetSeqno()), - "MsgID": hex.EncodeToString([]byte(msg.ID)), - "MsgSize": len(msg.Data), - "Manifest": update.Manifest, - "MsgSeq": update.MessageSequence, - } - - if err = p.cfg.DataStream.PutRecord(ctx, evt); err != nil { - slog.Warn( - "failed putting topic handler event", "topic", msg.GetTopic(), "err", tele.LogAttrError(err), - ) - } - - return nil -} - func (p *PubSub) validateF3ChainExchange(ctx context.Context, _ peer.ID, msg *pubsub.Message) pubsub.ValidationResult { var cmsg chainexchange.Message zstd, err := NewZSTD[*chainexchange.Message]() From 502ab5c86c8205934abdb48d1457deea05f5f581 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Tue, 10 Jun 2025 17:41:30 +0200 Subject: [PATCH 38/65] filecoin: log discovery interval --- fil/discovery.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fil/discovery.go b/fil/discovery.go index d2f906e..d9538ea 100644 --- a/fil/discovery.go +++ b/fil/discovery.go @@ -50,7 +50,7 @@ func NewDiscovery(h host.Host, cfg *DiscoveryConfig) (*Discovery, error) { } func (d *Discovery) Serve(ctx context.Context) (err error) { - slog.Info("Starting discv5 Discovery Service") + slog.Info("Starting discv5 Discovery Service", "interval", d.cfg.Interval) defer slog.Info("Stopped discv5 Discovery Service") defer func() { err = terminateSupervisorTreeOnErr(err) }() From 7b6e9ed7b3b4c37eb6c31ab793c719e776c6df36 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Tue, 10 Jun 2025 20:26:13 +0200 Subject: [PATCH 39/65] fix: reset topic metrics --- host/host.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/host/host.go b/host/host.go index 42b44f3..c2e2c65 100644 --- a/host/host.go +++ b/host/host.go @@ -420,11 +420,18 @@ func (h *Host) UpdatePeerScore(scores map[peer.ID]*pubsub.PeerScoreSnapshot) { slog.Debug(" tracked mesh metric for peer", "peerID", pid.String(), "topics", topics) } - for topic, state := range states { - h.meterMeshSize.Record(ctx, int64(state.meshSize), metric.WithAttributes(attribute.String("topic", topic))) - h.meterAvgMeshAge.Record(ctx, avg(state.meshTimes), metric.WithAttributes(attribute.String("topic", topic))) - h.meterAvgMeshScore.Record(ctx, avg(state.scores), metric.WithAttributes(attribute.String("topic", topic))) - h.meterAvgMeshAppScore.Record(ctx, avg(state.appScores), metric.WithAttributes(attribute.String("topic", topic))) + for _, topic := range h.ps.GetTopics() { + if state, found := states[topic]; found { + h.meterMeshSize.Record(ctx, int64(state.meshSize), metric.WithAttributes(attribute.String("topic", topic))) + h.meterAvgMeshAge.Record(ctx, avg(state.meshTimes), metric.WithAttributes(attribute.String("topic", topic))) + h.meterAvgMeshScore.Record(ctx, avg(state.scores), metric.WithAttributes(attribute.String("topic", topic))) + h.meterAvgMeshAppScore.Record(ctx, avg(state.appScores), metric.WithAttributes(attribute.String("topic", topic))) + } else { + h.meterMeshSize.Record(ctx, 0, metric.WithAttributes(attribute.String("topic", topic))) + h.meterAvgMeshAge.Record(ctx, 0, metric.WithAttributes(attribute.String("topic", topic))) + h.meterAvgMeshScore.Record(ctx, 0, metric.WithAttributes(attribute.String("topic", topic))) + h.meterAvgMeshAppScore.Record(ctx, 0, metric.WithAttributes(attribute.String("topic", topic))) + } } } From 1e06870e64912e473ae9b20ac7cc58652b417c00 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Tue, 10 Jun 2025 20:26:26 +0200 Subject: [PATCH 40/65] bump github.com/filecoin-project/go-f3 dep --- go.mod | 32 ++++++++++++++++---------------- go.sum | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/go.mod b/go.mod index 7cc509d..4fe908b 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/dennis-tra/go-kinesis v0.0.0-20240326083914-7acf5f8dc24e github.com/ethereum/go-ethereum v1.15.9 github.com/ferranbt/fastssz v0.1.4 - github.com/filecoin-project/go-f3 v0.8.3 + github.com/filecoin-project/go-f3 v0.8.4 github.com/filecoin-project/lotus v1.32.2 github.com/google/uuid v1.6.0 github.com/hashicorp/golang-lru/v2 v2.0.7 @@ -25,9 +25,9 @@ require ( github.com/libp2p/go-libp2p v0.41.1 github.com/libp2p/go-libp2p-kad-dht v0.33.0 github.com/libp2p/go-libp2p-mplex v0.10.0 - github.com/libp2p/go-libp2p-pubsub v0.13.1 + github.com/libp2p/go-libp2p-pubsub v0.14.0 github.com/lmittmann/tint v1.0.6 - github.com/multiformats/go-multiaddr v0.15.0 + github.com/multiformats/go-multiaddr v0.16.0 github.com/parquet-go/parquet-go v0.24.0 github.com/prometheus/client_golang v1.22.0 github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516 @@ -37,14 +37,14 @@ require ( github.com/thejerf/suture/v4 v4.0.6 github.com/urfave/cli/v2 v2.27.5 github.com/whyrusleeping/cbor-gen v0.3.1 - go.opentelemetry.io/otel v1.35.0 + go.opentelemetry.io/otel v1.36.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 go.opentelemetry.io/otel/exporters/prometheus v0.55.0 - go.opentelemetry.io/otel/metric v1.35.0 + go.opentelemetry.io/otel/metric v1.36.0 go.opentelemetry.io/otel/sdk v1.34.0 go.opentelemetry.io/otel/sdk/metric v1.33.0 - go.opentelemetry.io/otel/trace v1.35.0 - golang.org/x/crypto v0.38.0 + go.opentelemetry.io/otel/trace v1.36.0 + golang.org/x/crypto v0.39.0 golang.org/x/time v0.11.0 google.golang.org/grpc v1.70.0 google.golang.org/protobuf v1.36.6 @@ -118,7 +118,7 @@ require ( github.com/francoispqt/gojay v1.2.13 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect @@ -192,9 +192,9 @@ require ( github.com/multiformats/go-multiaddr-dns v0.4.1 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect - github.com/multiformats/go-multicodec v0.9.0 // indirect + github.com/multiformats/go-multicodec v0.9.1 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect - github.com/multiformats/go-multistream v0.6.0 // indirect + github.com/multiformats/go-multistream v0.6.1 // indirect github.com/multiformats/go-varint v0.0.7 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect @@ -269,15 +269,15 @@ require ( go.uber.org/mock v0.5.2 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect - golang.org/x/mod v0.24.0 // indirect - golang.org/x/net v0.40.0 // indirect + golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 // indirect + golang.org/x/mod v0.25.0 // indirect + golang.org/x/net v0.41.0 // indirect golang.org/x/oauth2 v0.25.0 // indirect - golang.org/x/sync v0.14.0 // indirect + golang.org/x/sync v0.15.0 // indirect golang.org/x/sys v0.33.0 // indirect golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.25.0 // indirect - golang.org/x/tools v0.33.0 // indirect + golang.org/x/text v0.26.0 // indirect + golang.org/x/tools v0.34.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gonum.org/v1/gonum v0.16.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b // indirect diff --git a/go.sum b/go.sum index acd55b4..0824f53 100644 --- a/go.sum +++ b/go.sum @@ -257,6 +257,8 @@ github.com/filecoin-project/go-crypto v0.1.0 h1:Pob2MphoipMbe/ksxZOMcQvmBHAd3sI/ github.com/filecoin-project/go-crypto v0.1.0/go.mod h1:K9UFXvvoyAVvB+0Le7oGlKiT9mgA5FHOJdYQXEE8IhI= github.com/filecoin-project/go-f3 v0.8.3 h1:0ToWoqJDsunr+Jf945Upvk6rdXn8It5B5LcyiY1Ry1k= github.com/filecoin-project/go-f3 v0.8.3/go.mod h1:KWksfw7CabMuL4ple/J52gK4soYBpTsL6i5WAgtJDqw= +github.com/filecoin-project/go-f3 v0.8.4 h1:qbdsiMYPWkM2zR/8oFDl4VvHm2YTF7xnr5m/smYKanA= +github.com/filecoin-project/go-f3 v0.8.4/go.mod h1:k23EMAx090NIWKlAYuO4TfjmfQTlIovaQ0nns960s9M= github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM= github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24= github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 h1:b3UDemBYN2HNfk3KOXNuxgTTxlWi3xVvbQP0IT38fvM= @@ -321,6 +323,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= @@ -673,6 +677,8 @@ github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMg github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= github.com/libp2p/go-libp2p-pubsub v0.13.1 h1:tV3ttzzZSCk0EtEXnxVmWIXgjVxXx+20Jwjbs/Ctzjo= github.com/libp2p/go-libp2p-pubsub v0.13.1/go.mod h1:MKPU5vMI8RRFyTP0HfdsF9cLmL1nHAeJm44AxJGJx44= +github.com/libp2p/go-libp2p-pubsub v0.14.0 h1:+YxFHOdrk45szLb8G/fVsWwg4pdx0nVUXoZdLvYw2VY= +github.com/libp2p/go-libp2p-pubsub v0.14.0/go.mod h1:MKPU5vMI8RRFyTP0HfdsF9cLmL1nHAeJm44AxJGJx44= github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= github.com/libp2p/go-libp2p-record v0.3.1 h1:cly48Xi5GjNw5Wq+7gmjfBiG9HCzQVkiZOUZ8kUl+Fg= github.com/libp2p/go-libp2p-record v0.3.1/go.mod h1:T8itUkLcWQLCYMqtX7Th6r7SexyUJpIyPgks757td/E= @@ -807,6 +813,8 @@ github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lg github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= github.com/multiformats/go-multiaddr v0.15.0 h1:zB/HeaI/apcZiTDwhY5YqMvNVl/oQYvs3XySU+qeAVo= github.com/multiformats/go-multiaddr v0.15.0/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0= +github.com/multiformats/go-multiaddr v0.16.0 h1:oGWEVKioVQcdIOBlYM8BH1rZDWOGJSqr9/BKl6zQ4qc= +github.com/multiformats/go-multiaddr v0.16.0/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0= github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.4.1 h1:whi/uCLbDS3mSEUMb1MsoT4uzUeZB0N32yzufqS0i5M= @@ -821,6 +829,8 @@ github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivnc github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +github.com/multiformats/go-multicodec v0.9.1 h1:x/Fuxr7ZuR4jJV4Os5g444F7xC4XmyUaT/FWtE+9Zjo= +github.com/multiformats/go-multicodec v0.9.1/go.mod h1:LLWNMtyV5ithSBUo3vFIMaeDy+h3EbkMTek1m+Fybbo= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= @@ -832,6 +842,8 @@ github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsC github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/multiformats/go-multistream v0.6.0 h1:ZaHKbsL404720283o4c/IHQXiS6gb8qAN5EIJ4PN5EA= github.com/multiformats/go-multistream v0.6.0/go.mod h1:MOyoG5otO24cHIg8kf9QW2/NozURlkP/rvi2FQJyCPg= +github.com/multiformats/go-multistream v0.6.1 h1:4aoX5v6T+yWmc2raBHsTvzmFhOI8WVOer28DeBBEYdQ= +github.com/multiformats/go-multistream v0.6.1/go.mod h1:ksQf6kqHAb6zIsyw7Zm+gAuVo57Qbq84E27YlYqavqw= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= @@ -1213,6 +1225,8 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSG go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I= go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= +go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 h1:5pojmb1U1AogINhN3SurB+zm/nIcusopeBNp42f45QM= @@ -1223,12 +1237,16 @@ go.opentelemetry.io/otel/exporters/prometheus v0.55.0 h1:sSPw658Lk2NWAv74lkD3B/R go.opentelemetry.io/otel/exporters/prometheus v0.55.0/go.mod h1:nC00vyCmQixoeaxF6KNyP42II/RHa9UdruK02qBmHvI= go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= +go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= go.opentelemetry.io/otel/sdk/metric v1.33.0 h1:Gs5VK9/WUJhNXZgn8MR6ITatvAmKeIuCtNbsP3JkNqU= go.opentelemetry.io/otel/sdk/metric v1.33.0/go.mod h1:dL5ykHZmm1B1nVRk9dDjChwDmt81MjVp3gLkQRwKf/Q= go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= +go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1284,9 +1302,13 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= +golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4= +golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -1302,6 +1324,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1340,6 +1364,8 @@ golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1359,6 +1385,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1435,6 +1463,8 @@ golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1463,6 +1493,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 476cfb90fa0679f0c64b03fe8a899a7011a8968e Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Thu, 12 Jun 2025 13:51:27 +0200 Subject: [PATCH 41/65] filecoin: remove wrong discv5 reference --- cmd/hermes/cmd_eth.go | 4 ++-- cmd/hermes/cmd_fil.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/hermes/cmd_eth.go b/cmd/hermes/cmd_eth.go index e87b57e..36ea355 100644 --- a/cmd/hermes/cmd_eth.go +++ b/cmd/hermes/cmd_eth.go @@ -158,7 +158,7 @@ var cmdEthFlags = []cli.Flag{ &cli.IntFlag{ Name: "devp2p.port", EnvVars: []string{"HERMES_ETH_DEVP2P_PORT"}, - Usage: "On which port should devp2p (disv5) listen", + Usage: "On which port should devp2p (discv5) listen", Value: ethConfig.Devp2pPort, Destination: ðConfig.Devp2pPort, DefaultText: "random", @@ -173,7 +173,7 @@ var cmdEthFlags = []cli.Flag{ &cli.IntFlag{ Name: "libp2p.port", EnvVars: []string{"HERMES_ETH_LIBP2P_PORT"}, - Usage: "On which port should libp2p (disv5) listen", + Usage: "On which port should libp2p (discv5) listen", Value: ethConfig.Libp2pPort, Destination: ðConfig.Libp2pPort, DefaultText: "random", diff --git a/cmd/hermes/cmd_fil.go b/cmd/hermes/cmd_fil.go index a7ff58a..e4052e9 100644 --- a/cmd/hermes/cmd_fil.go +++ b/cmd/hermes/cmd_fil.go @@ -71,7 +71,7 @@ var cmdFilFlags = []cli.Flag{ &cli.IntFlag{ Name: "libp2p.port", EnvVars: []string{"HERMES_FIL_LIBP2P_PORT"}, - Usage: "On which port should libp2p (disv5) listen", + Usage: "On which port should libp2p listen", Value: filConfig.Libp2pPort, Destination: &filConfig.Libp2pPort, DefaultText: "random", From 9940c7b888e9c9f23fedbf550520b7243975fbd3 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Thu, 12 Jun 2025 13:52:12 +0200 Subject: [PATCH 42/65] filecoin: drastically increase pubsub validate queue size --- fil/node_config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fil/node_config.go b/fil/node_config.go index 0ad41c9..3c787fe 100644 --- a/fil/node_config.go +++ b/fil/node_config.go @@ -223,7 +223,7 @@ func (n *NodeConfig) pubsubOptions(subFilter pubsub.SubscriptionFilter) []pubsub }), pubsub.WithPeerExchange(true), pubsub.WithSubscriptionFilter(subFilter), - pubsub.WithValidateQueueSize(128), // default is 32 + pubsub.WithValidateQueueSize(2048), // default is 32 pubsub.WithPeerScore( &pubsub.PeerScoreParams{ AppSpecificScore: func(p peer.ID) float64 { return 0 }, From 519992396827f8467b6cb2475714860ec70503d2 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Sun, 15 Jun 2025 21:31:48 +0200 Subject: [PATCH 43/65] filecoin: make validate queue size configurable --- cmd/hermes/cmd_fil.go | 10 ++++++++++ fil/node_config.go | 5 ++++- fil/pubsub.go | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/cmd/hermes/cmd_fil.go b/cmd/hermes/cmd_fil.go index e4052e9..efc22ff 100644 --- a/cmd/hermes/cmd_fil.go +++ b/cmd/hermes/cmd_fil.go @@ -21,6 +21,7 @@ var filConfig = &struct { Libp2pHost string Libp2pPort int Libp2pPeerscoreSnapshotFreq time.Duration + PubSubValidateQueueSize int LookupInterval time.Duration Network string DialTimeout time.Duration @@ -30,6 +31,7 @@ var filConfig = &struct { Libp2pHost: "127.0.0.1", Libp2pPort: 0, Libp2pPeerscoreSnapshotFreq: 15 * time.Second, + PubSubValidateQueueSize: 4096, LookupInterval: time.Minute, Network: "mainnet", DialTimeout: 5 * time.Second, @@ -91,6 +93,13 @@ var cmdFilFlags = []cli.Flag{ Destination: &filConfig.Libp2pPeerscoreSnapshotFreq, DefaultText: "random", }, + &cli.IntFlag{ + Name: "pubsub.validateQueueSize", + EnvVars: []string{"HERMES_FIL_PUBSUB_VALIDATE_QUEUE_SIZE"}, + Usage: "The queue size of the gossipsub validation queue", + Value: filConfig.PubSubValidateQueueSize, + Destination: &filConfig.PubSubValidateQueueSize, + }, &cli.DurationFlag{ Name: "lookup.interval", EnvVars: []string{"HERMES_FIL_LOOKUP_INTERVAL"}, @@ -149,6 +158,7 @@ func cmdFilAction(c *cli.Context) error { Libp2pPeerscoreSnapshotFreq: filConfig.Libp2pPeerscoreSnapshotFreq, LookupInterval: filConfig.LookupInterval, TopicConfigs: topicConfigs(), + PubSubValidateQueueSize: filConfig.PubSubValidateQueueSize, Bootstrappers: bootstrappers, DataStreamType: host.DataStreamtypeFromStr(rootConfig.DataStreamType), AWSConfig: rootConfig.awsConfig, diff --git a/fil/node_config.go b/fil/node_config.go index 3c787fe..5a8e1f3 100644 --- a/fil/node_config.go +++ b/fil/node_config.go @@ -41,6 +41,9 @@ type NodeConfig struct { // Topic configurations to subscribe to TopicConfigs map[string]*TopicConfig + // The size of the validate queue + PubSubValidateQueueSize int + // The address information of the local libp2p host Libp2pHost string Libp2pPort int @@ -223,7 +226,7 @@ func (n *NodeConfig) pubsubOptions(subFilter pubsub.SubscriptionFilter) []pubsub }), pubsub.WithPeerExchange(true), pubsub.WithSubscriptionFilter(subFilter), - pubsub.WithValidateQueueSize(2048), // default is 32 + pubsub.WithValidateQueueSize(n.PubSubValidateQueueSize), // default is 32 pubsub.WithPeerScore( &pubsub.PeerScoreParams{ AppSpecificScore: func(p peer.ID) float64 { return 0 }, diff --git a/fil/pubsub.go b/fil/pubsub.go index 73789a9..f6284c5 100644 --- a/fil/pubsub.go +++ b/fil/pubsub.go @@ -257,13 +257,13 @@ func (p *PubSub) handleF3Granite(ctx context.Context, msg *pubsub.Message) error } func (p *PubSub) validateF3ChainExchange(ctx context.Context, _ peer.ID, msg *pubsub.Message) pubsub.ValidationResult { - var cmsg chainexchange.Message zstd, err := NewZSTD[*chainexchange.Message]() if err != nil { slog.Warn("new zstd cbor decoder for *chainexchange.Message failed: ", tele.LogAttrError(err)) return pubsub.ValidationIgnore } + var cmsg chainexchange.Message if err := zstd.Decode(msg.Data, &cmsg); err != nil { return pubsub.ValidationReject } From cd12d7a103abeeae5dff06dcf603ff4110310187 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Sun, 15 Jun 2025 22:44:23 +0200 Subject: [PATCH 44/65] feat: add reason to reject msg metric --- host/meter_tracer.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/host/meter_tracer.go b/host/meter_tracer.go index 66e6a86..b608f15 100644 --- a/host/meter_tracer.go +++ b/host/meter_tracer.go @@ -186,7 +186,10 @@ func (m *meterTracer) DeliverMessage(msg *pubsub.Message) { // RejectMessage . func (m *meterTracer) RejectMessage(msg *pubsub.Message, reason string) { - m.rejectMsgCounter.Add(context.TODO(), 1, metric.WithAttributes(attribute.String("topic", msg.GetTopic()))) + m.rejectMsgCounter.Add(context.TODO(), 1, + metric.WithAttributes(attribute.String("topic", msg.GetTopic())), + metric.WithAttributes(attribute.String("reason", reason)), // there are eleven unique reasons + ) } // DuplicateMessage . From 849616d781ae395e00a40849f67f740cf36908f9 Mon Sep 17 00:00:00 2001 From: Matty Evans Date: Tue, 13 May 2025 18:48:36 +1000 Subject: [PATCH 45/65] feat(eth): add support for subscribing to custom topics (#62) * feat(eth): add support for subscribing to custom topics This commit adds a new flag `--subscription.topics` to the `eth` command, which allows users to specify a comma-separated list of topics to subscribe to. If this flag is not set, the default list of topics will be used. This change is useful for users who only want to subscribe to a subset of topics, which can reduce the amount of data they receive and improve performance. * docs: add documentation for topic subscription feature refactor(node_config): simplify topic subscription check to improve readability --- README.md | 26 ++++++++++++++++++++++- cmd/hermes/cmd_eth.go | 11 ++++++++++ eth/node_config.go | 31 +++++++++++++++++++++++++-- eth/node_config_test.go | 47 ++++++++++++++++++++++++++++++++++++++--- 4 files changed, 109 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ae0fd13..78a92cc 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ network. - [Deployment](#deployment) - [General](#general) - [Ethereum](#ethereum) + - [Subnet Configuration](#subnet-configuration) + - [Topic Subscription](#topic-subscription) - [Telemetry](#telemetry) - [Metrics](#metrics) - [Tracing](#tracing) @@ -229,7 +231,28 @@ For each topic that supports subnets, you can use one of these configuration str } ``` -This configuration allows you to set up multiple Hermes instances that monitor different parts of the network, or to focus monitoring on specific subnets of interest. +#### Topic Subscription + +In addition to subnet configuration, Hermes allows you to specify exactly which topics to subscribe to using the `--subscription.topics` flag. This gives you fine-grained control over which message types Hermes will monitor. + +By default, Hermes subscribes to all standard topics: +- Block messages +- Aggregate and proof messages +- Attestation messages +- Attester slashing messages +- Proposer slashing messages +- Contribution and proof messages +- Sync committee messages +- BLS to execution change messages +- Blob sidecar messages + +To subscribe to only specific topics, use the `--subscription.topics` flag with a comma-separated list: + +```shell +hermes eth --subscription.topics="beacon_attestation,beacon_block" +``` + +This configuration allows you to set up multiple Hermes instances that monitor different parts of the network, or to focus monitoring on specific subnets and topics of interest. To run Hermes for the Ethereum network you would need to point it to the beacon node by providing the @@ -282,6 +305,7 @@ OPTIONS: --config.yaml.url value The .yaml URL from which to fetch the beacon chain config, requires 'chain=devnet' [$HERMES_ETH_CONFIG_URL] --bootnodes.yaml.url value The .yaml URL from which to fetch the bootnode ENRs, requires 'chain=devnet' [$HERMES_ETH_BOOTNODES_URL] --deposit-contract-block.txt.url value The .txt URL from which to fetch the deposit contract block. Requires 'chain=devnet' [$HERMES_ETH_DEPOSIT_CONTRACT_BLOCK_URL] + --subscription.topics value [ --subscription.topics value ] Comma-separated list of topics to subscribe to (e.g. beacon_attestation,beacon_block) [$HERMES_ETH_SUBSCRIPTION_TOPICS] --subnet.attestation.type value Subnet selection strategy for attestation topics (all, static, random, static_range) (default: "all") [$HERMES_ETH_SUBNET_ATTESTATION_TYPE] --subnet.attestation.subnets value [ --subnet.attestation.subnets value ] Comma-separated list of subnet IDs for attestation when type=static [$HERMES_ETH_SUBNET_ATTESTATION_SUBNETS] --subnet.attestation.count value Number of random attestation subnets to select when type=random (default: 0) [$HERMES_ETH_SUBNET_ATTESTATION_COUNT] diff --git a/cmd/hermes/cmd_eth.go b/cmd/hermes/cmd_eth.go index 36ea355..9f1b1ed 100644 --- a/cmd/hermes/cmd_eth.go +++ b/cmd/hermes/cmd_eth.go @@ -57,6 +57,7 @@ var ethConfig = &struct { SubnetBlobSidecarCount uint64 SubnetBlobSidecarStart uint64 SubnetBlobSidecarEnd uint64 + SubscriptionTopics []string }{ PrivateKeyStr: "", // unset means it'll be generated Chain: params.MainnetName, @@ -370,6 +371,15 @@ var cmdEthFlags = []cli.Flag{ Value: ethConfig.SubnetBlobSidecarEnd, Destination: ðConfig.SubnetBlobSidecarEnd, }, + &cli.StringSliceFlag{ + Name: "subscription.topics", + EnvVars: []string{"HERMES_ETH_SUBSCRIPTION_TOPICS"}, + Usage: "An optional comma-separated list of topics to subscribe to", + Action: func(c *cli.Context, v []string) error { + ethConfig.SubscriptionTopics = v + return nil + }, + }, } func cmdEthAction(c *cli.Context) error { @@ -463,6 +473,7 @@ func cmdEthAction(c *cli.Context) error { PubSubSubscriptionRequestLimit: 200, // Prysm: beacon-chain/p2p/pubsub_filter.go#L22 PubSubQueueSize: 600, // Prysm: beacon-chain/p2p/config.go#L10 SubnetConfigs: createSubnetConfigs(), + SubscriptionTopics: ethConfig.SubscriptionTopics, Tracer: otel.GetTracerProvider().Tracer("hermes"), Meter: otel.GetMeterProvider().Meter("hermes"), } diff --git a/eth/node_config.go b/eth/node_config.go index a7968ee..0958392 100644 --- a/eth/node_config.go +++ b/eth/node_config.go @@ -8,6 +8,7 @@ import ( "log/slog" "math" "net" + "strings" "time" "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p" @@ -105,6 +106,10 @@ type NodeConfig struct { // Configuration for subnet selection by topic SubnetConfigs map[string]*SubnetConfig + // SubscriptionTopics is a list of topics to subscribe to. If not set, + // the default list of topics will be used. + SubscriptionTopics []string + // Telemetry accessors Tracer trace.Tracer Meter metric.Meter @@ -184,6 +189,19 @@ func (n *NodeConfig) Validate() error { } } + // Validate the SubscriptionTopics if provided. + if n.SubscriptionTopics != nil { + for _, topicBase := range n.SubscriptionTopics { + if topicBase == "" { + return fmt.Errorf("empty gossipsub topic provided") + } + + if _, err := topicFormatFromBase(topicBase); err != nil { + return err + } + } + } + // ensure that if the data stream is AWS, the parameters where given if n.DataStreamType == host.DataStreamTypeKinesis { if n.AWSConfig != nil { @@ -471,8 +489,17 @@ func (n *NodeConfig) composeEthTopicWithSubnet(base string, encoder encoder.Netw } func (n *NodeConfig) getDesiredFullTopics(encoder encoder.NetworkEncoding) []string { - desiredTopics := desiredPubSubBaseTopics() - fullTopics := make([]string, 0) + var ( + desiredTopics = desiredPubSubBaseTopics() + fullTopics = make([]string, 0) + ) + + // If the user has specified a list of topics to subscribe to, use that instead of the default list. + if len(n.SubscriptionTopics) > 0 { + desiredTopics = n.SubscriptionTopics + + slog.Info("Using user-specified topics", slog.Attr{Key: "topics", Value: slog.StringValue(strings.Join(desiredTopics, ", "))}) + } for _, topicBase := range desiredTopics { topicFormat, err := topicFormatFromBase(topicBase) diff --git a/eth/node_config_test.go b/eth/node_config_test.go index 2eb463e..2695d7d 100644 --- a/eth/node_config_test.go +++ b/eth/node_config_test.go @@ -76,9 +76,10 @@ func TestNodeConfig_ValidateSubnetConfigs(t *testing.T) { func TestNodeConfig_GetDesiredFullTopics(t *testing.T) { ssz := encoder.SszNetworkEncoder{} tests := []struct { - name string - subnetConfigs map[string]*SubnetConfig - wantTopicsFunc func(t *testing.T, topics []string) + name string + subnetConfigs map[string]*SubnetConfig + subscriptionTopics []string + wantTopicsFunc func(t *testing.T, topics []string) }{ { name: "static subnet config", @@ -141,12 +142,52 @@ func TestNodeConfig_GetDesiredFullTopics(t *testing.T) { ) }, }, + { + name: "custom subscription topics", + subscriptionTopics: []string{ + p2p.GossipBlockMessage, + p2p.GossipAttestationMessage, + }, + subnetConfigs: map[string]*SubnetConfig{ + p2p.GossipAttestationMessage: { + Type: SubnetStatic, + Subnets: []uint64{1, 2}, + }, + }, + wantTopicsFunc: func(t *testing.T, topics []string) { + // Check that we only have topics for the specified subscription topics + blockTopicFormat, err := topicFormatFromBase(p2p.GossipBlockMessage) + require.NoError(t, err) + blockTopic := fmt.Sprintf(blockTopicFormat, [4]byte{1, 2, 3, 4}) + ssz.ProtocolSuffix() + + attTopicFormat, err := topicFormatFromBase(p2p.GossipAttestationMessage) + require.NoError(t, err) + + // Check that block topic is included + assert.Contains(t, topics, blockTopic, "Block topic not found in result") + + // Check that attestation subnet topics are included + for _, subnet := range []uint64{1, 2} { + subnetTopic := formatSubnetTopic(attTopicFormat, subnet, ssz) + assert.Contains(t, topics, subnetTopic, "Expected subnet topic not found in result") + } + + // Check that we don't have any other base topics + // For example, we shouldn't have aggregate and proof messages + aggAndProofTopicFormat, err := topicFormatFromBase(p2p.GossipAggregateAndProofMessage) + require.NoError(t, err) + aggAndProofTopic := fmt.Sprintf(aggAndProofTopicFormat, [4]byte{1, 2, 3, 4}) + ssz.ProtocolSuffix() + + assert.NotContains(t, topics, aggAndProofTopic, "Unexpected topic found in result") + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := setupTestNodeConfig() cfg.SubnetConfigs = tt.subnetConfigs + cfg.SubscriptionTopics = tt.subscriptionTopics topics := cfg.getDesiredFullTopics(ssz) tt.wantTopicsFunc(t, topics) From d6b4efbf737efeaac180dee0038b8072f2cd874d Mon Sep 17 00:00:00 2001 From: Matty Evans Date: Wed, 4 Jun 2025 20:52:19 +1000 Subject: [PATCH 46/65] feat(eth/reqresp): Add metric for received goodbye messages (#64) Add a counter to track goodbye messages received from peers. This metric includes attributes for the goodbye code, the reason string, and the peer's agent version. This provides visibility into why peers are disconnecting. Introduce a helper function `normalizeAgentVersion` to extract the client name from the agent version string. This reduces the cardinality of the agent attribute in the metric. Also apply `normalizeAgentVersion` to the agent version logged in the stream handler for consistency. --- eth/reqresp.go | 64 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/eth/reqresp.go b/eth/reqresp.go index 5f1b205..5dddb11 100644 --- a/eth/reqresp.go +++ b/eth/reqresp.go @@ -69,6 +69,7 @@ type ReqResp struct { // metrics meterRequestCounter metric.Int64Counter latencyHistogram metric.Float64Histogram + goodbyeCounter metric.Int64Counter } type ContextStreamHandler func(context.Context, network.Stream) (map[string]any, error) @@ -110,6 +111,14 @@ func NewReqResp(h host.Host, cfg *ReqRespConfig) (*ReqResp, error) { return nil, fmt.Errorf("new request_latency histogram: %w", err) } + p.goodbyeCounter, err = cfg.Meter.Int64Counter( + "goodbye_messages", + metric.WithDescription("Counter for goodbye messages received"), + ) + if err != nil { + return nil, fmt.Errorf("new goodbye_messages counter: %w", err) + } + return p, nil } @@ -228,7 +237,7 @@ func (r *ReqResp) wrapStreamHandler(ctx context.Context, name string, handler Co agentVersion := "n.a." if err == nil { if av, ok := rawVal.(string); ok { - agentVersion = av + agentVersion = normalizeAgentVersion(av) } } @@ -324,6 +333,32 @@ func (r *ReqResp) goodbyeHandler(ctx context.Context, stream network.Stream) (ma msg, found := types.GoodbyeCodeMessages[req] if found { if _, err := r.host.Peerstore().Get(stream.Conn().RemotePeer(), peerstoreKeyIsHandshaked); err == nil { + var ( + agentVersion = "unknown" + reason = "unknown" + ) + + // Get agent version (client) for the peer. + rawVal, err := r.host.Peerstore().Get(stream.Conn().RemotePeer(), "AgentVersion") + if err == nil { + if av, ok := rawVal.(string); ok { + agentVersion = normalizeAgentVersion(av) + } + } + + // This will be one of GoodbyeCodeMessages. + if found { + reason = msg + } + + r.goodbyeCounter.Add(ctx, 1, metric.WithAttributes( + []attribute.KeyValue{ + attribute.Int64("code", int64(req)), + attribute.String("reason", reason), + attribute.String("agent", agentVersion), + }..., + )) + slog.Info("Received goodbye message", tele.LogAttrPeerID(stream.Conn().RemotePeer()), "msg", msg) } else { slog.Debug("Received goodbye message", tele.LogAttrPeerID(stream.Conn().RemotePeer()), "msg", msg) @@ -1080,3 +1115,30 @@ func (r *ReqResp) getBlockForForkVersion(forkV ForkVersion, encoding encoder.Net return sblk, fmt.Errorf("unrecognized fork_version (received:%s) (ours: %s) (global: %s)", forkV, r.cfg.ForkDigest, DenebForkVersion) } } + +// normalizeAgentVersion extracts the client name from the agent version string +// to reduce metric cardinality. +func normalizeAgentVersion(agentVersion string) string { + // List of known consensus layer clients + knownClients := []string{ + "prysm", "lighthouse", "nimbus", "lodestar", "grandine", "teku", "erigon", "caplin", + } + + // Convert to lowercase for case-insensitive matching. + lowerAgent := strings.ToLower(agentVersion) + + // Try to match against known clients. + for _, client := range knownClients { + if strings.Contains(lowerAgent, client) { + return client + } + } + + // Extract first part before slash if present. + parts := strings.Split(lowerAgent, "/") + if len(parts) > 0 && parts[0] != "" { + return parts[0] + } + + return "unknown" +} From f34f1ae7799f7cdb2993cf1345d036c4d725946a Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 23 Jun 2025 18:14:33 +0200 Subject: [PATCH 47/65] fix: staticcheck complaint --- fil/psutil.go | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/fil/psutil.go b/fil/psutil.go index 2d5eb8d..0857e87 100644 --- a/fil/psutil.go +++ b/fil/psutil.go @@ -40,33 +40,6 @@ func pubsubMsgIdHashData(m *pubsub_pb.Message) string { return string(hash[:]) } -// Generate a pubsub ID from the message topic + sender + data. -func pubsubMsgIdHashDataAndSender(m *pubsub_pb.Message) string { - hasher, err := blake2b.New256(nil) - if err != nil { - panic("failed to construct hasher") - } - - topic := []byte(m.GetTopic()) - if err := binary.Write(hasher, binary.BigEndian, uint32(len(topic))); err != nil { - panic(err) - } - if _, err := hasher.Write(topic); err != nil { - panic(err) - } - if err := binary.Write(hasher, binary.BigEndian, uint32(len(m.From))); err != nil { - panic(err) - } - if _, err := hasher.Write(m.From); err != nil { - panic(err) - } - if _, err := hasher.Write(m.Data); err != nil { - panic(err) - } - hash := hasher.Sum(nil) - return string(hash[:]) -} - // Borrowed from lotus var PubsubTopicScoreParams = &pubsub.TopicScoreParams{ // expected > 400 msgs/second on average. @@ -74,7 +47,6 @@ var PubsubTopicScoreParams = &pubsub.TopicScoreParams{ TopicWeight: 0.1, // max cap is 5, single invalid message is -100 // 1 tick per second, maxes at 1 hour - // XXX TimeInMeshWeight: 0.0002778, // ~1/3600 TimeInMeshQuantum: time.Second, TimeInMeshCap: 1, From c5d858db9cf2767ba6a7691c1133d4f3ba48b554 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 23 Jun 2025 18:21:18 +0200 Subject: [PATCH 48/65] fix: px parquet traces test --- host/parquet_traces_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/parquet_traces_test.go b/host/parquet_traces_test.go index 91b7818..36c8099 100644 --- a/host/parquet_traces_test.go +++ b/host/parquet_traces_test.go @@ -481,7 +481,7 @@ func TestParquetFormating(t *testing.T) { requireSentMsgEvent(t, e) case *GossipPeerExchangeEvent: - requireBaseEvent(t, EventTypeSentMsg, e.BaseEvent) + requireBaseEvent(t, EventTypeGossipPx, e.BaseEvent) direction, err := directionFromRPC(test.rawEvent.Type) require.NoError(t, err) requireBaseRPCEvent(t, direction, false, e.BaseRPCEvent) From f27254a9d80a0cd3f7016ed203f68a46b1733b1a Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 7 Jul 2025 13:41:05 +0200 Subject: [PATCH 49/65] add: funding.json --- .gitignore | 1 + funding.json | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 funding.json diff --git a/.gitignore b/.gitignore index add508f..7945346 100644 --- a/.gitignore +++ b/.gitignore @@ -148,6 +148,7 @@ fabric.properties # End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,go,goland+all,git *.json +!funding.json *.sh *.txt .vscode diff --git a/funding.json b/funding.json new file mode 100644 index 0000000..9d6c5d1 --- /dev/null +++ b/funding.json @@ -0,0 +1,5 @@ +{ + "opRetro": { + "projectId": "0x7504e494cb8d227193182e083128912173c14eaeecec9b90fa453de28377b269" + } +} \ No newline at end of file From e1f34f8dde35b2830905e1ac46efdbb2c320b37f Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 14 Jul 2025 08:35:34 +0200 Subject: [PATCH 50/65] filecoin: update readme --- README.md | 102 ++++++++++++++++++++++++++++++++-------------- cmd/hermes/cmd.go | 2 +- 2 files changed, 72 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 78a92cc..a83cf74 100644 --- a/README.md +++ b/README.md @@ -6,32 +6,39 @@ [![Build status](https://img.shields.io/github/actions/workflow/status/probe-lab/hermes/go-test.yml?branch=main)](https://github.com/probe-lab/hermes/actions) [![GoDoc](https://pkg.go.dev/badge/github.com/probe-lab/hermes)](https://pkg.go.dev/github.com/probe-lab/hermes) -Hermes is a GossipSub listener and tracer. It subscribes to all relevant pubsub topics -and traces all protocol interactions. As of `2024-05-21`, Hermes supports the Ethereum -network. +Hermes is a GossipSub listener and tracer. It subscribes to all relevant pubsub topics of the respective network +and traces all protocol interactions like grafts, prunes, and any RPCs. +As of `2025-07-11`, Hermes supports the Ethereum and Filecoin networks. ## Table of Contents -- [Hermes](#hermes) - - [Table of Contents](#table-of-contents) - - [Installation](#installation) - - [Developing](#developing) - - [CLI Arguments](#cli-arguments) - - [Deployment](#deployment) - - [General](#general) - - [Ethereum](#ethereum) - - [Subnet Configuration](#subnet-configuration) - - [Topic Subscription](#topic-subscription) - - [Telemetry](#telemetry) - - [Metrics](#metrics) - - [Tracing](#tracing) - - [Differences with other tools](#differences-with-other-tools) - - [Maintainers](#maintainers) - - [Contributing](#contributing) - - [License](#license) + + +* [Hermes](#hermes) + * [Table of Contents](#table-of-contents) + * [Installation](#installation) + * [Developing](#developing) + * [CLI Arguments](#cli-arguments) + * [Deployment](#deployment) + * [General](#general) + * [Ethereum](#ethereum) + * [Subnet Configuration](#subnet-configuration) + * [Filecoin](#filecoin) + * [Topic Subscription](#topic-subscription) + * [Telemetry](#telemetry) + * [Metrics](#metrics) + * [Tracing](#tracing) + * [Differences with other tools](#differences-with-other-tools) + * [Armiarma Crawler from MigaLabs vs Hermes from ProbeLab](#armiarma-crawler-from-migalabs-vs-hermes-from-probelab) + * [Maintainers](#maintainers) + * [Contributing](#contributing) + * [License](#license) + ## Installation +### From Source + ```sh go install github.com/probe-lab/hermes@latest ``` @@ -42,12 +49,15 @@ Check out the repository: ```shell git clone git@github.com:probe-lab/hermes.git +cd hermes ``` -Start Hermes by running +Start Hermes by running: ```shell -go run ./cmd/hermes # requires Go >=1.23 +go run ./cmd/hermes # Show help +go run ./cmd/hermes eth --help # Ethereum-specific options +go run ./cmd/hermes fil --help # Filecoin-specific options ```
@@ -62,6 +72,7 @@ USAGE: COMMANDS: eth, ethereum Listen to gossipsub topics of the Ethereum network + fil, filecoin Listen to gossipsub topics of the Filecoin network benchmark performs the given set of benchmarks for the hermes internals help, h Shows a list of commands or help for one command @@ -72,7 +83,7 @@ GLOBAL OPTIONS: --aws.key.id value Access key ID of the AWS account for the s3 bucket [$HERMES_AWS_ACCESS_KEY_ID] --aws.secret.key value Secret key of the AWS account for the S3 bucket [$HERMES_AWS_SECRET_KEY] - --data.stream.type value Format where the traces will be submitted: logger, kinesis, or callback. (default: "logger") [$HERMES_DATA_STREAM_TYPE] + --data.stream.type value Format where the traces will be submitted: logger, kinesis, noop, s3 or callback. (default: "logger") [$HERMES_DATA_STREAM_TYPE] --kinesis.region value The region of the AWS Kinesis Data Stream [$HERMES_KINESIS_REGION] --kinesis.stream value The name of the AWS Kinesis Data Stream [$HERMES_KINESIS_DATA_STREAM] --s3.bucket value Name of the S3 bucket that will be used as reference to submit the traces (default: "hermes") [$HERMES_S3_BUCKET] @@ -81,11 +92,12 @@ GLOBAL OPTIONS: --s3.flush.interval value Minimum time interval at which the batched traces will be dump in S3 (default: 2s) [$HERMES_S3_FLUSH_INTERVAL] --s3.flushers value Number of flushers that will be spawned to dump traces into S3 (default: 2) [$HERMES_S3_FLUSHERS] --s3.region value The name of the region where the s3 bucket will be stored [$HERMES_S3_REGION] + --s3.tag value Tag within the S3 bucket that will be used as reference to submit the traces [$HERMES_S3_TAG] Logging Configuration: --log.format value Sets the format to output the log statements in: text, json, hlog, tint (default: "hlog") [$HERMES_LOG_FORMAT] - --log.level value Sets an explicity logging level: debug, info, warn, error. Takes precedence over the verbose flag. (default: "info") [$HERMES_LOG_LEVEL] + --log.level value Sets an explicitly logging level: debug, info, warn, error. Takes precedence over the verbose flag. (default: "info") [$HERMES_LOG_LEVEL] --log.nocolor Whether to prevent the logger from outputting colored log statements (default: false) [$HERMES_LOG_NO_COLOR] --log.source Compute the source code position of a log statement and add a SourceKey attribute to the output. Only text and json formats. (default: false) [$HERMES_LOG_SOURCE] --verbose, -v Set logging level more verbose to include debug level logs (default: false) [$HERMES_VERBOSE] @@ -98,6 +110,7 @@ GLOBAL OPTIONS: --tracing Whether to emit trace data (default: false) [$HERMES_TRACING_ENABLED] --tracing.addr value Where to publish the traces to. (default: "localhost") [$HERMES_TRACING_ADDR] --tracing.port value On which port does the traces collector listen (default: 4317) [$HERMES_TRACING_PORT] + ```
@@ -105,7 +118,7 @@ GLOBAL OPTIONS: ### CLI Arguments We use dot notation to namespace command line arguments instead of hyphens because [the CLI library](https://github.com/urfave/cli) allows -to configuration parameters from a file which will then resolve the command line parameters. For example, +configuring parameters from a file which will then resolve the command line parameters. For example, the CLI flag `--log.format` could be read from a yaml file that looks like this: ```yaml @@ -118,9 +131,10 @@ _However_, Hermes currently doesn't support loading CLI arguments from a file ¯ ## Deployment Depending on the network you want to trace Hermes requires auxiliary infrastructure. -As of `2024-03-27`, Hermes supports these networks: +As of `2025-07-11`, Hermes supports these networks: - [Ethereum](#ethereum) +- [Filecoin](#filecoin) ### General @@ -131,8 +145,7 @@ There are different ways of keeping track of the events that Hermes generates: - `--kinesis.region=us-east-1` # just an example - `--kinesis.stream=$YOUR_DATA_STREAM_NAME` - If the name is set, Hermes will start pumping events to that stream. - -> It's important to note that the events **will not** be strictly ordered. They will only follow a lose ordering. The reasons are 1) potential retries of event submissions and 2) [record aggregation](https://docs.aws.amazon.com/streams/latest/dev/kinesis-kpl-concepts.html#kinesis-kpl-concepts-aggretation). Depending on the configured number of submission retries the events should be ordered within each 30s time window. + > It's important to note that the events **will not** be strictly ordered. They will only follow a lose ordering. The reasons are 1) potential retries of event submissions and 2) [record aggregation](https://docs.aws.amazon.com/streams/latest/dev/kinesis-kpl-concepts.html#kinesis-kpl-concepts-aggretation). Depending on the configured number of submission retries the events should be ordered within each 30s time window. - [S3](https://aws.amazon.com/s3/). Hermes will batch the traces, format them into a parquet file, and submit them to the given S3 Bucket. These are the flags that should be provided: - `--data.stream.type="s3"` - `--s3.region="us-east-1"` # just an example @@ -145,11 +158,12 @@ There are different ways of keeping track of the events that Hermes generates: - `--aws.key.id=$YOUR_AWS_KEY_ID` # only necessary for private buckets - `--aws.secret.key=$YOUR_AWS_SECRET_KEY` # only necessary for private buckets - - `Code Callbacks`. Hermes will execute the given callback functions whenever an event is traced. - `--data.stream.type="callback"` - `Logger`. Hermes will print the JSON formatted traces into `stdout` in a log format (ideal for local testing). - - `--data.strea.type="logger"` + - `--data.stream.type="logger"` +- `Noop`. Hermes will discard all traces. We use this for debugging other parts of the stack where the actual events aren't relevant but would otherwise pollute the logs. + - `--data.stream.type="noop"` _Note: we provide a local s3 setup to use if needed. The configuration of the `localstack s3` instance can be tunned using a copy (`.env`) of the `.env.template` file, which will be read by default when doing `docker compose up s3`. Make sure that the docker container is up running when launching the `hermes` instance._ @@ -326,6 +340,33 @@ OPTIONS: +### Filecoin + +To run Hermes in the Filecoin network, no auxiliary infrastructure is needed. +Just run: + +```shell +go run ./cmd/hermes fil +``` + +This will instruct Hermes to bootstrap into the Filecoin network using the +canonical bootstrap peers. By default, it subscribes to the following hard-coded (!) +topics: + +```text +/f3/chainexchange/0.0.1/filecoin +/f3/granite/0.0.3/filecoin +/fil/blocks/testnetnet +/fil/msgs/testnetnet +/indexer/ingest/mainnet +/drand/pubsub/v0.0.0/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971 +/drand/pubsub/v0.0.0/80c8b872c714f4c00fdd3daa465d5514049f457f01f85a4caf68cdcd394ba039 +/drand/pubsub/v0.0.0/8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce +``` + +On top of that, Hermes will periodically do a DHT lookup for arbitrary keys to +make itself known to the network but also to learn and discover new peers which +could be added to the mesh. ## Telemetry @@ -368,7 +409,6 @@ On the other hand, although Hermes also relies on a continuously running discv5 - [Dennis Trautwein](https://github.com/dennis-tra) - [Mikel Cortes](https://github.com/cortze) -- [Guillaume Michel](https://github.com/guillaumemichel) ## Contributing diff --git a/cmd/hermes/cmd.go b/cmd/hermes/cmd.go index 0b89f3a..670bf34 100644 --- a/cmd/hermes/cmd.go +++ b/cmd/hermes/cmd.go @@ -118,7 +118,7 @@ var rootFlags = []cli.Flag{ &cli.StringFlag{ Name: "log.level", EnvVars: []string{"HERMES_LOG_LEVEL"}, - Usage: "Sets an explicity logging level: debug, info, warn, error. Takes precedence over the verbose flag.", + Usage: "Sets an explicitly logging level: debug, info, warn, error. Takes precedence over the verbose flag.", Destination: &rootConfig.LogLevel, Value: rootConfig.LogLevel, Category: flagCategoryLogging, From 0445f8e60fdf2c267094fc4b8c3a477beef52192 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 14 Jul 2025 08:43:05 +0200 Subject: [PATCH 51/65] update: README ToC --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a83cf74..bea75b6 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,15 @@ As of `2025-07-11`, Hermes supports the Ethereum and Filecoin networks. * [Hermes](#hermes) * [Table of Contents](#table-of-contents) * [Installation](#installation) + * [From Source](#from-source) * [Developing](#developing) * [CLI Arguments](#cli-arguments) * [Deployment](#deployment) * [General](#general) * [Ethereum](#ethereum) * [Subnet Configuration](#subnet-configuration) - * [Filecoin](#filecoin) * [Topic Subscription](#topic-subscription) + * [Filecoin](#filecoin) * [Telemetry](#telemetry) * [Metrics](#metrics) * [Tracing](#tracing) From e2893818eac8d4206c131ff7c26ff09b703eed6f Mon Sep 17 00:00:00 2001 From: Mikel Cortes <45786396+cortze@users.noreply.github.com> Date: Tue, 5 Aug 2025 15:05:36 +0200 Subject: [PATCH 52/65] Update the Readme (#69) * add comparison between hermes and filecoin-lite * add hermes' light networking capabilities * Update README.md Co-authored-by: Yiannis Psaras <52073247+yiannisbot@users.noreply.github.com> * add missing text --------- Co-authored-by: Yiannis Psaras <52073247+yiannisbot@users.noreply.github.com> --- README.md | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bea75b6..7430f3f 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,13 @@ [![Build status](https://img.shields.io/github/actions/workflow/status/probe-lab/hermes/go-test.yml?branch=main)](https://github.com/probe-lab/hermes/actions) [![GoDoc](https://pkg.go.dev/badge/github.com/probe-lab/hermes)](https://pkg.go.dev/github.com/probe-lab/hermes) -Hermes is a GossipSub listener and tracer. It subscribes to all relevant pubsub topics of the respective network -and traces all protocol interactions like grafts, prunes, and any RPCs. +Hermes is light libp2p networking node that serves as a GossipSub listener and tracer for multiple networks. +It discovers and connects with network participats subscribing to all relevant pubsub topics of the respective +network and traces all protocol interactions like grafts, prunes, and any RPCs. As of `2025-07-11`, Hermes supports the Ethereum and Filecoin networks. ## Table of Contents - * [Hermes](#hermes) * [Table of Contents](#table-of-contents) @@ -26,6 +26,8 @@ As of `2025-07-11`, Hermes supports the Ethereum and Filecoin networks. * [Subnet Configuration](#subnet-configuration) * [Topic Subscription](#topic-subscription) * [Filecoin](#filecoin) + * [Hermes vs Filecoin Lite Nodes](#hermes-vs-filecoin-lite-nodes) + * [Importing Hermes](#importing-hermes) * [Telemetry](#telemetry) * [Metrics](#metrics) * [Tracing](#tracing) @@ -198,12 +200,12 @@ cfg.SubnetConfigs = map[string]*eth.SubnetConfig{ Type: eth.SubnetStatic, Subnets: []uint64{0, 1, 5, 44}, }, - + // Subscribe to all sync committee subnets (this is the default if no config provided) p2p.GossipSyncCommitteeMessage: { Type: eth.SubnetAll, }, - + // Subscribe to a random set of blob sidecar subnets p2p.GossipBlobSidecarMessage: { Type: eth.SubnetRandom, @@ -343,7 +345,7 @@ OPTIONS: ### Filecoin -To run Hermes in the Filecoin network, no auxiliary infrastructure is needed. +To run Hermes in the Filecoin network, no auxiliary infrastructure is needed. Just run: ```shell @@ -369,6 +371,27 @@ On top of that, Hermes will periodically do a DHT lookup for arbitrary keys to make itself known to the network but also to learn and discover new peers which could be added to the mesh. +#### Hermes vs Filecoin Lite Nodes +Existing Filecoin lite nodes, such as the Lotus lite node option, are primarily used for interacting with the network. +It is a resource efficient interface for end users to create wallets and keys, sign messages and submit transactions. +A Lotus lite node cannot connect to the GossipSub protocol and relies on a remote full node to get blockchain data. + +Hermes, on the other hand, is a network monitoring instrument to analyze GossipSub performance. +It behaves like a light node in the network by connecting to other nodes and advertising its presence through a periodic DHT lookup. +Hermes subscribes to all available GossipSub topics, allowing it to comprehensively receive and trace all of the activity in the network. + +## Importing Hermes +Hermes is more than just a simple GossipSub listener and tracer. +Its simplicity, lightweight deployment requirements, and abstraction from the application-layer logic, +makes it a suitable library for interacting with any of the supported networks—without needing to fork existing clients. + +The modular design, covering the peer discovery, libp2p host, or the GossipSub listener, makes it a strong foundation for interacting with networks, allowing for more than just monitoring P2P performance. +Because of that, Hermes can be leveraged as a general-purpose networking interface, extending its use cases beyond traditional network metrics. + +Below is a list of projects and studies that have relied on Hermes as a networking interface: +- [xatu](https://github.com/ethpandaops/xatu) +- [net-probe](https://ethresear.ch/t/bandwidth-availability-in-ethereum-regional-differences-and-network-impacts/21138) + ## Telemetry ### Metrics From 4c344c0ebe7660450bef29a4546b99f1dfac82ef Mon Sep 17 00:00:00 2001 From: web3-bot <81333946+web3-bot@users.noreply.github.com> Date: Wed, 13 Aug 2025 08:31:18 +0100 Subject: [PATCH 53/65] chore: update .github/workflows/go-test.yml (#70) --- .github/workflows/go-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index f57ee5a..d4458c9 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -34,7 +34,7 @@ jobs: --health-timeout 5s --health-retries 5 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Setup Go uses: actions/setup-go@v5 with: From 641c3e90e74b5a781b59566e101d44e2a5b897c2 Mon Sep 17 00:00:00 2001 From: Mikel Cortes <45786396+cortze@users.noreply.github.com> Date: Thu, 21 Aug 2025 15:24:40 +0200 Subject: [PATCH 54/65] Fix Eth connectivity issues (#71) * pass full discv peer to dialer * add subnet to bitfield translation * pass the full discovered peers to the dialer * ensure that the ENR and the MetaData share the right subnets * add comment on peer-dialer * make statickcheck happy * bypass the default empty subnet configurations * simplify code * udpate dependencies * clean-up * add metrics for control msgs (per msgID) --- cmd/hermes/cmd_eth.go | 12 +++------ eth/config_test.go | 6 ++--- eth/discovery.go | 6 ++--- eth/discovery_config.go | 22 ++++++++--------- eth/genesis.go | 6 ++--- eth/node.go | 42 +++++++++++++++++++++----------- eth/node_config_test.go | 8 +++--- eth/peer_dialer.go | 37 +++++++++++++++++++--------- eth/reqresp.go | 26 ++++++++++++++------ eth/subnets.go | 40 ++++++++++++++++++++++++------ eth/subnets_integration_test.go | 6 ++--- eth/subnets_test.go | 26 ++++++++++++-------- eth/topic_score_params.go | 26 ++++++++++---------- go.mod | 6 ++--- go.sum | 40 +++--------------------------- host/meter_tracer.go | 43 ++++++++++++++++++++++++++++++--- 16 files changed, 210 insertions(+), 142 deletions(-) diff --git a/cmd/hermes/cmd_eth.go b/cmd/hermes/cmd_eth.go index 9f1b1ed..0af217a 100644 --- a/cmd/hermes/cmd_eth.go +++ b/cmd/hermes/cmd_eth.go @@ -437,11 +437,6 @@ func cmdEthAction(c *cli.Context) error { return fmt.Errorf("create fork digest (%s, %x): %w", genesisTime, genesisRoot, err) } - // Overriding configuration so that functions like ComputForkDigest take the - // correct input data from the global configuration. - params.OverrideBeaconConfig(config.Beacon) - params.OverrideBeaconNetworkConfig(config.Network) - cfg := ð.NodeConfig{ GenesisConfig: config.Genesis, NetworkConfig: config.Network, @@ -488,6 +483,7 @@ func cmdEthAction(c *cli.Context) error { // createSubnetConfigs creates subnet configurations based on the command line flags. func createSubnetConfigs() map[string]*eth.SubnetConfig { + // ensure that we don't subscribe to any of the topics by default subnetConfigs := make(map[string]*eth.SubnetConfig) // Configure attestation subnets if specified @@ -579,7 +575,7 @@ func createAttestationSubnetConfig() *eth.SubnetConfig { config.Start = ethConfig.SubnetAttestationStart config.End = ethConfig.SubnetAttestationEnd } - + eth.GetSubscribedSubnets(config, eth.GlobalBeaconConfig.AttestationSubnetCount) return config } @@ -606,7 +602,7 @@ func createSyncCommitteeSubnetConfig() *eth.SubnetConfig { config.Start = ethConfig.SubnetSyncCommitteeStart config.End = ethConfig.SubnetSyncCommitteeEnd } - + eth.GetSubscribedSubnets(config, eth.GlobalBeaconConfig.SyncCommitteeSubnetCount) return config } @@ -633,7 +629,7 @@ func createBlobSidecarSubnetConfig() *eth.SubnetConfig { config.Start = ethConfig.SubnetBlobSidecarStart config.End = ethConfig.SubnetBlobSidecarEnd } - + eth.GetSubscribedSubnets(config, eth.GlobalBeaconConfig.BlobsidecarSubnetCountElectra) return config } diff --git a/eth/config_test.go b/eth/config_test.go index 2c3b2be..6da7b87 100644 --- a/eth/config_test.go +++ b/eth/config_test.go @@ -173,7 +173,7 @@ func TestTopicGenerationWithMixedConfig(t *testing.T) { // Should have exactly the configured attestation subnets hasAttSubnet := make(map[uint64]bool) for _, topic := range topics { - for subnet := uint64(0); subnet < globalBeaconConfig.AttestationSubnetCount; subnet++ { + for subnet := uint64(0); subnet < GlobalBeaconConfig.AttestationSubnetCount; subnet++ { expectedTopic := formatSubnetTopic(attTopicFormat, subnet, *encoder) if topic == expectedTopic { hasAttSubnet[subnet] = true @@ -194,7 +194,7 @@ func TestTopicGenerationWithMixedConfig(t *testing.T) { syncSubnetCount := 0 for _, topic := range topics { - for subnet := uint64(0); subnet < globalBeaconConfig.SyncCommitteeSubnetCount; subnet++ { + for subnet := uint64(0); subnet < GlobalBeaconConfig.SyncCommitteeSubnetCount; subnet++ { expectedTopic := formatSubnetTopic(syncTopicFormat, subnet, *encoder) if topic == expectedTopic { syncSubnetCount++ @@ -203,6 +203,6 @@ func TestTopicGenerationWithMixedConfig(t *testing.T) { } // Should have all sync committee subnets - assert.Equal(t, int(globalBeaconConfig.SyncCommitteeSubnetCount), syncSubnetCount, + assert.Equal(t, int(GlobalBeaconConfig.SyncCommitteeSubnetCount), syncSubnetCount, "Should have all sync committee subnets by default") } diff --git a/eth/discovery.go b/eth/discovery.go index e8b4411..9ceb8ba 100644 --- a/eth/discovery.go +++ b/eth/discovery.go @@ -31,7 +31,7 @@ type Discovery struct { cfg *DiscoveryConfig pk *ecdsa.PrivateKey node *enode.LocalNode - out chan peer.AddrInfo + out chan *DiscoveredPeer // Metrics MeterDiscoveredPeers metric.Int64Counter @@ -77,7 +77,7 @@ func NewDiscovery(privKey *ecdsa.PrivateKey, cfg *DiscoveryConfig) (*Discovery, cfg: cfg, pk: privKey, node: localNode, - out: make(chan peer.AddrInfo), + out: make(chan *DiscoveredPeer), } d.MeterDiscoveredPeers, err = cfg.Meter.Int64Counter("discovered_peers", metric.WithDescription("Total number of discovered peers")) @@ -207,7 +207,7 @@ func (d *Discovery) Serve(ctx context.Context) (err error) { d.MeterDiscoveredPeers.Add(ctx, 1) select { - case d.out <- pi.AddrInfo: + case d.out <- pi: case <-ctx.Done(): return nil } diff --git a/eth/discovery_config.go b/eth/discovery_config.go index c4852d6..c75d515 100644 --- a/eth/discovery_config.go +++ b/eth/discovery_config.go @@ -9,7 +9,6 @@ import ( "github.com/OffchainLabs/prysm/v6/time/slots" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" - "github.com/prysmaticlabs/go-bitfield" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" ) @@ -17,11 +16,15 @@ import ( type DiscoveryConfig struct { GenesisConfig *GenesisConfig NetworkConfig *params.NetworkConfig - Addr string - UDPPort int - TCPPort int - Tracer trace.Tracer - Meter metric.Meter + + Addr string + UDPPort int + TCPPort int + Tracer trace.Tracer + Meter metric.Meter + + AttestationSubnetConfig *SubnetConfig + SyncSubnetConfig *SubnetConfig } // enrEth2Entry generates an Ethereum 2.0 entry for the Ethereum Node Record @@ -61,15 +64,12 @@ func (d *DiscoveryConfig) enrEth2Entry() (enr.Entry, error) { } func (d *DiscoveryConfig) enrAttnetsEntry() enr.Entry { - bitV := bitfield.NewBitvector64() - for i := uint64(0); i < bitV.Len(); i++ { - bitV.SetBitAt(i, true) - } + bitV := BitArrayFromAttestationSubnets(d.AttestationSubnetConfig.Subnets) return enr.WithEntry(d.NetworkConfig.AttSubnetKey, bitV.Bytes()) } func (d *DiscoveryConfig) enrSyncnetsEntry() enr.Entry { - bitV := bitfield.Bitvector4{byte(0x00)} + bitV := BitArrayFromSyncSubnets(d.SyncSubnetConfig.Subnets) return enr.WithEntry(d.NetworkConfig.SyncCommsSubnetKey, bitV.Bytes()) } diff --git a/eth/genesis.go b/eth/genesis.go index 5476b23..3afbe7c 100644 --- a/eth/genesis.go +++ b/eth/genesis.go @@ -26,7 +26,7 @@ var ( DenebForkVersion ForkVersion ElectraForkVersion ForkVersion - globalBeaconConfig = params.MainnetConfig() // init with Mainnet (we would override if needed) + GlobalBeaconConfig = params.MainnetConfig() // init with Mainnet (we would override if needed) ) // configure global ForkVersion variables @@ -38,7 +38,7 @@ func initNetworkForkVersions(beaconConfig *params.BeaconChainConfig) { DenebForkVersion = ForkVersion(beaconConfig.DenebForkVersion) ElectraForkVersion = ForkVersion(beaconConfig.ElectraForkVersion) - globalBeaconConfig = beaconConfig + GlobalBeaconConfig = beaconConfig } // GenesisConfig represents the Genesis configuration with the Merkle Root @@ -105,7 +105,7 @@ func GetCurrentForkVersion(epoch primitives.Epoch, beaconConfg *params.BeaconCha } func GetForkVersionFromForkDigest(forkD [4]byte) (forkV ForkVersion, err error) { - genesisRoot := GenesisConfigs[globalBeaconConfig.ConfigName].GenesisValidatorRoot + genesisRoot := GenesisConfigs[GlobalBeaconConfig.ConfigName].GenesisValidatorRoot phase0D, _ := signing.ComputeForkDigest(Phase0ForkVersion[:], genesisRoot) altairD, _ := signing.ComputeForkDigest(AltairForkVersion[:], genesisRoot) bellatrixD, _ := signing.ComputeForkDigest(BellatrixForkVersion[:], genesisRoot) diff --git a/eth/node.go b/eth/node.go index bcded24..0d40bd7 100644 --- a/eth/node.go +++ b/eth/node.go @@ -8,6 +8,7 @@ import ( "sort" "time" + "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p" eth "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1" "github.com/aws/aws-sdk-go-v2/service/kinesis" gk "github.com/dennis-tra/go-kinesis" @@ -160,14 +161,25 @@ func NewNode(cfg *NodeConfig) (*Node, error) { return nil, fmt.Errorf("extract ecdsa private key: %w", err) } + attConfig, ok := cfg.SubnetConfigs[p2p.GossipAttestationMessage] + if !ok { + attConfig = new(SubnetConfig) + } + syncConfig, ok := cfg.SubnetConfigs[p2p.GossipSyncCommitteeMessage] + if !ok { + syncConfig = new(SubnetConfig) + } + disc, err := NewDiscovery(privKey, &DiscoveryConfig{ - GenesisConfig: cfg.GenesisConfig, - NetworkConfig: cfg.NetworkConfig, - Addr: cfg.Devp2pHost, - UDPPort: cfg.Devp2pPort, - TCPPort: cfg.Libp2pPort, - Tracer: cfg.Tracer, - Meter: cfg.Meter, + GenesisConfig: cfg.GenesisConfig, + NetworkConfig: cfg.NetworkConfig, + AttestationSubnetConfig: attConfig, + SyncSubnetConfig: syncConfig, + Addr: cfg.Devp2pHost, + UDPPort: cfg.Devp2pPort, + TCPPort: cfg.Libp2pPort, + Tracer: cfg.Tracer, + Meter: cfg.Meter, }) if err != nil { return nil, fmt.Errorf("new discovery service: %w", err) @@ -176,13 +188,15 @@ func NewNode(cfg *NodeConfig) (*Node, error) { // initialize the request-response protocol handlers reqRespCfg := &ReqRespConfig{ - ForkDigest: cfg.ForkDigest, - Encoder: cfg.RPCEncoder, - DataStream: ds, - ReadTimeout: cfg.BeaconConfig.TtfbTimeoutDuration(), - WriteTimeout: cfg.BeaconConfig.RespTimeoutDuration(), - Tracer: cfg.Tracer, - Meter: cfg.Meter, + ForkDigest: cfg.ForkDigest, + Encoder: cfg.RPCEncoder, + AttestationSubnetConfig: attConfig, + SyncSubnetConfig: syncConfig, + DataStream: ds, + ReadTimeout: cfg.BeaconConfig.TtfbTimeoutDuration(), + WriteTimeout: cfg.BeaconConfig.RespTimeoutDuration(), + Tracer: cfg.Tracer, + Meter: cfg.Meter, } reqResp, err := NewReqResp(h, reqRespCfg) diff --git a/eth/node_config_test.go b/eth/node_config_test.go index 2695d7d..fc71b91 100644 --- a/eth/node_config_test.go +++ b/eth/node_config_test.go @@ -123,12 +123,12 @@ func TestNodeConfig_GetDesiredFullTopics(t *testing.T) { attTopicFormat, err := topicFormatFromBase(p2p.GossipAttestationMessage) require.NoError(t, err) - totalAttSubnets := int(globalBeaconConfig.AttestationSubnetCount) + totalAttSubnets := int(GlobalBeaconConfig.AttestationSubnetCount) attSubnetTopicCount := 0 // Count how many attestation subnet topics we have. for _, topic := range topics { - for subnet := uint64(0); subnet < globalBeaconConfig.AttestationSubnetCount; subnet++ { + for subnet := uint64(0); subnet < GlobalBeaconConfig.AttestationSubnetCount; subnet++ { if topic == formatSubnetTopic(attTopicFormat, subnet, ssz) { attSubnetTopicCount++ break @@ -200,7 +200,7 @@ func formatSubnetTopic(base string, subnet uint64, encoder encoder.NetworkEncodi } func setupTestNodeConfig() *NodeConfig { - globalBeaconConfig = defaultTestBeaconConfig() + GlobalBeaconConfig = defaultTestBeaconConfig() return &NodeConfig{ GenesisConfig: &GenesisConfig{ @@ -208,7 +208,7 @@ func setupTestNodeConfig() *NodeConfig { GenesisValidatorRoot: []byte{1, 2, 3}, }, NetworkConfig: ¶ms.NetworkConfig{}, - BeaconConfig: globalBeaconConfig, + BeaconConfig: GlobalBeaconConfig, ForkDigest: [4]byte{1, 2, 3, 4}, DialTimeout: 60 * time.Second, Devp2pHost: "127.0.0.1", diff --git a/eth/peer_dialer.go b/eth/peer_dialer.go index 02efa19..e8b42f6 100644 --- a/eth/peer_dialer.go +++ b/eth/peer_dialer.go @@ -5,7 +5,7 @@ import ( "log/slog" "time" - "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/network" "github.com/thejerf/suture/v4" "github.com/probe-lab/hermes/host" @@ -17,7 +17,7 @@ import ( // to establish a connection. type PeerDialer struct { host *host.Host - peerChan <-chan peer.AddrInfo + peerChan <-chan *DiscoveredPeer maxPeers int } @@ -30,6 +30,7 @@ func (p *PeerDialer) Serve(ctx context.Context) error { for { // if we're at capacity, don't look for more peers if len(p.host.Network().Peers()) >= p.maxPeers { + // TODO: add check to see if we need to rotate any of the peers select { case <-ctx.Done(): return nil @@ -40,27 +41,41 @@ func (p *PeerDialer) Serve(ctx context.Context) error { } var ( - more bool - addrInfo peer.AddrInfo + more bool + newPeer *DiscoveredPeer ) select { case <-ctx.Done(): return nil - case addrInfo, more = <-p.peerChan: + case newPeer, more = <-p.peerChan: if !more { return nil } } // don't connect with ourselves - if addrInfo.ID == p.host.ID() { + if newPeer.AddrInfo.ID == p.host.ID() { continue } - // finally, start the connection establishment. - // The success case is handled in net_notifiee.go. - timeoutCtx, cancel := context.WithTimeout(ctx, 2*time.Second) - _ = p.host.Connect(timeoutCtx, addrInfo) // ignore error, this happens all the time - cancel() + // check if we are already connected to the peer + pConnect := p.host.Network().Connectedness(newPeer.AddrInfo.ID) + switch pConnect { + case network.NotConnected: + // TODO: Good to have: + // filter to only peers that support attestation networks that we want + // - if we are not subscribed to subnets, connect any node + + // finally, start the connection establishment. + // The success case is handled in net_notifiee.go. + timeoutCtx, cancel := context.WithTimeout(ctx, 2*time.Second) + _ = p.host.Connect(timeoutCtx, newPeer.AddrInfo) // ignore error, this happens all the time + cancel() + + case network.Connected: + continue // the peer is already connected + default: + continue + } } } diff --git a/eth/reqresp.go b/eth/reqresp.go index 5dddb11..2ff6bec 100644 --- a/eth/reqresp.go +++ b/eth/reqresp.go @@ -28,7 +28,6 @@ import ( "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/protocol" - "github.com/prysmaticlabs/go-bitfield" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/metric" @@ -44,6 +43,9 @@ type ReqRespConfig struct { Encoder encoder.NetworkEncoding DataStream hermeshost.DataStream + AttestationSubnetConfig *SubnetConfig + SyncSubnetConfig *SubnetConfig + ReadTimeout time.Duration WriteTimeout time.Duration @@ -81,14 +83,14 @@ func NewReqResp(h host.Host, cfg *ReqRespConfig) (*ReqResp, error) { md := &pb.MetaDataV1{ SeqNumber: 0, - Attnets: bitfield.NewBitvector64(), - Syncnets: bitfield.Bitvector4{byte(0x00)}, + Attnets: BitArrayFromAttestationSubnets(cfg.AttestationSubnetConfig.Subnets), + Syncnets: BitArrayFromSyncSubnets(cfg.SyncSubnetConfig.Subnets), } - // fake to support all attnets - for i := uint64(0); i < md.Attnets.Len(); i++ { - md.Attnets.SetBitAt(i, true) - } + slog.Info("Composed local MetaData", + "attnets", md.Attnets, + "syncnets", md.Syncnets, + ) p := &ReqResp{ host: h, @@ -481,6 +483,10 @@ func (r *ReqResp) metadataV1Handler(ctx context.Context, stream network.Stream) "Attnets": hex.EncodeToString(metaData.Attnets.Bytes()), } + slog.Info( + "metadata response", + "attnets", metaData.Attnets, + ) return traceData, stream.Close() } @@ -502,7 +508,11 @@ func (r *ReqResp) metadataV2Handler(ctx context.Context, stream network.Stream) "Attnets": hex.EncodeToString(metaData.Attnets.Bytes()), "Syncnets": hex.EncodeToString(metaData.Syncnets.Bytes()), } - + slog.Info( + "metadata response", + "attnets", metaData.Attnets, + "synccommittees", metaData.Syncnets, + ) return traceData, stream.Close() } diff --git a/eth/subnets.go b/eth/subnets.go index 5291c66..9bbce6f 100644 --- a/eth/subnets.go +++ b/eth/subnets.go @@ -7,6 +7,7 @@ import ( "time" "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p" + "github.com/prysmaticlabs/go-bitfield" ) // SubnetSelectionType defines how subnets are selected for any topic @@ -43,13 +44,13 @@ type SubnetConfig struct { func HasSubnets(topic string) (subnets uint64, hasSubnets bool) { switch topic { case p2p.GossipAttestationMessage: - return globalBeaconConfig.AttestationSubnetCount, true + return GlobalBeaconConfig.AttestationSubnetCount, true case p2p.GossipSyncCommitteeMessage: - return globalBeaconConfig.SyncCommitteeSubnetCount, true + return GlobalBeaconConfig.SyncCommitteeSubnetCount, true case p2p.GossipBlobSidecarMessage: - return globalBeaconConfig.BlobsidecarSubnetCount, true + return GlobalBeaconConfig.BlobsidecarSubnetCountElectra, true default: return uint64(0), false @@ -101,7 +102,7 @@ func (s *SubnetConfig) Validate(topic string, subnetCount uint64) error { return nil } -// GetSubscribedSubnets returns the subnet IDs to subscribe to for a given topic. +// GetSubscribedSubnets computes, stores and returns the subnet IDs to subscribe to for a given topic. // It handles the selection logic based on the subnet configuration. // // The function implements the following selection strategies: @@ -116,17 +117,22 @@ func GetSubscribedSubnets(config *SubnetConfig, totalSubnets uint64) []uint64 { // If no config, subscribe to all subnets by default. return getAllSubnets(totalSubnets) } + if len(config.Subnets) > 0 { + // if the subnets are alread pre-computed, just return them + return config.Subnets + } switch config.Type { case SubnetStatic: - return config.Subnets + // pass case SubnetRandom: - return getRandomSubnets(totalSubnets, config.Count) + config.Subnets = getRandomSubnets(totalSubnets, config.Count) case SubnetStaticRange: - return getSubnetRange(config.Start, config.End) + config.Subnets = getSubnetRange(config.Start, config.End) default: // SubnetAll or unrecognized type. - return getAllSubnets(totalSubnets) + config.Subnets = getAllSubnets(totalSubnets) } + return config.Subnets } // getRandomSubnets creates a slice of random subnet IDs. @@ -193,3 +199,21 @@ func getSubnetRange(start, end uint64) []uint64 { return subnets } + +// BitArrayFromAttestationSubnets returns the bitVector representation of the subscribed attestation subnets +func BitArrayFromAttestationSubnets(subnets []uint64) bitfield.Bitvector64 { + bitV := bitfield.NewBitvector64() + for _, subnet := range subnets { + bitV.SetBitAt(subnet, true) + } + return bitV +} + +// BitArrayFromSyncSubnets returns the bitVector representation of the subscribed sync subnets +func BitArrayFromSyncSubnets(subnets []uint64) bitfield.Bitvector4 { + bitV := bitfield.NewBitvector4() + for _, subnet := range subnets { + bitV.SetBitAt(subnet, true) + } + return bitV +} diff --git a/eth/subnets_integration_test.go b/eth/subnets_integration_test.go index f3fbc40..e262df5 100644 --- a/eth/subnets_integration_test.go +++ b/eth/subnets_integration_test.go @@ -31,7 +31,7 @@ func TestSubnetIntegration(t *testing.T) { // Count attestation subnet topics attSubnetCount := 0 for _, topic := range topics { - for subnet := uint64(0); subnet < globalBeaconConfig.AttestationSubnetCount; subnet++ { + for subnet := uint64(0); subnet < GlobalBeaconConfig.AttestationSubnetCount; subnet++ { if topic == formatSubnetTopic(attTopicFormat, subnet, ssz) { attSubnetCount++ break @@ -40,7 +40,7 @@ func TestSubnetIntegration(t *testing.T) { } // Should have all attestation subnets by default - assert.Equal(t, int(globalBeaconConfig.AttestationSubnetCount), attSubnetCount) + assert.Equal(t, int(GlobalBeaconConfig.AttestationSubnetCount), attSubnetCount) }) // Test with specific subnet configs @@ -88,7 +88,7 @@ func TestSubnetIntegration(t *testing.T) { // Count sync committee topics syncSubnetCount := 0 for _, topic := range topics { - for subnet := uint64(0); subnet < globalBeaconConfig.SyncCommitteeSubnetCount; subnet++ { + for subnet := uint64(0); subnet < GlobalBeaconConfig.SyncCommitteeSubnetCount; subnet++ { if topic == formatSubnetTopic(syncTopicFormat, subnet, ssz) { syncSubnetCount++ break diff --git a/eth/subnets_test.go b/eth/subnets_test.go index 151abe1..be42726 100644 --- a/eth/subnets_test.go +++ b/eth/subnets_test.go @@ -10,9 +10,6 @@ import ( ) func TestHasSubnets(t *testing.T) { - // Setup global beacon config for tests. - globalBeaconConfig = defaultTestBeaconConfig() - tests := []struct { name string topic string @@ -22,19 +19,19 @@ func TestHasSubnets(t *testing.T) { { name: "attestation topic", topic: p2p.GossipAttestationMessage, - wantSubnets: globalBeaconConfig.AttestationSubnetCount, + wantSubnets: GlobalBeaconConfig.AttestationSubnetCount, wantHasSubnet: true, }, { name: "sync committee topic", topic: p2p.GossipSyncCommitteeMessage, - wantSubnets: globalBeaconConfig.SyncCommitteeSubnetCount, + wantSubnets: GlobalBeaconConfig.SyncCommitteeSubnetCount, wantHasSubnet: true, }, { name: "blob sidecar topic", topic: p2p.GossipBlobSidecarMessage, - wantSubnets: globalBeaconConfig.BlobsidecarSubnetCount, + wantSubnets: GlobalBeaconConfig.BlobsidecarSubnetCountElectra, wantHasSubnet: true, }, { @@ -54,13 +51,15 @@ func TestHasSubnets(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { subnets, hasSubnets := HasSubnets(tt.topic) - assert.Equal(t, tt.wantSubnets, subnets) assert.Equal(t, tt.wantHasSubnet, hasSubnets) + assert.Equal(t, tt.wantSubnets, subnets) }) } } func TestSubnetConfig_Validate(t *testing.T) { + // Setup global beacon config for tests. + GlobalBeaconConfig = defaultTestBeaconConfig() const totalSubnets = 64 tests := []struct { @@ -181,6 +180,9 @@ func TestSubnetConfig_Validate(t *testing.T) { } func TestGetSubscribedSubnets(t *testing.T) { + // Setup global beacon config for tests. + GlobalBeaconConfig = defaultTestBeaconConfig() + const totalSubnets = 64 tests := []struct { @@ -267,6 +269,9 @@ func TestGetSubscribedSubnets(t *testing.T) { } func TestGetRandomSubnets(t *testing.T) { + // Setup global beacon config for tests. + GlobalBeaconConfig = defaultTestBeaconConfig() + tests := []struct { name string totalSubnets uint64 @@ -391,8 +396,9 @@ func TestGetSubnetRange(t *testing.T) { // Helper function to create a default test beacon config func defaultTestBeaconConfig() *params.BeaconChainConfig { return ¶ms.BeaconChainConfig{ - AttestationSubnetCount: 64, - SyncCommitteeSubnetCount: 4, - BlobsidecarSubnetCount: 6, + AttestationSubnetCount: 64, + SyncCommitteeSubnetCount: 4, + BlobsidecarSubnetCount: 6, + BlobsidecarSubnetCountElectra: 9, } } diff --git a/eth/topic_score_params.go b/eth/topic_score_params.go index 658d305..4660070 100644 --- a/eth/topic_score_params.go +++ b/eth/topic_score_params.go @@ -80,7 +80,7 @@ func topicToScoreParamsMapper(topic string, activeValidators uint64) *pubsub.Top // defaultBlockTopicParams returns the Block-topic specific parameters that need to be given to the topic subscriber func defaultBlockTopicParams() *pubsub.TopicScoreParams { decayEpoch := time.Duration(5) - blocksPerEpoch := uint64(globalBeaconConfig.SlotsPerEpoch) + blocksPerEpoch := uint64(GlobalBeaconConfig.SlotsPerEpoch) meshWeight := -0.717 return &pubsub.TopicScoreParams{ TopicWeight: beaconBlockWeight, @@ -143,7 +143,7 @@ func defaultAggregateTopicParams(activeValidators uint64) *pubsub.TopicScorePara func defaultSyncContributionTopicParams() *pubsub.TopicScoreParams { // Determine the expected message rate for the particular gossip topic. - aggPerSlot := globalBeaconConfig.SyncCommitteeSubnetCount * globalBeaconConfig.TargetAggregatorsPerSyncSubcommittee + aggPerSlot := GlobalBeaconConfig.SyncCommitteeSubnetCount * GlobalBeaconConfig.TargetAggregatorsPerSyncSubcommittee firstMessageCap, err := decayLimit(scoreDecay(1*oneEpochDuration()), float64(aggPerSlot*2/gossipSubD)) if err != nil { slog.Warn("skipping initializing topic scoring", tele.LogAttrError(err)) @@ -179,7 +179,7 @@ func defaultSyncContributionTopicParams() *pubsub.TopicScoreParams { } func defaultAggregateSubnetTopicParams(activeValidators uint64) *pubsub.TopicScoreParams { - subnetCount := globalBeaconConfig.AttestationSubnetCount + subnetCount := GlobalBeaconConfig.AttestationSubnetCount // Get weight for each specific subnet. topicWeight := attestationTotalWeight / float64(subnetCount) subnetWeight := activeValidators / subnetCount @@ -188,13 +188,13 @@ func defaultAggregateSubnetTopicParams(activeValidators uint64) *pubsub.TopicSco return nil } // Determine the amount of validators expected in a subnet in a single slot. - numPerSlot := time.Duration(subnetWeight / uint64(globalBeaconConfig.SlotsPerEpoch)) + numPerSlot := time.Duration(subnetWeight / uint64(GlobalBeaconConfig.SlotsPerEpoch)) if numPerSlot == 0 { slog.Warn("numPerSlot is 0, skipping initializing topic scoring") return nil } comsPerSlot := committeeCountPerSlot(activeValidators) - exceedsThreshold := comsPerSlot >= 2*subnetCount/uint64(globalBeaconConfig.SlotsPerEpoch) + exceedsThreshold := comsPerSlot >= 2*subnetCount/uint64(GlobalBeaconConfig.SlotsPerEpoch) firstDecay := time.Duration(1) meshDecay := time.Duration(4) if exceedsThreshold { @@ -243,10 +243,10 @@ func defaultAggregateSubnetTopicParams(activeValidators uint64) *pubsub.TopicSco } func defaultSyncSubnetTopicParams(activeValidators uint64) *pubsub.TopicScoreParams { - subnetCount := globalBeaconConfig.SyncCommitteeSubnetCount + subnetCount := GlobalBeaconConfig.SyncCommitteeSubnetCount // Get weight for each specific subnet. topicWeight := syncCommitteesTotalWeight / float64(subnetCount) - syncComSize := globalBeaconConfig.SyncCommitteeSize + syncComSize := GlobalBeaconConfig.SyncCommitteeSize // Set the max as the sync committee size if activeValidators > syncComSize { activeValidators = syncComSize @@ -391,11 +391,11 @@ func defaultBlsToExecutionChangeTopicParams() *pubsub.TopicScoreParams { // utility functions func oneSlotDuration() time.Duration { - return time.Duration(globalBeaconConfig.SecondsPerSlot) * time.Second + return time.Duration(GlobalBeaconConfig.SecondsPerSlot) * time.Second } func oneEpochDuration() time.Duration { - return time.Duration(globalBeaconConfig.SlotsPerEpoch) * oneSlotDuration() + return time.Duration(GlobalBeaconConfig.SlotsPerEpoch) * oneSlotDuration() } // determines the decay rate from the provided time period till @@ -450,7 +450,7 @@ func maxScore() float64 { // Uses a very rough gauge for total aggregator size per slot. func aggregatorsPerSlot(activeValidators uint64) uint64 { comms := committeeCountPerSlot(activeValidators) - totalAggs := comms * globalBeaconConfig.TargetAggregatorsPerCommittee + totalAggs := comms * GlobalBeaconConfig.TargetAggregatorsPerCommittee return totalAggs } @@ -462,9 +462,9 @@ func committeeCountPerSlot(activeValidators uint64) uint64 { } func slotCommitteeCount(activeValidatorCount uint64) uint64 { - committeesPerSlot := activeValidatorCount / globalBeaconConfig.SecondsPerSlot / globalBeaconConfig.TargetCommitteeSize - if committeesPerSlot > globalBeaconConfig.MaxCommitteesPerSlot { - return globalBeaconConfig.MaxCommitteesPerSlot + committeesPerSlot := activeValidatorCount / GlobalBeaconConfig.SecondsPerSlot / GlobalBeaconConfig.TargetCommitteeSize + if committeesPerSlot > GlobalBeaconConfig.MaxCommitteesPerSlot { + return GlobalBeaconConfig.MaxCommitteesPerSlot } if committeesPerSlot == 0 { return 1 diff --git a/go.mod b/go.mod index 4fe908b..2852686 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,6 @@ require ( github.com/prometheus/client_golang v1.22.0 github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516 github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 - github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.10.0 github.com/thejerf/suture/v4 v4.0.6 github.com/urfave/cli/v2 v2.27.5 @@ -208,12 +207,12 @@ require ( github.com/pion/dtls/v2 v2.2.12 // indirect github.com/pion/dtls/v3 v3.0.6 // indirect github.com/pion/ice/v4 v4.0.10 // indirect - github.com/pion/interceptor v0.1.37 // indirect + github.com/pion/interceptor v0.1.39 // indirect github.com/pion/logging v0.2.3 // indirect github.com/pion/mdns/v2 v2.0.7 // indirect github.com/pion/randutil v0.1.0 // indirect github.com/pion/rtcp v1.2.15 // indirect - github.com/pion/rtp v1.8.15 // indirect + github.com/pion/rtp v1.8.21 // indirect github.com/pion/sctp v1.8.39 // indirect github.com/pion/sdp/v3 v3.0.11 // indirect github.com/pion/srtp/v3 v3.0.4 // indirect @@ -242,6 +241,7 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/progressbar/v3 v3.17.1 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/supranational/blst v0.3.14 // indirect diff --git a/go.sum b/go.sum index 0824f53..8db5930 100644 --- a/go.sum +++ b/go.sum @@ -255,8 +255,6 @@ github.com/filecoin-project/go-clock v0.1.0/go.mod h1:4uB/O4PvOjlx1VCMdZ9MyDZXRm github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= github.com/filecoin-project/go-crypto v0.1.0 h1:Pob2MphoipMbe/ksxZOMcQvmBHAd3sI/WEqcbpIsGI0= github.com/filecoin-project/go-crypto v0.1.0/go.mod h1:K9UFXvvoyAVvB+0Le7oGlKiT9mgA5FHOJdYQXEE8IhI= -github.com/filecoin-project/go-f3 v0.8.3 h1:0ToWoqJDsunr+Jf945Upvk6rdXn8It5B5LcyiY1Ry1k= -github.com/filecoin-project/go-f3 v0.8.3/go.mod h1:KWksfw7CabMuL4ple/J52gK4soYBpTsL6i5WAgtJDqw= github.com/filecoin-project/go-f3 v0.8.4 h1:qbdsiMYPWkM2zR/8oFDl4VvHm2YTF7xnr5m/smYKanA= github.com/filecoin-project/go-f3 v0.8.4/go.mod h1:k23EMAx090NIWKlAYuO4TfjmfQTlIovaQ0nns960s9M= github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM= @@ -321,8 +319,6 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -675,8 +671,6 @@ github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCv github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= -github.com/libp2p/go-libp2p-pubsub v0.13.1 h1:tV3ttzzZSCk0EtEXnxVmWIXgjVxXx+20Jwjbs/Ctzjo= -github.com/libp2p/go-libp2p-pubsub v0.13.1/go.mod h1:MKPU5vMI8RRFyTP0HfdsF9cLmL1nHAeJm44AxJGJx44= github.com/libp2p/go-libp2p-pubsub v0.14.0 h1:+YxFHOdrk45szLb8G/fVsWwg4pdx0nVUXoZdLvYw2VY= github.com/libp2p/go-libp2p-pubsub v0.14.0/go.mod h1:MKPU5vMI8RRFyTP0HfdsF9cLmL1nHAeJm44AxJGJx44= github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= @@ -811,8 +805,6 @@ github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lg github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.15.0 h1:zB/HeaI/apcZiTDwhY5YqMvNVl/oQYvs3XySU+qeAVo= -github.com/multiformats/go-multiaddr v0.15.0/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0= github.com/multiformats/go-multiaddr v0.16.0 h1:oGWEVKioVQcdIOBlYM8BH1rZDWOGJSqr9/BKl6zQ4qc= github.com/multiformats/go-multiaddr v0.16.0/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0= github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= @@ -827,8 +819,6 @@ github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/g github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= -github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= -github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= github.com/multiformats/go-multicodec v0.9.1 h1:x/Fuxr7ZuR4jJV4Os5g444F7xC4XmyUaT/FWtE+9Zjo= github.com/multiformats/go-multicodec v0.9.1/go.mod h1:LLWNMtyV5ithSBUo3vFIMaeDy+h3EbkMTek1m+Fybbo= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= @@ -840,8 +830,6 @@ github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUj github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= -github.com/multiformats/go-multistream v0.6.0 h1:ZaHKbsL404720283o4c/IHQXiS6gb8qAN5EIJ4PN5EA= -github.com/multiformats/go-multistream v0.6.0/go.mod h1:MOyoG5otO24cHIg8kf9QW2/NozURlkP/rvi2FQJyCPg= github.com/multiformats/go-multistream v0.6.1 h1:4aoX5v6T+yWmc2raBHsTvzmFhOI8WVOer28DeBBEYdQ= github.com/multiformats/go-multistream v0.6.1/go.mod h1:ksQf6kqHAb6zIsyw7Zm+gAuVo57Qbq84E27YlYqavqw= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= @@ -923,8 +911,8 @@ github.com/pion/dtls/v3 v3.0.6 h1:7Hkd8WhAJNbRgq9RgdNh1aaWlZlGpYTzdqjy9x9sK2E= github.com/pion/dtls/v3 v3.0.6/go.mod h1:iJxNQ3Uhn1NZWOMWlLxEEHAN5yX7GyPvvKw04v9bzYU= github.com/pion/ice/v4 v4.0.10 h1:P59w1iauC/wPk9PdY8Vjl4fOFL5B+USq1+xbDcN6gT4= github.com/pion/ice/v4 v4.0.10/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= -github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI= -github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y= +github.com/pion/interceptor v0.1.39 h1:Y6k0bN9Y3Lg/Wb21JBWp480tohtns8ybJ037AGr9UuA= +github.com/pion/interceptor v0.1.39/go.mod h1:Z6kqH7M/FYirg3frjGJ21VLSRJGBXB/KqaTIrdqnOic= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI= github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90= @@ -934,8 +922,8 @@ github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= -github.com/pion/rtp v1.8.15 h1:MuhuGn1cxpVCPLNY1lI7F1tQ8Spntpgf12ob+pOYT8s= -github.com/pion/rtp v1.8.15/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk= +github.com/pion/rtp v1.8.21 h1:3yrOwmZFyUpcIosNcWRpQaU+UXIJ6yxLuJ8Bx0mw37Y= +github.com/pion/rtp v1.8.21/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk= github.com/pion/sctp v1.8.39 h1:PJma40vRHa3UTO3C4MyeJDQ+KIobVYRZQZ0Nt7SjQnE= github.com/pion/sctp v1.8.39/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= github.com/pion/sdp/v3 v3.0.11 h1:VhgVSopdsBKwhCFoyyPmT1fKMeV9nLMrEKxNOdy3IVI= @@ -1223,8 +1211,6 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I= -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60= @@ -1235,16 +1221,12 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 h1:BEj3S go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0/go.mod h1:9cKLGBDzI/F3NoHLQGm4ZrYdIHsvGt6ej6hUowxY0J4= go.opentelemetry.io/otel/exporters/prometheus v0.55.0 h1:sSPw658Lk2NWAv74lkD3B/RSDb+xRFx46GjkrL3VUZo= go.opentelemetry.io/otel/exporters/prometheus v0.55.0/go.mod h1:nC00vyCmQixoeaxF6KNyP42II/RHa9UdruK02qBmHvI= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= go.opentelemetry.io/otel/sdk/metric v1.33.0 h1:Gs5VK9/WUJhNXZgn8MR6ITatvAmKeIuCtNbsP3JkNqU= go.opentelemetry.io/otel/sdk/metric v1.33.0/go.mod h1:dL5ykHZmm1B1nVRk9dDjChwDmt81MjVp3gLkQRwKf/Q= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= @@ -1300,13 +1282,9 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= -golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4= golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1322,8 +1300,6 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1362,8 +1338,6 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1383,8 +1357,6 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1461,8 +1433,6 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1491,8 +1461,6 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= -golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/host/meter_tracer.go b/host/meter_tracer.go index b608f15..b66b7be 100644 --- a/host/meter_tracer.go +++ b/host/meter_tracer.go @@ -226,10 +226,45 @@ func (m *meterTracer) setMetricFromRPC(act action, subCtr metric.Int64Counter, p subCtr.Add(ctx, int64(len(rpc.Subscriptions))) if rpc.Control != nil { - ctrlCtr.Add(ctx, int64(len(rpc.Control.Graft)), metric.WithAttributes(attribute.String("control_message", "graft"))) - ctrlCtr.Add(ctx, int64(len(rpc.Control.Prune)), metric.WithAttributes(attribute.String("control_message", "prune"))) - ctrlCtr.Add(ctx, int64(len(rpc.Control.Ihave)), metric.WithAttributes(attribute.String("control_message", "ihave"))) - ctrlCtr.Add(ctx, int64(len(rpc.Control.Iwant)), metric.WithAttributes(attribute.String("control_message", "iwant"))) + for _, g := range rpc.Control.Graft { + ctrlCtr.Add( + ctx, int64(1), + metric.WithAttributes( + attribute.String("control_message", "graft"), + attribute.String("topic", g.GetTopicID()), + ), + ) + } + for _, p := range rpc.Control.Prune { + ctrlCtr.Add( + ctx, int64(1), + metric.WithAttributes( + attribute.String("control_message", "prune"), + attribute.String("topic", p.GetTopicID()), + ), + ) + } + for _, ihave := range rpc.Control.Ihave { + ctrlCtr.Add( + ctx, int64(len(ihave.GetMessageIDs())), + metric.WithAttributes( + attribute.String("control_message", "ihave"), + attribute.String("topic", ihave.GetTopicID()), + ), + ) + } + for _, iwant := range rpc.Control.Iwant { + ctrlCtr.Add( + ctx, int64(len(iwant.GetMessageIDs())), + metric.WithAttributes(attribute.String("control_message", "iwant")), + ) + } + for _, idontwant := range rpc.Control.Idontwant { + ctrlCtr.Add( + ctx, int64(len(idontwant.GetMessageIDs())), + metric.WithAttributes(attribute.String("control_message", "idontwant")), + ) + } } for _, msg := range rpc.Publish { // For incoming messages from pubsub, we do not record metrics for them as these values From 8cc2967e655c821d57dfd3075dea0c5c4ba7e329 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Mon, 14 Jul 2025 13:06:07 +0200 Subject: [PATCH 55/65] add optimism support --- cmd/hermes/cmd.go | 1 + cmd/hermes/cmd_op.go | 179 +++++++++++++++ eth/node.go | 4 +- go.mod | 3 +- op/discovery.go | 317 ++++++++++++++++++++++++++ op/node.go | 361 +++++++++++++++++++++++++++++ op/node_config.go | 314 +++++++++++++++++++++++++ op/p2p/id.go | 134 +++++++++++ op/p2p/peer_params.go | 86 +++++++ op/p2p/ssz.go | 515 ++++++++++++++++++++++++++++++++++++++++++ op/p2p/types.go | 280 +++++++++++++++++++++++ op/peer_dialer.go | 65 ++++++ op/pubsub.go | 154 +++++++++++++ 13 files changed, 2410 insertions(+), 3 deletions(-) create mode 100644 cmd/hermes/cmd_op.go create mode 100644 op/discovery.go create mode 100644 op/node.go create mode 100644 op/node_config.go create mode 100644 op/p2p/id.go create mode 100644 op/p2p/peer_params.go create mode 100644 op/p2p/ssz.go create mode 100644 op/p2p/types.go create mode 100644 op/peer_dialer.go create mode 100644 op/pubsub.go diff --git a/cmd/hermes/cmd.go b/cmd/hermes/cmd.go index 670bf34..0448fe5 100644 --- a/cmd/hermes/cmd.go +++ b/cmd/hermes/cmd.go @@ -100,6 +100,7 @@ var app = &cli.App{ Commands: []*cli.Command{ cmdEth, cmdFil, + cmdOp, cmdBenchmark, }, After: rootAfter, diff --git a/cmd/hermes/cmd_op.go b/cmd/hermes/cmd_op.go new file mode 100644 index 0000000..c6fad6d --- /dev/null +++ b/cmd/hermes/cmd_op.go @@ -0,0 +1,179 @@ +package main + +import ( + "fmt" + "log/slog" + "time" + + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/urfave/cli/v2" + "go.opentelemetry.io/otel" + + "github.com/probe-lab/hermes/host" + "github.com/probe-lab/hermes/op" +) + +var opConfig = &struct { + PrivateKeyStr string + Devp2pHost string + Devp2pPort int + Libp2pHost string + Libp2pPort int + Libp2pPeerscoreSnapshotFreq time.Duration + ChainID int + DialTimeout time.Duration + Bootstrappers *cli.StringSlice +}{ + PrivateKeyStr: "", // unset means it'll be generated + Devp2pHost: "127.0.0.1", + Devp2pPort: 0, + Libp2pHost: "127.0.0.1", + Libp2pPort: 0, + Libp2pPeerscoreSnapshotFreq: 15 * time.Second, + ChainID: 10, + DialTimeout: 5 * time.Second, + Bootstrappers: cli.NewStringSlice(), +} + +var cmdOp = &cli.Command{ + Name: "op", + Aliases: []string{"optimism"}, + Usage: "Listen to gossipsub topics of any OPStack-based network", + Flags: cmdOpFlags, + Action: cmdOpAction, +} + +var cmdOpFlags = []cli.Flag{ + &cli.StringFlag{ + Name: "key", + Aliases: []string{"k"}, + EnvVars: []string{"HERMES_OP_KEY"}, + Usage: "The private key for the hermes libp2p/ethereum node in hex format.", + Value: opConfig.PrivateKeyStr, + Destination: &opConfig.PrivateKeyStr, + Action: validateKeyFlag, + }, + &cli.DurationFlag{ + Name: "dial.timeout", + EnvVars: []string{"HERMES_OP_DIAL_TIMEOUT"}, + Usage: "The request timeout when contacting other network participants", + Value: opConfig.DialTimeout, + Destination: &opConfig.DialTimeout, + }, + &cli.StringFlag{ + Name: "libp2p.host", + EnvVars: []string{"HERMES_OP_LIBP2P_HOST"}, + Usage: "Which network interface should libp2p bind to.", + Value: opConfig.Libp2pHost, + Destination: &opConfig.Libp2pHost, + }, + &cli.IntFlag{ + Name: "libp2p.port", + EnvVars: []string{"HERMES_OP_LIBP2P_PORT"}, + Usage: "On which port should libp2p listen", + Value: opConfig.Libp2pPort, + Destination: &opConfig.Libp2pPort, + DefaultText: "random", + }, + &cli.IntFlag{ + Name: "chain.id", + EnvVars: []string{"HERMES_OP_CHAIN_ID"}, + Usage: "Which network hermes should connect to", + Value: opConfig.ChainID, + Destination: &opConfig.ChainID, + }, + &cli.DurationFlag{ + Name: "libp2p.peerscore.snapshot.frequency", + EnvVars: []string{"HERMES_OP_LIBP2P_PEERSCORE_SNAPSHOT_FREQUENCY"}, + Usage: "Frequency at which GossipSub peerscores will be accessed (in seconds)", + Value: opConfig.Libp2pPeerscoreSnapshotFreq, + Destination: &opConfig.Libp2pPeerscoreSnapshotFreq, + DefaultText: "random", + }, + &cli.StringSliceFlag{ + Name: "bootstrappers", + EnvVars: []string{"HERMES_OP_BOOTSTRAPPERS"}, + Usage: "List of bootstrappers to connect to", + Value: opConfig.Bootstrappers, + Destination: opConfig.Bootstrappers, + DefaultText: "eth mainnet", + }, +} + +func cmdOpAction(c *cli.Context) error { + slog.Info("Starting Hermes for Optimism...") + defer slog.Info("Stopped Hermes for Optimism.") + + // Print hermes configuration for debugging purposes + printFilConfig() + + bootstrapperCfg := opConfig.Bootstrappers.Value() + if len(bootstrapperCfg) == 0 { + bootstrapperCfg = []string{ + // Teku team's bootnodes + "enr:-Iu4QLm7bZGdAt9NSeJG0cEnJohWcQTQaI9wFLu3Q7eHIDfrI4cwtzvEW3F3VbG9XdFXlrHyFGeXPn9snTCQJ9bnMRABgmlkgnY0gmlwhAOTJQCJc2VjcDI1NmsxoQIZdZD6tDYpkpEfVo5bgiU8MGRjhcOmHGD2nErK0UKRrIN0Y3CCIyiDdWRwgiMo", + "enr:-Iu4QEDJ4Wa_UQNbK8Ay1hFEkXvd8psolVK6OhfTL9irqz3nbXxxWyKwEplPfkju4zduVQj6mMhUCm9R2Lc4YM5jPcIBgmlkgnY0gmlwhANrfESJc2VjcDI1NmsxoQJCYz2-nsqFpeEj6eov9HSi9QssIVIVNr0I89J1vXM9foN0Y3CCIyiDdWRwgiMo", + // Prylab team's bootnodes + "enr:-Ku4QImhMc1z8yCiNJ1TyUxdcfNucje3BGwEHzodEZUan8PherEo4sF7pPHPSIB1NNuSg5fZy7qFsjmUKs2ea1Whi0EBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQOVphkDqal4QzPMksc5wnpuC3gvSC8AfbFOnZY_On34wIN1ZHCCIyg", + "enr:-Ku4QP2xDnEtUXIjzJ_DhlCRN9SN99RYQPJL92TMlSv7U5C1YnYLjwOQHgZIUXw6c-BvRg2Yc2QsZxxoS_pPRVe0yK8Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQMeFF5GrS7UZpAH2Ly84aLK-TyvH-dRo0JM1i8yygH50YN1ZHCCJxA", + "enr:-Ku4QPp9z1W4tAO8Ber_NQierYaOStqhDqQdOPY3bB3jDgkjcbk6YrEnVYIiCBbTxuar3CzS528d2iE7TdJsrL-dEKoBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQMw5fqqkw2hHC4F5HZZDPsNmPdB1Gi8JPQK7pRc9XHh-oN1ZHCCKvg", + // Lighthouse team's bootnodes + "enr:-Le4QPUXJS2BTORXxyx2Ia-9ae4YqA_JWX3ssj4E_J-3z1A-HmFGrU8BpvpqhNabayXeOZ2Nq_sbeDgtzMJpLLnXFgAChGV0aDKQtTA_KgEAAAAAIgEAAAAAAIJpZIJ2NIJpcISsaa0Zg2lwNpAkAIkHAAAAAPA8kv_-awoTiXNlY3AyNTZrMaEDHAD2JKYevx89W0CcFJFiskdcEzkH_Wdv9iW42qLK79ODdWRwgiMohHVkcDaCI4I", + "enr:-Le4QLHZDSvkLfqgEo8IWGG96h6mxwe_PsggC20CL3neLBjfXLGAQFOPSltZ7oP6ol54OvaNqO02Rnvb8YmDR274uq8ChGV0aDKQtTA_KgEAAAAAIgEAAAAAAIJpZIJ2NIJpcISLosQxg2lwNpAqAX4AAAAAAPA8kv_-ax65iXNlY3AyNTZrMaEDBJj7_dLFACaxBfaI8KZTh_SSJUjhyAyfshimvSqo22WDdWRwgiMohHVkcDaCI4I", + "enr:-Le4QH6LQrusDbAHPjU_HcKOuMeXfdEB5NJyXgHWFadfHgiySqeDyusQMvfphdYWOzuSZO9Uq2AMRJR5O4ip7OvVma8BhGV0aDKQtTA_KgEAAAAAIgEAAAAAAIJpZIJ2NIJpcISLY9ncg2lwNpAkAh8AgQIBAAAAAAAAAAmXiXNlY3AyNTZrMaECDYCZTZEksF-kmgPholqgVt8IXr-8L7Nu7YrZ7HUpgxmDdWRwgiMohHVkcDaCI4I", + "enr:-Le4QIqLuWybHNONr933Lk0dcMmAB5WgvGKRyDihy1wHDIVlNuuztX62W51voT4I8qD34GcTEOTmag1bcdZ_8aaT4NUBhGV0aDKQtTA_KgEAAAAAIgEAAAAAAIJpZIJ2NIJpcISLY04ng2lwNpAkAh8AgAIBAAAAAAAAAA-fiXNlY3AyNTZrMaEDscnRV6n1m-D9ID5UsURk0jsoKNXt1TIrj8uKOGW6iluDdWRwgiMohHVkcDaCI4I", + // EF bootnodes + "enr:-Ku4QHqVeJ8PPICcWk1vSn_XcSkjOkNiTg6Fmii5j6vUQgvzMc9L1goFnLKgXqBJspJjIsB91LTOleFmyWWrFVATGngBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhAMRHkWJc2VjcDI1NmsxoQKLVXFOhp2uX6jeT0DvvDpPcU8FWMjQdR4wMuORMhpX24N1ZHCCIyg", + "enr:-Ku4QG-2_Md3sZIAUebGYT6g0SMskIml77l6yR-M_JXc-UdNHCmHQeOiMLbylPejyJsdAPsTHJyjJB2sYGDLe0dn8uYBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhBLY-NyJc2VjcDI1NmsxoQORcM6e19T1T9gi7jxEZjk_sjVLGFscUNqAY9obgZaxbIN1ZHCCIyg", + "enr:-Ku4QPn5eVhcoF1opaFEvg1b6JNFD2rqVkHQ8HApOKK61OIcIXD127bKWgAtbwI7pnxx6cDyk_nI88TrZKQaGMZj0q0Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhDayLMaJc2VjcDI1NmsxoQK2sBOLGcUb4AwuYzFuAVCaNHA-dy24UuEKkeFNgCVCsIN1ZHCCIyg", + "enr:-Ku4QEWzdnVtXc2Q0ZVigfCGggOVB2Vc1ZCPEc6j21NIFLODSJbvNaef1g4PxhPwl_3kax86YPheFUSLXPRs98vvYsoBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhDZBrP2Jc2VjcDI1NmsxoQM6jr8Rb1ktLEsVcKAPa08wCsKUmvoQ8khiOl_SLozf9IN1ZHCCIyg", + // Nimbus team's bootnodes + "enr:-LK4QA8FfhaAjlb_BXsXxSfiysR7R52Nhi9JBt4F8SPssu8hdE1BXQQEtVDC3qStCW60LSO7hEsVHv5zm8_6Vnjhcn0Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhAN4aBKJc2VjcDI1NmsxoQJerDhsJ-KxZ8sHySMOCmTO6sHM3iCFQ6VMvLTe948MyYN0Y3CCI4yDdWRwgiOM", + "enr:-LK4QKWrXTpV9T78hNG6s8AM6IO4XH9kFT91uZtFg1GcsJ6dKovDOr1jtAAFPnS2lvNltkOGA9k29BUN7lFh_sjuc9QBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhANAdd-Jc2VjcDI1NmsxoQLQa6ai7y9PMN5hpLe5HmiJSlYzMuzP7ZhwRiwHvqNXdoN0Y3CCI4yDdWRwgiOM", + // Lodestar team's bootnodes + "enr:-IS4QPi-onjNsT5xAIAenhCGTDl4z-4UOR25Uq-3TmG4V3kwB9ljLTb_Kp1wdjHNj-H8VVLRBSSWVZo3GUe3z6k0E-IBgmlkgnY0gmlwhKB3_qGJc2VjcDI1NmsxoQMvAfgB4cJXvvXeM6WbCG86CstbSxbQBSGx31FAwVtOTYN1ZHCCIyg", + "enr:-KG4QCb8NC3gEM3I0okStV5BPX7Bg6ZXTYCzzbYyEXUPGcZtHmvQtiJH4C4F2jG7azTcb9pN3JlgpfxAnRVFzJ3-LykBgmlkgnY0gmlwhFPlR9KDaXA2kP6AAAAAAAAAAlBW__4my5iJc2VjcDI1NmsxoQLdUv9Eo9sxCt0tc_CheLOWnX59yHJtkBSOL7kpxdJ6GYN1ZHCCIyiEdWRwNoIjKA", + } + } + + bootstrappers := make([]*enode.Node, len(bootstrapperCfg)) + for i, enrStr := range bootstrapperCfg { + bootnode, err := enode.Parse(enode.ValidSchemes, enrStr) + if err != nil { + return fmt.Errorf("not a valid enr string %q: %w", enrStr, err) + } + bootstrappers[i] = bootnode + } + + blockTopics := make([]string, 4) + for version := 0; version < 4; version++ { + blockTopics[version] = fmt.Sprintf("/optimism/%d/%d/blocks", opConfig.ChainID, version) + } + + cfg := &op.NodeConfig{ + PrivateKeyStr: opConfig.PrivateKeyStr, + ChainID: opConfig.ChainID, + BlockTopics: blockTopics, + DialTimeout: opConfig.DialTimeout, + Devp2pHost: opConfig.Devp2pHost, + Devp2pPort: opConfig.Devp2pPort, + Libp2pHost: opConfig.Libp2pHost, + Libp2pPort: opConfig.Libp2pPort, + Libp2pPeerscoreSnapshotFreq: opConfig.Libp2pPeerscoreSnapshotFreq, + Bootstrappers: bootstrappers, + DataStreamType: host.DataStreamtypeFromStr(rootConfig.DataStreamType), + AWSConfig: rootConfig.awsConfig, + S3Config: rootConfig.s3Config, + KinesisRegion: rootConfig.KinesisRegion, + KinesisStream: rootConfig.KinesisStream, + Tracer: otel.GetTracerProvider().Tracer("hermes"), + Meter: otel.GetMeterProvider().Meter("hermes"), + } + + n, err := op.NewNode(cfg) + if err != nil { + return fmt.Errorf("new node: %w", err) + } + + return n.Start(c.Context) +} diff --git a/eth/node.go b/eth/node.go index 0d40bd7..c6c7e48 100644 --- a/eth/node.go +++ b/eth/node.go @@ -496,12 +496,12 @@ func (n *Node) Start(ctx context.Context) error { // start the peer dialers, that consume the discovered peers from // the discovery service up until MaxPeers. for i := 0; i < n.cfg.DialConcurrency; i++ { - cs := &PeerDialer{ + pd := &PeerDialer{ host: n.host, peerChan: n.disc.out, maxPeers: n.cfg.MaxPeers, } - n.sup.Add(cs) + n.sup.Add(pd) } // start public listen address watcher to keep our ENR up to date diff --git a/go.mod b/go.mod index 2852686..2669fdd 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/ferranbt/fastssz v0.1.4 github.com/filecoin-project/go-f3 v0.8.4 github.com/filecoin-project/lotus v1.32.2 + github.com/golang/snappy v0.0.5-0.20231225225746-43d5d4cd4e0e github.com/google/uuid v1.6.0 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/iand/pontium v0.3.15 @@ -122,10 +123,10 @@ require ( github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/golang/snappy v0.0.5-0.20231225225746-43d5d4cd4e0e // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/gopacket v1.1.19 // indirect diff --git a/op/discovery.go b/op/discovery.go new file mode 100644 index 0000000..e2b55f0 --- /dev/null +++ b/op/discovery.go @@ -0,0 +1,317 @@ +package op + +import ( + "bytes" + "context" + "crypto/ecdsa" + "crypto/elliptic" + "encoding/binary" + "fmt" + "io" + "log/slog" + "net" + + "github.com/ethereum/go-ethereum/crypto/secp256k1" + elog "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" + "github.com/ethereum/go-ethereum/rlp" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + ma "github.com/multiformats/go-multiaddr" + "github.com/thejerf/suture/v4" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/trace" + + "github.com/probe-lab/hermes/tele" +) + +type DiscoveryConfig struct { + ChainID uint64 + Addr string + UDPPort int + TCPPort int + Seeds []*enode.Node + Tracer trace.Tracer + Meter metric.Meter +} + +// Discovery is a suture service that periodically queries the discv5 DHT +// for random peers and publishes the discovered peers on the `out` channel. +// Users of this Discovery service are required to read from the channel. +// Otherwise, the discovery will block forever. +type Discovery struct { + cfg *DiscoveryConfig + pk *ecdsa.PrivateKey + node *enode.LocalNode + out chan peer.AddrInfo + + // Metrics + MeterDiscoveredPeers metric.Int64Counter +} + +var _ suture.Service = (*Discovery)(nil) + +func NewDiscovery(privKey *ecdsa.PrivateKey, cfg *DiscoveryConfig) (*Discovery, error) { + slog.Info("Initialize Discovery service") + + db, err := enode.OpenDB("") // in memory db + if err != nil { + return nil, fmt.Errorf("could not open node's peer database: %w", err) + } + + ip := net.ParseIP(cfg.Addr) + + localNode := enode.NewLocalNode(db, privKey) + + opstackENREntry := &OpStackENRData{ + chainID: cfg.ChainID, + version: 0, + } + + localNode.Set(enr.IP(ip.String())) + localNode.Set(enr.UDP(cfg.UDPPort)) + localNode.Set(enr.TCP(cfg.TCPPort)) + localNode.Set(opstackENREntry) + localNode.SetFallbackIP(ip) + localNode.SetFallbackUDP(cfg.TCPPort) + + slog.Info("Initialized new enode", + "id", localNode.ID().String(), + "ip", localNode.Node().IP().String(), + "tcp", localNode.Node().TCP(), + "udp", localNode.Node().UDP(), + ) + + d := &Discovery{ + cfg: cfg, + pk: privKey, + node: localNode, + out: make(chan peer.AddrInfo), + } + + d.MeterDiscoveredPeers, err = cfg.Meter.Int64Counter("discovered_peers", metric.WithDescription("Total number of discovered peers")) + if err != nil { + return nil, fmt.Errorf("discovered_peers counter: %w", err) + } + + return d, nil +} + +func (d *Discovery) Serve(ctx context.Context) (err error) { + slog.Info("Starting discv5 Discovery Service") + defer slog.Info("Stopped disv5 Discovery Service") + defer func() { err = terminateSupervisorTreeOnErr(err) }() + + ip := net.ParseIP(d.cfg.Addr) + + var bindIP net.IP + var networkVersion string + switch { + case ip == nil: + return fmt.Errorf("invalid IP address provided: %s", d.cfg.Addr) + case ip.To4() != nil: + bindIP = net.IPv4zero + networkVersion = "udp4" + case ip.To16() != nil: + bindIP = net.IPv6zero + networkVersion = "udp6" + default: + return fmt.Errorf("invalid IP address provided: %s", d.cfg.Addr) + } + + udpAddr := &net.UDPAddr{ + IP: bindIP, + Port: d.cfg.UDPPort, + } + + conn, err := net.ListenUDP(networkVersion, udpAddr) + if err != nil { + return fmt.Errorf("failed to listen on %s:%d: %w", bindIP, d.cfg.UDPPort, err) + } + defer logDeferErr(conn.Close, "failed to close discovery UDP connection") + logger := elog.New() + elog.SetDefault(logger) + cfg := discover.Config{ + PrivateKey: d.pk, + Bootnodes: d.cfg.Seeds, + Unhandled: nil, // Not used in dv5 + Log: logger, + ValidSchemes: enode.ValidSchemes, + } + + listener, err := discover.ListenV5(conn, d.node, cfg) + if err != nil { + return fmt.Errorf("failed to start discv5 listener: %w", err) + } + defer listener.Close() + + iterator := enode.Filter(listener.RandomNodes(), func(node *enode.Node) bool { + var dat OpStackENRData + if err := node.Load(&dat); err != nil { + return false + } + // check chain ID matches + if d.cfg.ChainID != dat.chainID { + return false + } + + if dat.version != 0 { + return false + } + + return true + }) + + go func() { + <-ctx.Done() + iterator.Close() + }() + + slog.Info("Looking for discv5 peers...") + defer iterator.Close() + defer close(d.out) + for { + + // check if the context is already cancelled + select { + case <-ctx.Done(): + return nil + default: + // pass + } + + // let's see if we have another peer to process + exists := iterator.Next() + if !exists { + return + } + + slog.Info("New peer discovered") + + // yes, we do + node := iterator.Node() + + // Skip peer if it is only privately reachable + if node.IP().IsPrivate() { + continue + } + + // construct the data structure that libp2p can make sense of + pi, err := NewDiscoveredPeer(node) + if err != nil { + slog.Warn("Could not convert discovered node to peer info", tele.LogAttrError(err)) + continue + } + + // Update metrics + d.MeterDiscoveredPeers.Add(ctx, 1) + + select { + case d.out <- pi.AddrInfo: + case <-ctx.Done(): + return nil + } + } +} + +type DiscoveredPeer struct { + AddrInfo peer.AddrInfo + ENR *enode.Node +} + +func NewDiscoveredPeer(node *enode.Node) (*DiscoveredPeer, error) { + pubKey := node.Pubkey() + if pubKey == nil { + return nil, fmt.Errorf("no public key") + } + + pubBytes := elliptic.Marshal(secp256k1.S256(), pubKey.X, pubKey.Y) //lint:ignore SA1019 couldn't figure out the alternative + secpKey, err := crypto.UnmarshalSecp256k1PublicKey(pubBytes) + if err != nil { + return nil, fmt.Errorf("unmarshal secp256k1 public key: %w", err) + } + + peerID, err := peer.IDFromPublicKey(secpKey) + if err != nil { + return nil, fmt.Errorf("peer ID from public key: %w", err) + } + + var ipScheme string + if p4 := node.IP().To4(); len(p4) == net.IPv4len { + ipScheme = "ip4" + } else { + ipScheme = "ip6" + } + + maddrs := []ma.Multiaddr{} + if node.UDP() != 0 { + maddrStr := fmt.Sprintf("/%s/%s/udp/%d", ipScheme, node.IP(), node.UDP()) + maddr, err := ma.NewMultiaddr(maddrStr) + if err != nil { + return nil, fmt.Errorf("parse multiaddress %s: %w", maddrStr, err) + } + maddrs = append(maddrs, maddr) + } + + if node.TCP() != 0 { + maddrStr := fmt.Sprintf("/%s/%s/tcp/%d", ipScheme, node.IP(), node.TCP()) + maddr, err := ma.NewMultiaddr(maddrStr) + if err != nil { + return nil, fmt.Errorf("parse multiaddress %s: %w", maddrStr, err) + } + maddrs = append(maddrs, maddr) + } + + pi := &DiscoveredPeer{ + AddrInfo: peer.AddrInfo{ + ID: peerID, + Addrs: maddrs, + }, + ENR: node, + } + + return pi, nil +} + +type OpStackENRData struct { + chainID uint64 + version uint64 +} + +var _ enr.Entry = (*OpStackENRData)(nil) + +func (o *OpStackENRData) ENRKey() string { + return "opstack" +} + +func (o *OpStackENRData) EncodeRLP(w io.Writer) error { + out := make([]byte, 2*binary.MaxVarintLen64) + offset := binary.PutUvarint(out, o.chainID) + offset += binary.PutUvarint(out[offset:], o.version) + out = out[:offset] + // encode as byte-string + return rlp.Encode(w, out) +} + +func (o *OpStackENRData) DecodeRLP(s *rlp.Stream) error { + b, err := s.Bytes() + if err != nil { + return fmt.Errorf("failed to decode outer ENR entry: %w", err) + } + // We don't check the byte length: the below readers are limited, and the ENR itself has size limits. + // Future "opstack" entries may contain additional data, and will be tagged with a newer version etc. + r := bytes.NewReader(b) + chainID, err := binary.ReadUvarint(r) + if err != nil { + return fmt.Errorf("failed to read chain ID var int: %w", err) + } + version, err := binary.ReadUvarint(r) + if err != nil { + return fmt.Errorf("failed to read version var int: %w", err) + } + o.chainID = chainID + o.version = version + return nil +} diff --git a/op/node.go b/op/node.go new file mode 100644 index 0000000..7a8e909 --- /dev/null +++ b/op/node.go @@ -0,0 +1,361 @@ +package op + +import ( + "context" + "errors" + "fmt" + "log/slog" + "sort" + "strconv" + "time" + + "github.com/aws/aws-sdk-go-v2/service/kinesis" + gk "github.com/dennis-tra/go-kinesis" + ma "github.com/multiformats/go-multiaddr" + "github.com/thejerf/suture/v4" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" + + "github.com/probe-lab/hermes/host" + "github.com/probe-lab/hermes/tele" +) + +// Node is the main entry point to listening to the Ethereum GossipSub mesh. +type Node struct { + // The configuration that's passed in externally + cfg *NodeConfig + + // The libp2p host, however, this is a custom Hermes wrapper host. + host *host.Host + + // The data stream to which we transmit data + ds host.DataStream + + // The PubSub service that implements various gossipsub topics + pubSub *PubSub + + // The discovery service, periodically querying the discv5 DHT network + disc *Discovery + + // The suture supervisor that is the root of the service tree + sup *suture.Supervisor + + // Metrics + connCount metric.Int64ObservableGauge + connDurHist metric.Float64Histogram + connAge metric.Float64Histogram + connMedianAge metric.Float64ObservableGauge + + // eventCallbacks contains a list of callbacks that are executed when an event is received + eventCallbacks []func(ctx context.Context, event *host.TraceEvent) +} + +// NewNode initializes a new [Node] using the provided configuration. +// It first validates the node configuration. Then it initializes the libp2p +// host using the libp2p options from the given configuration object. Next, it +// initializes the Ethereum node by extracting the ECDSA private key, +// creating a new discovery service, creating a new ReqResp server, +// creating a new PubSub server, and creating a new Prysm client. +// Finally, it initializes the Hermes node by setting the configuration and +// dependencies. +func NewNode(cfg *NodeConfig) (*Node, error) { + if err := cfg.Validate(); err != nil { + return nil, fmt.Errorf("node config validation failed: %w", err) + } + + var ds host.DataStream + switch cfg.DataStreamType { + case host.DataStreamTypeLogger: + ds = new(host.TraceLogger) + + case host.DataStreamTypeKinesis: + droppedTraces, err := cfg.Meter.Int64Counter("dropped_traces") + if err != nil { + return nil, fmt.Errorf("new dropped_traces counter: %w", err) + } + + notifiee := &gk.NotifieeBundle{ + DroppedRecordF: func(ctx context.Context, record gk.Record) { + tevt, ok := record.(*host.TraceEvent) + if !ok { + droppedTraces.Add(ctx, 1, metric.WithAttributes(attribute.String("evt_type", "UNKNOWN"))) + } else { + droppedTraces.Add(ctx, 1, metric.WithAttributes(attribute.String("evt_type", tevt.Type))) + } + slog.Warn("Dropped record", "partition_key", record.PartitionKey(), "size", len(record.Data())) + }, + } + + pcfg := gk.DefaultProducerConfig() + pcfg.Log = slog.Default() + pcfg.Meter = cfg.Meter + pcfg.Notifiee = notifiee + pcfg.RetryLimit = 5 + + p, err := gk.NewProducer(kinesis.NewFromConfig(*cfg.AWSConfig), cfg.KinesisStream, pcfg) + if err != nil { + return nil, fmt.Errorf("new kinesis producer: %w", err) + } + + ds = host.NewKinesisDataStream(p) + + case host.DataStreamTypeCallback: + ds = host.NewCallbackDataStream() + + case host.DataStreamTypeS3: + // get the metrics tracer and meter from the root config + cfg.S3Config.Meter = cfg.Meter + var err error + ds, err = host.NewS3DataStream(*cfg.S3Config) + if err != nil { + return nil, fmt.Errorf("new s3 producer %w", err) + } + + case host.DataStreamTypeNoop: + ds = new(host.NoopDataStream) + + default: + return nil, fmt.Errorf("not recognised data-stream (%s)", cfg.DataStreamType) + } + + hostCfg := &host.Config{ + DataStream: ds, + PeerscoreSnapshotFreq: cfg.Libp2pPeerscoreSnapshotFreq, + Tracer: cfg.Tracer, + Meter: cfg.Meter, + } + + // initialize libp2p host + opts, err := cfg.libp2pOptions() + if err != nil { + return nil, fmt.Errorf("build libp2p options: %w", err) + } + + h, err := host.New(hostCfg, opts...) + if err != nil { + return nil, fmt.Errorf("new libp2p host: %w", err) + } + slog.Info("Initialized new libp2p Host", tele.LogAttrPeerID(h.ID()), "maddrs", h.Addrs()) + + privKey, err := cfg.ECDSAPrivateKey() + if err != nil { + return nil, fmt.Errorf("private key: %w", err) + } + + devp2pTCPport := cfg.Libp2pPort + if devp2pTCPport == 0 { + for _, addr := range h.Addrs() { + tcpPortStr, err := addr.ValueForProtocol(ma.P_TCP) + if err != nil { + continue + } + v, err := strconv.ParseUint(tcpPortStr, 10, 16) + if err != nil { + continue + } + devp2pTCPport = int(v) + break + } + } + + disc, err := NewDiscovery(privKey, &DiscoveryConfig{ + ChainID: uint64(cfg.ChainID), + Addr: cfg.Devp2pHost, + UDPPort: cfg.Devp2pPort, + TCPPort: devp2pTCPport, + Seeds: cfg.Bootstrappers, + Tracer: cfg.Tracer, + Meter: cfg.Meter, + }) + if err != nil { + return nil, fmt.Errorf("new discovery service: %w", err) + } + slog.Info("Initialized new devp2p Node", "enr", disc.node.Node().String()) + + // initialize the pubsub topic handlers + pubSubConfig := &PubSubConfig{ + ChainID: cfg.ChainID, + BlockTopics: cfg.BlockTopics, + DataStream: ds, + } + + pubSub, err := NewPubSub(h, pubSubConfig) + if err != nil { + return nil, fmt.Errorf("new PubSub service: %w", err) + } + + // finally, initialize hermes node + n := &Node{ + cfg: cfg, + host: h, + ds: ds, + pubSub: pubSub, + disc: disc, + sup: suture.NewSimple("fil"), + } + + if ds.Type() == host.DataStreamTypeCallback { + cbDs := ds.(*host.CallbackDataStream) + + cbDs.OnEvent(func(ctx context.Context, event *host.TraceEvent) { + for _, cb := range n.eventCallbacks { + cb(ctx, event) + } + }) + } + + if err := n.initMetrics(cfg); err != nil { + return nil, fmt.Errorf("new metrics: %w", err) + } + + return n, nil +} + +// initMetrics initializes various prometheus metrics and stores the meters +// on the [Node] object. +func (n *Node) initMetrics(cfg *NodeConfig) (err error) { + n.connDurHist, err = cfg.Meter.Float64Histogram( + "connection_duration_min", + metric.WithExplicitBucketBoundaries(0.5, 1, 5, 10, 50, 100, 500, 1000), + ) + if err != nil { + return fmt.Errorf("new connection_duration_min histogram: %w", err) + } + + n.connCount, err = cfg.Meter.Int64ObservableGauge("connection_count") + if err != nil { + return fmt.Errorf("new connection_count gauge: %w", err) + } + + _, err = cfg.Meter.RegisterCallback(func(ctx context.Context, obs metric.Observer) error { + obs.ObserveInt64(n.connCount, int64(len(n.host.Network().Peers()))) + return nil + }, n.connCount) + if err != nil { + return fmt.Errorf("register connection_count gauge callback: %w", err) + } + + n.connAge, err = cfg.Meter.Float64Histogram("conn_age", metric.WithDescription("Connection age after disconnect in seconds"), metric.WithUnit("s")) + if err != nil { + return fmt.Errorf("new conn_age histogram: %w", err) + } + + n.connMedianAge, err = cfg.Meter.Float64ObservableGauge("conn_median_age", metric.WithDescription("The median age of all currently active connections"), metric.WithUnit("s")) + if err != nil { + return fmt.Errorf("new conn_median_age gauge: %w", err) + } + _, err = cfg.Meter.RegisterCallback(func(ctx context.Context, obs metric.Observer) error { + // get a reference to all connections + conns := n.host.Network().Conns() + if len(conns) == 0 { + // don't measure anything if we have no active connection + return nil + } + + // calculate connection ages in seconds + ages := make([]float64, len(conns)) + for i, conn := range conns { + ages[i] = time.Since(conn.Stat().Opened).Seconds() + } + + // calculate median + sort.Float64s(ages) + + if len(ages)%2 == 0 { + lo, hi := ages[(len(ages)-1)/2], ages[len(ages)/2] + obs.ObserveFloat64(n.connMedianAge, (lo+hi)/2) + } else { + obs.ObserveFloat64(n.connMedianAge, ages[len(ages)/2]) + } + + return nil + }, n.connMedianAge) + if err != nil { + return fmt.Errorf("register conn_median_age gauge callback: %w", err) + } + + return nil +} + +// OnEvent registers a callback that is executed when an event is received. +func (n *Node) OnEvent(cb func(ctx context.Context, event *host.TraceEvent)) { + n.eventCallbacks = append(n.eventCallbacks, cb) +} + +// Start starts the listening process. +func (n *Node) Start(ctx context.Context) error { + defer logDeferErr(n.host.Close, "Failed closing libp2p host") + + dsCleanupFn, err := n.startDataStream(ctx) + if err != nil { + return fmt.Errorf("failed starting data stream producer: %w", err) + } + defer dsCleanupFn() + + // initialize GossipSub + n.pubSub.gs, err = n.host.InitGossipSub(ctx, n.cfg.pubsubOptions(n)...) + if err != nil { + return fmt.Errorf("init gossip sub: %w", err) + } + + // start the discovery service to find peers in the discv5 DHT + n.sup.Add(n.disc) + + // start the pubsub subscriptions and handlers + n.sup.Add(n.pubSub) + + // start the hermes host to trace gossipsub messages + n.sup.Add(n.host) + + // start the peer dialers, that consume the discovered peers from + // the discovery service up until MaxPeers. + for i := 0; i < 3; i++ { // TODO: parametrize + pd := &PeerDialer{ + host: n.host, + peerChan: n.disc.out, + maxPeers: 30, // TODO: parametrize + } + n.sup.Add(pd) + } + + // start all long-running services + return n.sup.Serve(ctx) +} + +// logDeferErr executes the given function and logs the given error message +// in case of an error. +func logDeferErr(fn func() error, onErrMsg string) { + if err := fn(); err != nil && !errors.Is(err, context.Canceled) { + slog.Warn(onErrMsg, tele.LogAttrError(err)) + } +} + +// terminateSupervisorTreeOnErr can be used like +// +// defer func() { err = terminateSupervisorTreeOnErr(err) }() +// +// to instruct the suture supervisor to terminate the supervisor tree if +// the surrounding function returns an error. +func terminateSupervisorTreeOnErr(err error) error { + if err != nil { + return fmt.Errorf("%s: %w", err, suture.ErrTerminateSupervisorTree) + } + return nil +} + +// startDataStream starts the data stream and implements a graceful shutdown +func (n *Node) startDataStream(ctx context.Context) (func(), error) { + backgroundCtx := context.Background() + + go func() { + if err := n.ds.Start(backgroundCtx); err != nil { + slog.Warn("Failed to start data stream", tele.LogAttrError(err)) + } + }() + + cleanupFn := func() { + n.ds.Stop(ctx) + } + + return cleanupFn, nil +} diff --git a/op/node_config.go b/op/node_config.go new file mode 100644 index 0000000..2717abd --- /dev/null +++ b/op/node_config.go @@ -0,0 +1,314 @@ +package op + +import ( + "crypto/ecdsa" + "crypto/rand" + "crypto/sha256" + "encoding/binary" + "encoding/hex" + "fmt" + "log/slog" + "math" + "sync" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/decred/dcrd/dcrec/secp256k1/v4" + gcrypto "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/golang/snappy" + "github.com/libp2p/go-libp2p" + pubsub "github.com/libp2p/go-libp2p-pubsub" + pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb" + "github.com/libp2p/go-libp2p/core/crypto" + rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/trace" + + "github.com/probe-lab/hermes/host" + "github.com/probe-lab/hermes/op/p2p" +) + +const ( + // maxGossipSize limits the total size of gossip RPC containers as well as decompressed individual messages. + maxGossipSize = 10 * (1 << 20) + // minGossipSize is used to make sure that there is at least some data to validate the signature against. + minGossipSize = 66 + maxOutboundQueue = 256 + maxValidateQueue = 256 + globalValidateThrottle = 512 + gossipHeartbeat = 500 * time.Millisecond + // seenMessagesTTL limits the duration that message IDs are remembered for gossip deduplication purposes + // 130 * gossipHeartbeat + seenMessagesTTL = 130 * gossipHeartbeat + DefaultMeshD = 8 // topic stable mesh target count + DefaultMeshDlo = 6 // topic stable mesh low watermark + DefaultMeshDhi = 12 // topic stable mesh high watermark + DefaultMeshDlazy = 6 // gossip target + // peerScoreInspectFrequency is the frequency at which peer scores are inspected + peerScoreInspectFrequency = 15 * time.Second +) + +// Message domains, the msg id function uncompresses to keep data monomorphic, +// but invalid compressed data will need a unique different id. + +var MessageDomainInvalidSnappy = [4]byte{0, 0, 0, 0} +var MessageDomainValidSnappy = [4]byte{1, 0, 0, 0} + +type NodeConfig struct { + // The private key for the libp2p host and local enode in hex format + PrivateKeyStr string + + ChainID int + BlockTopics []string + Bootstrappers []*enode.Node + + // The parsed private key as an unexported field. This is used to cache the + // parsing result, so that [PrivateKey] can be called multiple times without + // regenerating the key over and over again. + privateKey *crypto.Secp256k1PrivateKey + + // General timeout when communicating with other network participants + DialTimeout time.Duration + + // The address information of the local ethereuem [enode.Node]. + Devp2pHost string + Devp2pPort int + + // The address information of the local libp2p host + Libp2pHost string + Libp2pPort int + Libp2pPeerscoreSnapshotFreq time.Duration + + // Pause between two discovery lookups + LookupInterval time.Duration + + // The Data Stream configuration + DataStreamType host.DataStreamType + AWSConfig *aws.Config + S3Config *host.S3DSConfig + KinesisRegion string + KinesisStream string + + // Telemetry accessors + Tracer trace.Tracer + Meter metric.Meter +} + +// Validate validates the [NodeConfig] [Node] configuration. +func (n *NodeConfig) Validate() error { + if _, err := n.PrivateKey(); err != nil { + return err + } + + if n.DialTimeout <= 0 { + return fmt.Errorf("dial timeout must be positive") + } + + if n.Libp2pPort < 0 { + return fmt.Errorf("libp2p port must be greater than or equal to 0, got %d", n.Libp2pPort) + } + + if len(n.Bootstrappers) == 0 { + return fmt.Errorf("no valid bootstrapper multiaddresses provided, please check the --bootstrappers flag") + } + + // ensure that if the data stream is AWS, the parameters where given + if n.DataStreamType == host.DataStreamTypeKinesis { + if n.AWSConfig != nil { + if n.KinesisStream == "" { + return fmt.Errorf("kinesis is enabled but stream is not set") + } + + if n.KinesisRegion == "" { + return fmt.Errorf("kinesis is enabled but region is not set") + } + } + } + + if n.DataStreamType == host.DataStreamTypeS3 { + if n.S3Config != nil { + // we should have caught the error at the root_cmd, but still adding it here + if err := n.S3Config.CheckValidity(); err != nil { + return fmt.Errorf("s3 trace submission is enabled but no valid config was given %w", err) + } + } else { + return fmt.Errorf("s3 configuration is empty") + } + } + + if n.Tracer == nil { + return fmt.Errorf("tracer must not be nil") + } + + if n.Meter == nil { + return fmt.Errorf("meter must not be nil") + } + + return nil +} + +// PrivateKey returns a parsed Secp256k1 private key from the given +// PrivateKeyStr. If that's unset, a new one will be generated. In any case, +// the result will be cached, so that the private key won't be generated twice. +func (n *NodeConfig) PrivateKey() (*crypto.Secp256k1PrivateKey, error) { + if n.privateKey != nil { + return n.privateKey, nil + } + + var err error + var privBytes []byte + if n.PrivateKeyStr == "" { + slog.Debug("Generating new private key") + key, err := ecdsa.GenerateKey(gcrypto.S256(), rand.Reader) + if err != nil { + return nil, fmt.Errorf("failed to generate key: %w", err) + } + + privBytes = gcrypto.FromECDSA(key) + if len(privBytes) != secp256k1.PrivKeyBytesLen { + return nil, fmt.Errorf("expected secp256k1 data size to be %d", secp256k1.PrivKeyBytesLen) + } + } else { + privBytes, err = hex.DecodeString(n.PrivateKeyStr) + if err != nil { + return nil, fmt.Errorf("failed to decode private key: %w", err) + } + } + + n.privateKey = (*crypto.Secp256k1PrivateKey)(secp256k1.PrivKeyFromBytes(privBytes)) + + if n.PrivateKeyStr == "" { + n.PrivateKeyStr = hex.EncodeToString(privBytes) + } + + return n.privateKey, nil +} + +// ECDSAPrivateKey returns the ECDSA private key associated with the [NodeConfig]. +// It retrieves the private key using the PrivateKey method and then converts it +// to ECDSA format. If there is an error retrieving the private key or +// converting it to ECDSA format, an error is returned. +func (n *NodeConfig) ECDSAPrivateKey() (*ecdsa.PrivateKey, error) { + privKey, err := n.PrivateKey() + if err != nil { + return nil, fmt.Errorf("private key: %w", err) + } + data, err := privKey.Raw() + if err != nil { + return nil, fmt.Errorf("get raw bytes from private key: %w", err) + } + + return gcrypto.ToECDSA(data) +} + +// libp2pOptions returns the options to configure the libp2p node. It retrieves +// the private key, constructs the libp2p listen multiaddr based on the node +// configuration. The options include setting the identity with the private key, +// adding the listen address, setting the user agent to "hermes", +// using only the TCP transport, enabling the Mplex multiplexer explicitly (this +// is required by the specs). +func (n *NodeConfig) libp2pOptions() ([]libp2p.Option, error) { + privKey, err := n.PrivateKey() + if err != nil { + return nil, fmt.Errorf("get private key: %w", err) + } + + listenMaddr, err := host.MaddrFrom(n.Libp2pHost, uint(n.Libp2pPort)) + if err != nil { + return nil, fmt.Errorf("construct libp2p listen maddr: %w", err) + } + + str, err := rcmgr.NewStatsTraceReporter() + if err != nil { + return nil, err + } + + rmgr, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(rcmgr.DefaultLimits.AutoScale()), rcmgr.WithTraceReporter(str)) + if err != nil { + return nil, err + } + + opts := []libp2p.Option{ + libp2p.Identity(privKey), + libp2p.ListenAddrs(listenMaddr), + libp2p.UserAgent("hermes"), + libp2p.DisableRelay(), + libp2p.Ping(true), + libp2p.ResourceManager(rmgr), + libp2p.DisableMetrics(), + } + return opts, nil +} + +func (n *NodeConfig) pubsubOptions(subFilter pubsub.SubscriptionFilter) []pubsub.Option { + psOpts := []pubsub.Option{ + pubsub.WithMessageIdFn(MsgID), + pubsub.WithNoAuthor(), + pubsub.WithMessageSignaturePolicy(pubsub.StrictNoSign), + pubsub.WithValidateQueueSize(maxValidateQueue), + pubsub.WithPeerOutboundQueueSize(maxOutboundQueue), + pubsub.WithValidateThrottle(globalValidateThrottle), + pubsub.WithSeenMessagesTTL(seenMessagesTTL), + pubsub.WithPeerExchange(false), + pubsub.WithSubscriptionFilter(subFilter), + pubsub.WithPeerScore( + p2p.LightPeerScoreParams(n.BlockTopics, 2), + p2p.NewPeerScoreThresholds(), + ), + } + return psOpts +} + +// DecayToZero is the decay factor for a peer's score to zero. +const DecayToZero = 0.01 + +// ScoreDecay returns the decay factor for a given duration. +func ScoreDecay(duration time.Duration, slot time.Duration) float64 { + numOfTimes := duration / slot + return math.Pow(DecayToZero, 1/float64(numOfTimes)) +} + +var msgBufPool = sync.Pool{New: func() any { + // note: the topic validator concurrency is limited, so pool won't blow up, even with large pre-allocation. + x := make([]byte, 0, maxGossipSize) + return &x +}} + +func MsgID(pmsg *pubsubpb.Message) string { + valid := false + var data []byte + // If it's a valid compressed snappy data, then hash the uncompressed contents. + // The validator can throw away the message later when recognized as invalid, + // and the unique hash helps detect duplicates. + dLen, err := snappy.DecodedLen(pmsg.Data) + if err == nil && dLen <= maxGossipSize { + res := msgBufPool.Get().(*[]byte) + defer msgBufPool.Put(res) + if data, err = snappy.Decode((*res)[:cap(*res)], pmsg.Data); err == nil { + if cap(data) > cap(*res) { + // if we ended up growing the slice capacity, fine, keep the larger one. + *res = data[:cap(data)] + } + valid = true + } + } + if data == nil { + data = pmsg.Data + } + h := sha256.New() + if valid { + h.Write(MessageDomainValidSnappy[:]) + } else { + h.Write(MessageDomainInvalidSnappy[:]) + } + // The chain ID is part of the gossip topic, making the msg id unique + topic := pmsg.GetTopic() + var topicLen [8]byte + binary.LittleEndian.PutUint64(topicLen[:], uint64(len(topic))) + h.Write(topicLen[:]) + h.Write([]byte(topic)) + h.Write(data) + // the message ID is shortened to save space, a lot of these may be gossiped. + return string(h.Sum(nil)[:20]) +} diff --git a/op/p2p/id.go b/op/p2p/id.go new file mode 100644 index 0000000..73cb6ac --- /dev/null +++ b/op/p2p/id.go @@ -0,0 +1,134 @@ +package p2p + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +type BlockID struct { + Hash common.Hash `json:"hash"` + Number uint64 `json:"number"` +} + +func (id BlockID) String() string { + return fmt.Sprintf("%s:%d", id.Hash.String(), id.Number) +} + +// TerminalString implements log.TerminalStringer, formatting a string for console +// output during logging. +func (id BlockID) TerminalString() string { + return fmt.Sprintf("%s:%d", id.Hash.TerminalString(), id.Number) +} + +func ReceiptBlockID(r *types.Receipt) BlockID { + return BlockID{Number: r.BlockNumber.Uint64(), Hash: r.BlockHash} +} + +func HeaderBlockID(h *types.Header) BlockID { + return BlockID{Number: h.Number.Uint64(), Hash: h.Hash()} +} + +type L2BlockRef struct { + Hash common.Hash `json:"hash"` + Number uint64 `json:"number"` + ParentHash common.Hash `json:"parentHash"` + Time uint64 `json:"timestamp"` + L1Origin BlockID `json:"l1origin"` + SequenceNumber uint64 `json:"sequenceNumber"` // distance to first block of epoch +} + +func (id L2BlockRef) String() string { + return fmt.Sprintf("%s:%d", id.Hash.String(), id.Number) +} + +// TerminalString implements log.TerminalStringer, formatting a string for console +// output during logging. +func (id L2BlockRef) TerminalString() string { + return fmt.Sprintf("%s:%d", id.Hash.TerminalString(), id.Number) +} + +func (id L2BlockRef) BlockRef() BlockRef { + return BlockRef{ + Hash: id.Hash, + Number: id.Number, + ParentHash: id.ParentHash, + Time: id.Time, + } +} + +type L1BlockRef struct { + Hash common.Hash `json:"hash"` + Number uint64 `json:"number"` + ParentHash common.Hash `json:"parentHash"` + Time uint64 `json:"timestamp"` +} + +func (id L1BlockRef) String() string { + return fmt.Sprintf("%s:%d", id.Hash.String(), id.Number) +} + +// TerminalString implements log.TerminalStringer, formatting a string for console +// output during logging. +func (id L1BlockRef) TerminalString() string { + return fmt.Sprintf("%s:%d", id.Hash.TerminalString(), id.Number) +} + +func (id L1BlockRef) ID() BlockID { + return BlockID{ + Hash: id.Hash, + Number: id.Number, + } +} + +func (id L1BlockRef) ParentID() BlockID { + n := id.ID().Number + // Saturate at 0 with subtraction + if n > 0 { + n -= 1 + } + return BlockID{ + Hash: id.ParentHash, + Number: n, + } +} + +// BlockRef is a Block Ref independent of L1 or L2 +// Because L1BlockRefs are strict subsets of L2BlockRefs, BlockRef is a direct alias of L1BlockRef +type BlockRef = L1BlockRef + +func BlockRefFromHeader(h *types.Header) *BlockRef { + return &BlockRef{ + Hash: h.Hash(), + Number: h.Number.Uint64(), + ParentHash: h.ParentHash, + Time: h.Time, + } +} +func (id L2BlockRef) ID() BlockID { + return BlockID{ + Hash: id.Hash, + Number: id.Number, + } +} + +func (id L2BlockRef) ParentID() BlockID { + n := id.ID().Number + // Saturate at 0 with subtraction + if n > 0 { + n -= 1 + } + return BlockID{ + Hash: id.ParentHash, + Number: n, + } +} + +// IndexedBlobHash represents a blob hash that commits to a single blob confirmed in a block. The +// index helps us avoid unnecessary blob to blob hash conversions to find the right content in a +// sidecar. +type IndexedBlobHash struct { + Index uint64 // absolute index in the block, a.k.a. position in sidecar blobs array + Hash common.Hash // hash of the blob, used for consistency checks +} diff --git a/op/p2p/peer_params.go b/op/p2p/peer_params.go new file mode 100644 index 0000000..6fbbe09 --- /dev/null +++ b/op/p2p/peer_params.go @@ -0,0 +1,86 @@ +package p2p + +import ( + "math" + "time" + + pubsub "github.com/libp2p/go-libp2p-pubsub" + "github.com/libp2p/go-libp2p/core/peer" +) + +// DecayToZero is the decay factor for a peer's score to zero. +const DecayToZero = 0.01 + +// ScoreDecay returns the decay factor for a given duration. +func ScoreDecay(duration time.Duration, slot time.Duration) float64 { + numOfTimes := duration / slot + return math.Pow(DecayToZero, 1/float64(numOfTimes)) +} + +// LightPeerScoreParams is an instantiation of [pubsub.PeerScoreParams] with light penalties. +// See [PeerScoreParams] for detailed documentation. +// +// [PeerScoreParams]: https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.8.1#PeerScoreParams +func LightPeerScoreParams(blockTopics []string, blockTime uint64) *pubsub.PeerScoreParams { + slot := time.Duration(blockTime) * time.Second + if slot == 0 { + slot = 2 * time.Second + } + + topicParams := make(map[string]*pubsub.TopicScoreParams, 4) + for _, topicName := range blockTopics { + topicParams[topicName] = &pubsub.TopicScoreParams{ + TopicWeight: 0.1, + TimeInMeshWeight: 0.00027, // ~1/3600 + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 1, + FirstMessageDeliveriesWeight: 5, // max value is 500 + FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + FirstMessageDeliveriesCap: 100, + InvalidMessageDeliveriesWeight: -1000, + InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + } + } + + // We initialize an "epoch" as 6 blocks suggesting 6 blocks, + // each taking ~ 2 seconds, is 12 seconds + epoch := 6 * slot + tenEpochs := 10 * epoch + oneHundredEpochs := 100 * epoch + return &pubsub.PeerScoreParams{ + // We inentionally do not use any per-topic scoring, + // since it is expected for the network to migrate + // from older topics to newer ones over time and we don't + // want to penalize peers for not participating in the old topics. + // Therefore the Topics map is nil: + Topics: topicParams, + AppSpecificScore: func(p peer.ID) float64 { + return 0 + }, + AppSpecificWeight: 1, + IPColocationFactorWeight: -35, + IPColocationFactorThreshold: 10, + IPColocationFactorWhitelist: nil, + BehaviourPenaltyWeight: -16, + BehaviourPenaltyThreshold: 6, + BehaviourPenaltyDecay: ScoreDecay(tenEpochs, slot), + DecayInterval: slot, + DecayToZero: DecayToZero, + RetainScore: oneHundredEpochs, + } +} + +// NewPeerScoreThresholds returns a default [pubsub.PeerScoreThresholds]. +// See [PeerScoreThresholds] for detailed documentation. +// +// [PeerScoreThresholds]: https://pkg.go.dev/github.com/libp2p/go-libp2p-pubsub@v0.8.1#PeerScoreThresholds +func NewPeerScoreThresholds() *pubsub.PeerScoreThresholds { + return &pubsub.PeerScoreThresholds{ + SkipAtomicValidation: false, + GossipThreshold: -10, + PublishThreshold: -40, + GraylistThreshold: -40, + AcceptPXThreshold: 20, + OpportunisticGraftThreshold: 0.05, + } +} diff --git a/op/p2p/ssz.go b/op/p2p/ssz.go new file mode 100644 index 0000000..d06cba2 --- /dev/null +++ b/op/p2p/ssz.go @@ -0,0 +1,515 @@ +package p2p + +import ( + "encoding/binary" + "errors" + "fmt" + "io" + "math" + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +type BlockVersion int + +const ( // iota is reset to 0 + BlockV1 BlockVersion = iota + BlockV2 + BlockV3 + BlockV4 +) + +// ExecutionPayload and ExecutionPayloadEnvelope are the only SSZ types we have to marshal/unmarshal, +// so instead of importing a SSZ lib we implement the bare minimum. +// This is more efficient than RLP, and matches the L1 consensus-layer encoding of ExecutionPayload. + +var ( + // The payloads are small enough to read and write at once. + // But this happens often enough that we want to avoid re-allocating buffers for this. + payloadBufPool = sync.Pool{New: func() any { + x := make([]byte, 0, 100_000) + return &x + }} + + // ErrExtraDataTooLarge occurs when the ExecutionPayload's ExtraData field + // is too large to be properly represented in SSZ. + ErrExtraDataTooLarge = errors.New("extra data too large") + + ErrBadTransactionOffset = errors.New("transactions offset is smaller than extra data offset, aborting") + ErrBadWithdrawalsOffset = errors.New("withdrawals offset is smaller than transaction offset, aborting") + ErrBadExtraDataOffset = errors.New("unexpected extra data offset") + ErrScopeTooSmall = errors.New("scope too small to decode execution payload") + + ErrMissingData = errors.New("execution payload envelope is missing data") +) + +const ( + // All fields (4s are offsets to dynamic data) + blockV1FixedPart = 32 + 20 + 32 + 32 + 256 + 32 + 8 + 8 + 8 + 8 + 4 + 32 + 32 + 4 + + // V1 + Withdrawals offset + blockV2FixedPart = blockV1FixedPart + 4 + + // V2 + BlobGasUsed + ExcessBlobGas + blockV3FixedPart = blockV2FixedPart + 8 + 8 + + // V3 + WithdrawalsRoot + blockV4FixedPart = blockV3FixedPart + 32 + + withdrawalSize = 8 + 8 + 20 + 8 + + // MAX_TRANSACTIONS_PER_PAYLOAD in consensus spec + // https://github.com/ethereum/consensus-specs/blob/ef434e87165e9a4c82a99f54ffd4974ae113f732/specs/bellatrix/beacon-chain.md#execution + maxTransactionsPerPayload = 1 << 20 + + // MAX_WITHDRAWALS_PER_PAYLOAD in consensus spec + // https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#execution + maxWithdrawalsPerPayload = 1 << 4 +) + +func (v BlockVersion) HasBlobProperties() bool { + return v == BlockV3 || v == BlockV4 +} + +func (v BlockVersion) HasWithdrawals() bool { + return v == BlockV2 || v == BlockV3 || v == BlockV4 +} + +func (v BlockVersion) HasParentBeaconBlockRoot() bool { + return v == BlockV3 || v == BlockV4 +} + +func (v BlockVersion) HasWithdrawalsRoot() bool { + return v == BlockV4 +} + +func executionPayloadFixedPart(version BlockVersion) uint32 { + if version == BlockV4 { + return blockV4FixedPart + } else if version == BlockV3 { + return blockV3FixedPart + } else if version == BlockV2 { + return blockV2FixedPart + } else { + return blockV1FixedPart + } +} + +func (payload *ExecutionPayload) inferVersion() BlockVersion { + if payload.WithdrawalsRoot != nil && *payload.WithdrawalsRoot != types.EmptyWithdrawalsHash { + return BlockV4 + } else if payload.ExcessBlobGas != nil && payload.BlobGasUsed != nil { + return BlockV3 + } else if payload.Withdrawals != nil { + return BlockV2 + } else { + return BlockV1 + } +} + +func (payload *ExecutionPayload) SizeSSZ() (full uint32) { + return executionPayloadFixedPart(payload.inferVersion()) + uint32(len(payload.ExtraData)) + payload.transactionSize() + payload.withdrawalSize() +} + +func (payload *ExecutionPayload) withdrawalSize() uint32 { + if payload.Withdrawals == nil { + return 0 + } + + return uint32(len(*payload.Withdrawals) * withdrawalSize) +} + +func (payload *ExecutionPayload) transactionSize() uint32 { + // One offset to each transaction + result := uint32(len(payload.Transactions)) * 4 + // Each transaction + for _, tx := range payload.Transactions { + result += uint32(len(tx)) + } + return result +} + +// marshalBytes32LE returns the value of z as a 32-byte little-endian array. +func marshalBytes32LE(out []byte, z *Uint256Quantity) { + _ = out[31] // bounds check hint to compiler + binary.LittleEndian.PutUint64(out[0:8], z[0]) + binary.LittleEndian.PutUint64(out[8:16], z[1]) + binary.LittleEndian.PutUint64(out[16:24], z[2]) + binary.LittleEndian.PutUint64(out[24:32], z[3]) +} + +func unmarshalBytes32LE(in []byte, z *Uint256Quantity) { + _ = in[31] // bounds check hint to compiler + z[0] = binary.LittleEndian.Uint64(in[0:8]) + z[1] = binary.LittleEndian.Uint64(in[8:16]) + z[2] = binary.LittleEndian.Uint64(in[16:24]) + z[3] = binary.LittleEndian.Uint64(in[24:32]) +} + +// MarshalSSZ encodes the ExecutionPayload as SSZ type +func (payload *ExecutionPayload) MarshalSSZ(w io.Writer) (n int, err error) { + fixedSize := executionPayloadFixedPart(payload.inferVersion()) + transactionSize := payload.transactionSize() + + // Cast to uint32 to enable 32-bit MIPS support where math.MaxUint32-executionPayloadFixedPart is too big for int + // In that case, len(payload.ExtraData) can't be longer than an int so this is always false anyway. + extraDataSize := uint32(len(payload.ExtraData)) + if extraDataSize > math.MaxUint32-fixedSize { + return 0, ErrExtraDataTooLarge + } + + scope := payload.SizeSSZ() + + buf := *payloadBufPool.Get().(*[]byte) + if uint32(cap(buf)) < scope { + buf = make([]byte, scope) + } else { + buf = buf[:scope] + } + defer payloadBufPool.Put(&buf) + + offset := uint32(0) + copy(buf[offset:offset+32], payload.ParentHash[:]) + offset += 32 + copy(buf[offset:offset+20], payload.FeeRecipient[:]) + offset += 20 + copy(buf[offset:offset+32], payload.StateRoot[:]) + offset += 32 + copy(buf[offset:offset+32], payload.ReceiptsRoot[:]) + offset += 32 + copy(buf[offset:offset+256], payload.LogsBloom[:]) + offset += 256 + copy(buf[offset:offset+32], payload.PrevRandao[:]) + offset += 32 + binary.LittleEndian.PutUint64(buf[offset:offset+8], uint64(payload.BlockNumber)) + offset += 8 + binary.LittleEndian.PutUint64(buf[offset:offset+8], uint64(payload.GasLimit)) + offset += 8 + binary.LittleEndian.PutUint64(buf[offset:offset+8], uint64(payload.GasUsed)) + offset += 8 + binary.LittleEndian.PutUint64(buf[offset:offset+8], uint64(payload.Timestamp)) + offset += 8 + // offset to ExtraData + binary.LittleEndian.PutUint32(buf[offset:offset+4], fixedSize) + offset += 4 + marshalBytes32LE(buf[offset:offset+32], &payload.BaseFeePerGas) + offset += 32 + copy(buf[offset:offset+32], payload.BlockHash[:]) + offset += 32 + // offset to Transactions + binary.LittleEndian.PutUint32(buf[offset:offset+4], fixedSize+extraDataSize) + offset += 4 + + if payload.Withdrawals == nil && offset != fixedSize { + panic("transactions - fixed part size is inconsistent") + } + + if payload.Withdrawals != nil { + binary.LittleEndian.PutUint32(buf[offset:offset+4], fixedSize+extraDataSize+transactionSize) + offset += 4 + } + + payloadVersion := payload.inferVersion() + if payloadVersion.HasBlobProperties() { + if payload.BlobGasUsed == nil || payload.ExcessBlobGas == nil { + return 0, errors.New("cannot encode ecotone payload without dencun header attributes") + } + binary.LittleEndian.PutUint64(buf[offset:offset+8], uint64(*payload.BlobGasUsed)) + offset += 8 + binary.LittleEndian.PutUint64(buf[offset:offset+8], uint64(*payload.ExcessBlobGas)) + offset += 8 + } + + if payloadVersion.HasWithdrawalsRoot() { + if payload.WithdrawalsRoot == nil { + return 0, errors.New("cannot encode Isthmus payload without withdrawals root") + } + copy(buf[offset:offset+32], (*payload.WithdrawalsRoot)[:]) + offset += 32 + } + + if payload.Withdrawals != nil && offset != fixedSize { + panic("withdrawals - fixed part size is inconsistent") + } + + // dynamic value 1: ExtraData + copy(buf[offset:offset+extraDataSize], payload.ExtraData[:]) + offset += extraDataSize + // dynamic value 2: Transactions + marshalTransactions(buf[offset:offset+transactionSize], payload.Transactions) + offset += transactionSize + // dynamic value 3: Withdrawals + if payload.Withdrawals != nil { + marshalWithdrawals(buf[offset:], *payload.Withdrawals) + } + + return w.Write(buf) +} + +func marshalWithdrawals(out []byte, withdrawals types.Withdrawals) { + offset := uint32(0) + + for _, withdrawal := range withdrawals { + binary.LittleEndian.PutUint64(out[offset:offset+8], withdrawal.Index) + offset += 8 + binary.LittleEndian.PutUint64(out[offset:offset+8], withdrawal.Validator) + offset += 8 + copy(out[offset:offset+20], withdrawal.Address[:]) + offset += 20 + binary.LittleEndian.PutUint64(out[offset:offset+8], withdrawal.Amount) + offset += 8 + } +} + +func marshalTransactions(out []byte, txs []Data) { + offset := uint32(0) + txOffset := uint32(len(txs)) * 4 + for _, tx := range txs { + binary.LittleEndian.PutUint32(out[offset:offset+4], txOffset) + offset += 4 + nextTxOffset := txOffset + uint32(len(tx)) + copy(out[txOffset:nextTxOffset], tx) + txOffset = nextTxOffset + } +} + +// UnmarshalSSZ decodes the ExecutionPayload as SSZ type +func (payload *ExecutionPayload) UnmarshalSSZ(version BlockVersion, scope uint32, r io.Reader) error { + fixedSize := executionPayloadFixedPart(version) + + if scope < fixedSize { + return fmt.Errorf("scope too small to decode execution payload: %d, version is: %v", scope, version) + } + + buf := *payloadBufPool.Get().(*[]byte) + if uint32(cap(buf)) < scope { + buf = make([]byte, scope) + } else { + buf = buf[:scope] + } + defer payloadBufPool.Put(&buf) + + if _, err := io.ReadFull(r, buf); err != nil { + return fmt.Errorf("failed to read fixed-size part of ExecutionPayload: %w", err) + } + offset := uint32(0) + copy(payload.ParentHash[:], buf[offset:offset+32]) + offset += 32 + copy(payload.FeeRecipient[:], buf[offset:offset+20]) + offset += 20 + copy(payload.StateRoot[:], buf[offset:offset+32]) + offset += 32 + copy(payload.ReceiptsRoot[:], buf[offset:offset+32]) + offset += 32 + copy(payload.LogsBloom[:], buf[offset:offset+256]) + offset += 256 + copy(payload.PrevRandao[:], buf[offset:offset+32]) + offset += 32 + payload.BlockNumber = Uint64Quantity(binary.LittleEndian.Uint64(buf[offset : offset+8])) + offset += 8 + payload.GasLimit = Uint64Quantity(binary.LittleEndian.Uint64(buf[offset : offset+8])) + offset += 8 + payload.GasUsed = Uint64Quantity(binary.LittleEndian.Uint64(buf[offset : offset+8])) + offset += 8 + payload.Timestamp = Uint64Quantity(binary.LittleEndian.Uint64(buf[offset : offset+8])) + offset += 8 + extraDataOffset := binary.LittleEndian.Uint32(buf[offset : offset+4]) + if extraDataOffset != fixedSize { + return fmt.Errorf("%w: %d <> %d", ErrBadExtraDataOffset, extraDataOffset, fixedSize) + } + offset += 4 + unmarshalBytes32LE(buf[offset:offset+32], &payload.BaseFeePerGas) + offset += 32 + copy(payload.BlockHash[:], buf[offset:offset+32]) + offset += 32 + + transactionsOffset := binary.LittleEndian.Uint32(buf[offset : offset+4]) + if transactionsOffset < extraDataOffset { + return ErrBadTransactionOffset + } + offset += 4 + if version == BlockV1 && offset != fixedSize { + panic("fixed part size is inconsistent") + } + + withdrawalsOffset := scope + if version.HasWithdrawals() { + withdrawalsOffset = binary.LittleEndian.Uint32(buf[offset : offset+4]) + offset += 4 + + if withdrawalsOffset < transactionsOffset { + return ErrBadWithdrawalsOffset + } + if withdrawalsOffset > scope { + return fmt.Errorf("withdrawals offset is too large: %d", withdrawalsOffset) + } + } + + if version.HasBlobProperties() { + blobGasUsed := binary.LittleEndian.Uint64(buf[offset : offset+8]) + payload.BlobGasUsed = (*Uint64Quantity)(&blobGasUsed) + offset += 8 + excessBlobGas := binary.LittleEndian.Uint64(buf[offset : offset+8]) + payload.ExcessBlobGas = (*Uint64Quantity)(&excessBlobGas) + offset += 8 + } + + if version.HasWithdrawalsRoot() { + withdrawalsRoot := common.Hash{} + copy(withdrawalsRoot[:], buf[offset:offset+32]) + payload.WithdrawalsRoot = &withdrawalsRoot + offset += 32 + } + + _ = offset // for future extensions: we keep the offset accurate for extensions + + if transactionsOffset > extraDataOffset+32 || transactionsOffset > scope { + return fmt.Errorf("extra-data is too large: %d", transactionsOffset-extraDataOffset) + } + + extraDataSize := transactionsOffset - extraDataOffset + payload.ExtraData = make(BytesMax32, extraDataSize) + copy(payload.ExtraData, buf[extraDataOffset:transactionsOffset]) + + txs, err := unmarshalTransactions(buf[transactionsOffset:withdrawalsOffset]) + if err != nil { + return fmt.Errorf("failed to unmarshal transactions list: %w", err) + } + payload.Transactions = txs + + if version.HasWithdrawals() { + withdrawals, err := unmarshalWithdrawals(buf[withdrawalsOffset:]) + if err != nil { + return fmt.Errorf("failed to unmarshal withdrawals list: %w", err) + } + payload.Withdrawals = &withdrawals + } + + return nil +} + +func unmarshalWithdrawals(in []byte) (types.Withdrawals, error) { + result := types.Withdrawals{} // empty list by default, intentionally non-nil + + if len(in)%withdrawalSize != 0 { + return nil, errors.New("invalid withdrawals data") + } + + withdrawalCount := len(in) / withdrawalSize + + if withdrawalCount > maxWithdrawalsPerPayload { + return nil, fmt.Errorf("too many withdrawals: %d > %d", withdrawalCount, maxWithdrawalsPerPayload) + } + + offset := 0 + + for i := 0; i < withdrawalCount; i++ { + withdrawal := &types.Withdrawal{} + + withdrawal.Index = binary.LittleEndian.Uint64(in[offset : offset+8]) + offset += 8 + + withdrawal.Validator = binary.LittleEndian.Uint64(in[offset : offset+8]) + offset += 8 + + copy(withdrawal.Address[:], in[offset:offset+20]) + offset += 20 + + withdrawal.Amount = binary.LittleEndian.Uint64(in[offset : offset+8]) + offset += 8 + + result = append(result, withdrawal) + } + + return result, nil +} + +func unmarshalTransactions(in []byte) (txs []Data, err error) { + scope := uint32(len(in)) + if scope == 0 { // empty txs list + return make([]Data, 0), nil + } + if scope < 4 { + return nil, fmt.Errorf("not enough scope to read first tx offset: %d", scope) + } + offset := uint32(0) + firstTxOffset := binary.LittleEndian.Uint32(in[offset : offset+4]) + offset += 4 + if firstTxOffset%4 != 0 { + return nil, fmt.Errorf("invalid first tx offset: %d, not a multiple of offset size", firstTxOffset) + } + if firstTxOffset > scope { + return nil, fmt.Errorf("invalid first tx offset: %d, out of scope %d", firstTxOffset, scope) + } + txCount := firstTxOffset / 4 + if txCount == 0 && scope > 0 { + return nil, fmt.Errorf("invalid first tx offset: %d, no transactions in scope %d", firstTxOffset, scope) + } + if txCount > maxTransactionsPerPayload { + return nil, fmt.Errorf("too many transactions: %d > %d", txCount, maxTransactionsPerPayload) + } + txs = make([]Data, txCount) + currentTxOffset := firstTxOffset + for i := uint32(0); i < txCount; i++ { + nextTxOffset := scope + if i+1 < txCount { + nextTxOffset = binary.LittleEndian.Uint32(in[offset : offset+4]) + offset += 4 + } + if nextTxOffset < currentTxOffset || nextTxOffset > scope { + return nil, fmt.Errorf("tx %d has bad next offset: %d, current is %d, scope is %d", i, nextTxOffset, currentTxOffset, scope) + } + currentTxSize := nextTxOffset - currentTxOffset + txs[i] = make(Data, currentTxSize) + copy(txs[i], in[currentTxOffset:nextTxOffset]) + currentTxOffset = nextTxOffset + } + return txs, nil +} + +// UnmarshalSSZ decodes the ExecutionPayloadEnvelope as SSZ type +func (envelope *ExecutionPayloadEnvelope) UnmarshalSSZ(version BlockVersion, scope uint32, r io.Reader) error { + if scope < common.HashLength { + return fmt.Errorf("%w: %d", ErrScopeTooSmall, scope) + } + + data := make([]byte, common.HashLength) + n, err := r.Read(data) + if err != nil || n != common.HashLength { + return err + } + + envelope.ParentBeaconBlockRoot = &common.Hash{} + copy(envelope.ParentBeaconBlockRoot[:], data) + + var payload ExecutionPayload + err = payload.UnmarshalSSZ(version, scope-32, r) + if err != nil { + return err + } + + envelope.ExecutionPayload = &payload + return nil +} + +// MarshalSSZ encodes the ExecutionPayload as SSZ type +func (envelope *ExecutionPayloadEnvelope) MarshalSSZ(w io.Writer) (n int, err error) { + if envelope.ExecutionPayload == nil || envelope.ParentBeaconBlockRoot == nil { + return 0, ErrMissingData + } + + // write parent beacon block root + hashSize, err := w.Write(envelope.ParentBeaconBlockRoot[:]) + if err != nil || hashSize != common.HashLength { + return 0, errors.New("unable to write parent beacon block hash") + } + + payloadSize, err := envelope.ExecutionPayload.MarshalSSZ(w) + if err != nil { + return 0, err + } + + return hashSize + payloadSize, nil +} diff --git a/op/p2p/types.go b/op/p2p/types.go new file mode 100644 index 0000000..0bee80c --- /dev/null +++ b/op/p2p/types.go @@ -0,0 +1,280 @@ +package p2p + +import ( + "errors" + "fmt" + "github.com/ethereum/go-ethereum/beacon/engine" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "reflect" +) + +type ErrorCode int + +func (c ErrorCode) IsEngineError() bool { + return -38100 < c && c <= -38000 +} + +func (c ErrorCode) IsGenericRPCError() bool { + return -32700 < c && c <= -32600 +} + +// Engine error codes used to be -3200x, but were rebased to -3800x: +// https://github.com/ethereum/execution-apis/pull/214 +const ( + MethodNotFound ErrorCode = -32601 // RPC method not found or not available. + InvalidParams ErrorCode = -32602 + UnknownPayload ErrorCode = -38001 // Payload does not exist / is not available. + InvalidForkchoiceState ErrorCode = -38002 // Forkchoice state is invalid / inconsistent. + InvalidPayloadAttributes ErrorCode = -38003 // Payload attributes are invalid / inconsistent. + TooLargeEngineRequest ErrorCode = -38004 // Unused, here for completeness, only used by engine_getPayloadBodiesByHashV1 + UnsupportedFork ErrorCode = -38005 // Unused, see issue #11130. +) + +var ErrBedrockScalarPaddingNotEmpty = errors.New("version 0 scalar value has non-empty padding") + +// InputError can be used to create rpc.Error instances with a specific error code. +type InputError struct { + Inner error + Code ErrorCode +} + +func (ie InputError) Error() string { + return fmt.Sprintf("input error %d: %s", ie.Code, ie.Inner.Error()) +} + +// Makes InputError implement the rpc.Error interface +func (ie InputError) ErrorCode() int { + return int(ie.Code) +} + +func (ie InputError) Unwrap() error { + return ie.Inner +} + +// Is checks if the error is the given target type. +// Any type of InputError counts, regardless of code. +func (ie InputError) Is(target error) bool { + _, ok := target.(InputError) + return ok // we implement Unwrap, so we do not have to check the inner type now +} + +// Bytes65 is a 65-byte long byte string, and encoded with 0x-prefix in hex. +// This can be used to represent encoded secp256k ethereum signatures. +type Bytes65 [65]byte + +func (b *Bytes65) UnmarshalJSON(text []byte) error { + return hexutil.UnmarshalFixedJSON(reflect.TypeOf(b), text, b[:]) +} + +func (b *Bytes65) UnmarshalText(text []byte) error { + return hexutil.UnmarshalFixedText("Bytes65", text, b[:]) +} + +func (b Bytes65) MarshalText() ([]byte, error) { + return hexutil.Bytes(b[:]).MarshalText() +} + +func (b Bytes65) String() string { + return hexutil.Encode(b[:]) +} + +// TerminalString implements log.TerminalStringer, formatting a string for console +// output during logging. +func (b Bytes65) TerminalString() string { + return fmt.Sprintf("0x%x..%x", b[:3], b[65-3:]) +} + +type Bytes32 [32]byte + +func (b *Bytes32) UnmarshalJSON(text []byte) error { + return hexutil.UnmarshalFixedJSON(reflect.TypeOf(b), text, b[:]) +} + +func (b *Bytes32) UnmarshalText(text []byte) error { + return hexutil.UnmarshalFixedText("Bytes32", text, b[:]) +} + +func (b Bytes32) MarshalText() ([]byte, error) { + return hexutil.Bytes(b[:]).MarshalText() +} + +func (b Bytes32) String() string { + return hexutil.Encode(b[:]) +} + +// TerminalString implements log.TerminalStringer, formatting a string for console +// output during logging. +func (b Bytes32) TerminalString() string { + return fmt.Sprintf("0x%x..%x", b[:3], b[29:]) +} + +type Bytes8 [8]byte + +func (b *Bytes8) UnmarshalJSON(text []byte) error { + return hexutil.UnmarshalFixedJSON(reflect.TypeOf(b), text, b[:]) +} + +func (b *Bytes8) UnmarshalText(text []byte) error { + return hexutil.UnmarshalFixedText("Bytes8", text, b[:]) +} + +func (b Bytes8) MarshalText() ([]byte, error) { + return hexutil.Bytes(b[:]).MarshalText() +} + +func (b Bytes8) String() string { + return hexutil.Encode(b[:]) +} + +// TerminalString implements log.TerminalStringer, formatting a string for console +// output during logging. +func (b Bytes8) TerminalString() string { + return fmt.Sprintf("0x%x", b[:]) +} + +type Bytes96 [96]byte + +func (b *Bytes96) UnmarshalJSON(text []byte) error { + return hexutil.UnmarshalFixedJSON(reflect.TypeOf(b), text, b[:]) +} + +func (b *Bytes96) UnmarshalText(text []byte) error { + return hexutil.UnmarshalFixedText("Bytes96", text, b[:]) +} + +func (b Bytes96) MarshalText() ([]byte, error) { + return hexutil.Bytes(b[:]).MarshalText() +} + +func (b Bytes96) String() string { + return hexutil.Encode(b[:]) +} + +// TerminalString implements log.TerminalStringer, formatting a string for console +// output during logging. +func (b Bytes96) TerminalString() string { + return fmt.Sprintf("0x%x..%x", b[:3], b[93:]) +} + +type Bytes256 [256]byte + +func (b *Bytes256) UnmarshalJSON(text []byte) error { + return hexutil.UnmarshalFixedJSON(reflect.TypeOf(b), text, b[:]) +} + +func (b *Bytes256) UnmarshalText(text []byte) error { + return hexutil.UnmarshalFixedText("Bytes32", text, b[:]) +} + +func (b Bytes256) MarshalText() ([]byte, error) { + return hexutil.Bytes(b[:]).MarshalText() +} + +func (b Bytes256) String() string { + return hexutil.Encode(b[:]) +} + +// TerminalString implements log.TerminalStringer, formatting a string for console +// output during logging. +func (b Bytes256) TerminalString() string { + return fmt.Sprintf("0x%x..%x", b[:3], b[253:]) +} + +type Uint64Quantity = hexutil.Uint64 + +type BytesMax32 []byte + +func (b *BytesMax32) UnmarshalJSON(text []byte) error { + if len(text) > 64+2+2 { // account for delimiter "", and 0x prefix + return fmt.Errorf("input too long, expected at most 32 hex-encoded, 0x-prefixed, bytes: %x", text) + } + return (*hexutil.Bytes)(b).UnmarshalJSON(text) +} + +func (b *BytesMax32) UnmarshalText(text []byte) error { + if len(text) > 64+2 { // account for 0x prefix + return fmt.Errorf("input too long, expected at most 32 hex-encoded, 0x-prefixed, bytes: %x", text) + } + return (*hexutil.Bytes)(b).UnmarshalText(text) +} + +func (b BytesMax32) MarshalText() ([]byte, error) { + return (hexutil.Bytes)(b).MarshalText() +} + +func (b BytesMax32) String() string { + return hexutil.Encode(b) +} + +type Uint256Quantity = hexutil.U256 + +type Data = hexutil.Bytes + +type PayloadID = engine.PayloadID + +type ExecutionPayloadEnvelope struct { + ParentBeaconBlockRoot *common.Hash + ExecutionPayload *ExecutionPayload +} + +func (env *ExecutionPayloadEnvelope) ID() BlockID { + return env.ExecutionPayload.ID() +} + +func (env *ExecutionPayloadEnvelope) String() string { + return fmt.Sprintf("envelope(%s)", env.ID()) +} + +type ExecutionPayload struct { + ParentHash common.Hash + FeeRecipient common.Address + StateRoot Bytes32 + ReceiptsRoot Bytes32 + LogsBloom Bytes256 + PrevRandao Bytes32 + BlockNumber Uint64Quantity + GasLimit Uint64Quantity + GasUsed Uint64Quantity + Timestamp Uint64Quantity + ExtraData BytesMax32 + BaseFeePerGas Uint256Quantity + BlockHash common.Hash + // Array of transaction objects, each object is a byte list (DATA) representing + // TransactionType || TransactionPayload or LegacyTransaction as defined in EIP-2718 + Transactions []Data + // Nil if not present (Bedrock) + Withdrawals *types.Withdrawals + // Nil if not present (Bedrock, Canyon, Delta) + BlobGasUsed *Uint64Quantity + // Nil if not present (Bedrock, Canyon, Delta) + ExcessBlobGas *Uint64Quantity + // Nil if not present (Bedrock, Canyon, Delta, Ecotone, Fjord, Granite, Holocene) + WithdrawalsRoot *common.Hash +} + +func (payload *ExecutionPayload) ID() BlockID { + return BlockID{Hash: payload.BlockHash, Number: uint64(payload.BlockNumber)} +} + +func (payload *ExecutionPayload) String() string { + return fmt.Sprintf("payload(%s)", payload.ID()) +} + +func (payload *ExecutionPayload) ParentID() BlockID { + n := uint64(payload.BlockNumber) + if n > 0 { + n -= 1 + } + return BlockID{Hash: payload.ParentHash, Number: n} +} + +func (payload *ExecutionPayload) BlockRef() BlockRef { + return BlockRef{ + Hash: payload.BlockHash, + Number: uint64(payload.BlockNumber), + ParentHash: payload.ParentHash, + Time: uint64(payload.Timestamp), + } +} diff --git a/op/peer_dialer.go b/op/peer_dialer.go new file mode 100644 index 0000000..769743d --- /dev/null +++ b/op/peer_dialer.go @@ -0,0 +1,65 @@ +package op + +import ( + "context" + "log/slog" + "time" + + "github.com/libp2p/go-libp2p/core/peer" + "github.com/thejerf/suture/v4" + + "github.com/probe-lab/hermes/host" +) + +// PeerDialer is a suture service that reads peers from the peerChan (which +// is filled by the [Discovery] service until that peerChan channel is closed. +// When PeerDialer sees a new peer, it does a few sanity checks and tries +// to establish a connection. +type PeerDialer struct { + host *host.Host + peerChan <-chan peer.AddrInfo + maxPeers int +} + +var _ suture.Service = (*PeerDialer)(nil) + +func (p *PeerDialer) Serve(ctx context.Context) error { + slog.Debug("Started Peer Dialer Service") + defer slog.Debug("Stopped Peer Dialer Service") + + for { + // if we're at capacity, don't look for more peers + if len(p.host.Network().Peers()) >= p.maxPeers { + select { + case <-ctx.Done(): + return nil + case <-time.After(time.Second): + // pass + } + continue + } + + var ( + more bool + addrInfo peer.AddrInfo + ) + select { + case <-ctx.Done(): + return nil + case addrInfo, more = <-p.peerChan: + if !more { + return nil + } + } + + // don't connect with ourselves + if addrInfo.ID == p.host.ID() { + continue + } + + // finally, start the connection establishment. + // The success case is handled in net_notifiee.go. + _ = p.host.Connect(ctx, addrInfo) // ignore error, this happens all the time + // GossipSub will pick up the connection event and go from there + } +} diff --git a/op/pubsub.go b/op/pubsub.go new file mode 100644 index 0000000..32a347c --- /dev/null +++ b/op/pubsub.go @@ -0,0 +1,154 @@ +package op + +import ( + "bytes" + "context" + "encoding/hex" + "fmt" + "github.com/golang/snappy" + pubsub "github.com/libp2p/go-libp2p-pubsub" + pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/probe-lab/hermes/op/p2p" + "github.com/probe-lab/hermes/tele" + "github.com/thejerf/suture/v4" + "log/slog" + "time" + + "github.com/probe-lab/hermes/host" +) + +const eventTypeHandleMessage = "HANDLE_MESSAGE" + +type PubSubConfig struct { + ChainID int + BlockTopics []string + DataStream host.DataStream +} + +func (p PubSubConfig) Validate() error { + if p.ChainID <= 0 { + return fmt.Errorf("chainID unset or negative: %d", p.ChainID) + } + + return nil +} + +type PubSub struct { + host *host.Host + cfg *PubSubConfig + gs *pubsub.PubSub +} + +func NewPubSub(h *host.Host, cfg *PubSubConfig) (*PubSub, error) { + if err := cfg.Validate(); err != nil { + return nil, fmt.Errorf("validate configuration: %w", err) + } + + return &PubSub{ + host: h, + cfg: cfg, + }, nil +} + +func (p *PubSub) Serve(ctx context.Context) error { + if p.gs == nil { + return fmt.Errorf("node's pubsub service uninitialized gossip sub: %w", suture.ErrTerminateSupervisorTree) + } + + supervisor := suture.NewSimple("pubsub") + + for version, topicName := range p.cfg.BlockTopics { + topic, err := p.gs.Join(topicName) + if err != nil { + return fmt.Errorf("join pubsub topic %s: %w", topicName, err) + } + defer logDeferErr(topic.Close, fmt.Sprintf("failed closing %s topic", topicName)) + + sub, err := topic.Subscribe() + if err != nil { + return fmt.Errorf("subscribe to pubsub topic %s: %w", topicName, err) + } + + ts := &host.TopicSubscription{ + Topic: topicName, + LocalID: p.host.ID(), + Sub: sub, + Handler: p.handleBlock(p2p.BlockVersion(version)), + } + + supervisor.Add(ts) + } + + return supervisor.Serve(ctx) +} + +func (p *PubSub) handleBlock(blockVersion p2p.BlockVersion) host.TopicHandler { + return func(ctx context.Context, msg *pubsub.Message) error { + evt := &host.TraceEvent{ + Type: eventTypeHandleMessage, + Topic: msg.GetTopic(), + PeerID: p.host.ID(), + Timestamp: time.Now(), + } + + data, err := snappy.Decode(nil, msg.Data) + if err != nil { + return fmt.Errorf("decode message: %w", err) + } + + // message starts with compact-encoding secp256k1 encoded signature + //signature := data[:65] + payloadBytes := data[65:] + + var envelope p2p.ExecutionPayloadEnvelope + if blockVersion.HasParentBeaconBlockRoot() { + if err := envelope.UnmarshalSSZ(blockVersion, uint32(len(payloadBytes)), bytes.NewReader(payloadBytes)); err != nil { + slog.Warn("invalid envelope payload", "err", err, "peer", msg.GetFrom()) + return fmt.Errorf("invalid envelope payload: %w", err) + } + } else { + var payload p2p.ExecutionPayload + if err := payload.UnmarshalSSZ(blockVersion, uint32(len(payloadBytes)), bytes.NewReader(payloadBytes)); err != nil { + slog.Warn("invalid execution payload", "err", err, "peer", msg.GetFrom()) + return fmt.Errorf("invalid execution payload: %w", err) + } + envelope = p2p.ExecutionPayloadEnvelope{ExecutionPayload: &payload} + } + + envelope.ExecutionPayload.Transactions = []p2p.Data{} + envelope.ExecutionPayload.LogsBloom = [256]byte{} + + evt.Payload = map[string]any{ + "PeerID": msg.ReceivedFrom, + "Topic": msg.GetTopic(), + "Seq": hex.EncodeToString(msg.GetSeqno()), + "MsgID": hex.EncodeToString([]byte(msg.ID)), + "MsgSize": len(msg.Data), + "ParentBeaconBlockRoot": envelope.ParentBeaconBlockRoot, + "ExecutionPayload": envelope.ExecutionPayload, + } + + if err := p.cfg.DataStream.PutRecord(ctx, evt); err != nil { + slog.Warn( + "failed putting topic handler event", "topic", msg.GetTopic(), "err", tele.LogAttrError(err), + ) + } + + return nil + } +} + +var _ pubsub.SubscriptionFilter = (*Node)(nil) + +// CanSubscribe originally returns true if the topic is of interest, and we could subscribe to it. +func (n *Node) CanSubscribe(topic string) bool { + return true +} + +// FilterIncomingSubscriptions is invoked for all RPCs containing subscription notifications. +// This method returns only the topics of interest and may return an error if the subscription +// request contains too many topics. +func (n *Node) FilterIncomingSubscriptions(id peer.ID, subs []*pubsubpb.RPC_SubOpts) ([]*pubsubpb.RPC_SubOpts, error) { + return pubsub.FilterSubscriptions(subs, n.CanSubscribe), nil +} From a8dd2b7889fee7a978fc37e3e8883e264d0553f7 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Fri, 22 Aug 2025 12:09:27 +0200 Subject: [PATCH 56/65] fix: print correct op configuration on startup --- cmd/hermes/cmd_op.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/cmd/hermes/cmd_op.go b/cmd/hermes/cmd_op.go index c6fad6d..2fa6393 100644 --- a/cmd/hermes/cmd_op.go +++ b/cmd/hermes/cmd_op.go @@ -1,7 +1,9 @@ package main import ( + "encoding/json" "fmt" + "github.com/probe-lab/hermes/tele" "log/slog" "time" @@ -105,7 +107,7 @@ func cmdOpAction(c *cli.Context) error { defer slog.Info("Stopped Hermes for Optimism.") // Print hermes configuration for debugging purposes - printFilConfig() + printOpConfig() bootstrapperCfg := opConfig.Bootstrappers.Value() if len(bootstrapperCfg) == 0 { @@ -177,3 +179,19 @@ func cmdOpAction(c *cli.Context) error { return n.Start(c.Context) } + +func printOpConfig() { + cfgCopy := *opConfig + if cfgCopy.PrivateKeyStr != "" { + cfgCopy.PrivateKeyStr = "***" + } + + dat, err := json.Marshal(cfgCopy) + if err != nil { + slog.Warn("Failed marshalling eth config struct", tele.LogAttrError(err)) + return + } + + slog.Info("Config:") + slog.Info(string(dat)) +} From e3514eadf5688faf79f4aa37b3a2952a09eaedf7 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Fri, 22 Aug 2025 12:09:36 +0200 Subject: [PATCH 57/65] remove: unused constants --- op/node_config.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/op/node_config.go b/op/node_config.go index 2717abd..d875428 100644 --- a/op/node_config.go +++ b/op/node_config.go @@ -33,20 +33,13 @@ const ( // maxGossipSize limits the total size of gossip RPC containers as well as decompressed individual messages. maxGossipSize = 10 * (1 << 20) // minGossipSize is used to make sure that there is at least some data to validate the signature against. - minGossipSize = 66 maxOutboundQueue = 256 maxValidateQueue = 256 globalValidateThrottle = 512 gossipHeartbeat = 500 * time.Millisecond // seenMessagesTTL limits the duration that message IDs are remembered for gossip deduplication purposes // 130 * gossipHeartbeat - seenMessagesTTL = 130 * gossipHeartbeat - DefaultMeshD = 8 // topic stable mesh target count - DefaultMeshDlo = 6 // topic stable mesh low watermark - DefaultMeshDhi = 12 // topic stable mesh high watermark - DefaultMeshDlazy = 6 // gossip target - // peerScoreInspectFrequency is the frequency at which peer scores are inspected - peerScoreInspectFrequency = 15 * time.Second + seenMessagesTTL = 130 * gossipHeartbeat ) // Message domains, the msg id function uncompresses to keep data monomorphic, From 2490586dc2c801d07014a67a8d6e1258c84dc729 Mon Sep 17 00:00:00 2001 From: Dennis Trautwein Date: Fri, 22 Aug 2025 12:21:35 +0200 Subject: [PATCH 58/65] Update README.md --- README.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7430f3f..738e2aa 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Hermes is light libp2p networking node that serves as a GossipSub listener and tracer for multiple networks. It discovers and connects with network participats subscribing to all relevant pubsub topics of the respective network and traces all protocol interactions like grafts, prunes, and any RPCs. -As of `2025-07-11`, Hermes supports the Ethereum and Filecoin networks. +As of `2025-08-22`, Hermes supports the Ethereum, Filecoin, and OPStack-based networks. ## Table of Contents @@ -27,6 +27,7 @@ As of `2025-07-11`, Hermes supports the Ethereum and Filecoin networks. * [Topic Subscription](#topic-subscription) * [Filecoin](#filecoin) * [Hermes vs Filecoin Lite Nodes](#hermes-vs-filecoin-lite-nodes) + * [Optimism](#optimism) * [Importing Hermes](#importing-hermes) * [Telemetry](#telemetry) * [Metrics](#metrics) @@ -61,6 +62,7 @@ Start Hermes by running: go run ./cmd/hermes # Show help go run ./cmd/hermes eth --help # Ethereum-specific options go run ./cmd/hermes fil --help # Filecoin-specific options +go run ./cmd/hermes op --help # OPStack-specific options ```
@@ -76,6 +78,7 @@ USAGE: COMMANDS: eth, ethereum Listen to gossipsub topics of the Ethereum network fil, filecoin Listen to gossipsub topics of the Filecoin network + op, optimism Listen to gossipsub topics of any OPStack-based network benchmark performs the given set of benchmarks for the hermes internals help, h Shows a list of commands or help for one command @@ -134,10 +137,11 @@ _However_, Hermes currently doesn't support loading CLI arguments from a file ¯ ## Deployment Depending on the network you want to trace Hermes requires auxiliary infrastructure. -As of `2025-07-11`, Hermes supports these networks: +As of `2025-08-22`, Hermes supports these networks: - [Ethereum](#ethereum) - [Filecoin](#filecoin) +- [OPStack](#opstack) ### General @@ -380,6 +384,52 @@ Hermes, on the other hand, is a network monitoring instrument to analyze GossipS It behaves like a light node in the network by connecting to other nodes and advertising its presence through a periodic DHT lookup. Hermes subscribes to all available GossipSub topics, allowing it to comprehensively receive and trace all of the activity in the network. +### OPStack + +To run Hermes in an OPStack-based network, no auxiliary infrastructure is needed. +Just run: + +```shell +go run ./cmd/hermes op +``` + +This will instruct Hermes to bootstrap into the Optimism network using the +canonical bootstrap peers. Check out the help page via `hermes op --help` for +configuration options of the libp2p host or devp2p local node (e.g., listen addrs/ports). + +If you want to connect to a different OPStack network, like Base, run: + +```shell +go run ./cmd/hermes op --chain.id 8453 +``` + +You can use https://chainlist.org/ to find the corresponding chain ID for the network +you want to trace. The default is chain ID `10` which corresponds to the Optimism +network. + +
+Hermes' Optimism Help Page + +```text +NAME: + hermes op - Listen to gossipsub topics of any OPStack-based network + +USAGE: + hermes op [command options] + +OPTIONS: + --key value, -k value The private key for the hermes libp2p/ethereum node in hex format. [$HERMES_OP_KEY] + --dial.timeout value The request timeout when contacting other network participants (default: 5s) [$HERMES_OP_DIAL_TIMEOUT] + --libp2p.host value Which network interface should libp2p bind to. (default: "127.0.0.1") [$HERMES_OP_LIBP2P_HOST] + --libp2p.port value On which port should libp2p listen (default: random) [$HERMES_OP_LIBP2P_PORT] + --chain.id value Which network hermes should connect to (default: 10) [$HERMES_OP_CHAIN_ID] + --libp2p.peerscore.snapshot.frequency value Frequency at which GossipSub peerscores will be accessed (in seconds) (default: random) [$HERMES_OP_LIBP2P_PEERSCORE_SNAPSHOT_FREQUENCY] + --bootstrappers value [ --bootstrappers value ] List of bootstrappers to connect to (default: eth mainnet) [$HERMES_OP_BOOTSTRAPPERS] + --help, -h show help +``` + +
+ ## Importing Hermes Hermes is more than just a simple GossipSub listener and tracer. Its simplicity, lightweight deployment requirements, and abstraction from the application-layer logic, From 712c7b6d8f22b7703bdf1f2a0e6cefd609c7d433 Mon Sep 17 00:00:00 2001 From: Matty Evans Date: Mon, 25 Aug 2025 13:35:31 +1000 Subject: [PATCH 59/65] feat: add Fulu fork support with BPO-aware fork digest calculation - Add support for Fulu network fork with custom fork digests - Update Go to 1.24.5 and upgrade dependencies - Remove unused cpyStatusAny and deprecated cpyStatus helpers - Skip TestReqResp_ProtocolRequests to prevent CI failures --- cmd/hermes/cmd_eth.go | 13 +- cmd/hermes/cmd_eth_chains.go | 11 +- eth/discovery.go | 14 +- eth/discovery_config.go | 29 +- eth/genesis.go | 42 +-- eth/network_config.go | 1 + eth/node.go | 81 ++-- eth/node_config.go | 4 + eth/output_full.go | 46 +++ eth/output_kinesis.go | 45 +++ eth/prysm.go | 102 ++++- eth/pubsub.go | 53 ++- eth/reqresp.go | 695 +++++++++++++++++++++++++++++++---- eth/reqresp_test.go | 245 ++++++++++++ eth/reqresp_types.go | 207 +++++++++++ eth/subnets.go | 3 + eth/topic_score_params.go | 4 +- go.mod | 14 +- go.sum | 24 +- 19 files changed, 1447 insertions(+), 186 deletions(-) create mode 100644 eth/reqresp_types.go diff --git a/cmd/hermes/cmd_eth.go b/cmd/hermes/cmd_eth.go index 0af217a..b323395 100644 --- a/cmd/hermes/cmd_eth.go +++ b/cmd/hermes/cmd_eth.go @@ -7,7 +7,6 @@ import ( "log/slog" "time" - "github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing" "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p" "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/encoder" "github.com/OffchainLabs/prysm/v6/config/params" @@ -415,16 +414,15 @@ func cmdEthAction(c *cli.Context) error { config = c } - // Overriding configuration so that functions like ComputForkDigest take the - // correct input data from the global configuration. + // Overriding configuration so that params.ForkDigest and other functions + // use the correct network configuration. params.OverrideBeaconConfig(config.Beacon) params.OverrideBeaconNetworkConfig(config.Network) - genesisRoot := config.Genesis.GenesisValidatorRoot genesisTime := config.Genesis.GenesisTime // compute fork version and fork digest - currentSlot := slots.Since(genesisTime) + currentSlot := slots.CurrentSlot(genesisTime) currentEpoch := slots.ToEpoch(currentSlot) currentForkVersion, err := eth.GetCurrentForkVersion(currentEpoch, config.Beacon) @@ -432,10 +430,7 @@ func cmdEthAction(c *cli.Context) error { return fmt.Errorf("compute fork version for epoch %d: %w", currentEpoch, err) } - forkDigest, err := signing.ComputeForkDigest(currentForkVersion[:], genesisRoot) - if err != nil { - return fmt.Errorf("create fork digest (%s, %x): %w", genesisTime, genesisRoot, err) - } + forkDigest := params.ForkDigest(currentEpoch) cfg := ð.NodeConfig{ GenesisConfig: config.Genesis, diff --git a/cmd/hermes/cmd_eth_chains.go b/cmd/hermes/cmd_eth_chains.go index 84f73f0..919b540 100644 --- a/cmd/hermes/cmd_eth_chains.go +++ b/cmd/hermes/cmd_eth_chains.go @@ -5,7 +5,6 @@ import ( "log/slog" "math" - "github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing" "github.com/OffchainLabs/prysm/v6/config/params" "github.com/urfave/cli/v2" @@ -35,6 +34,10 @@ func cmdEthChainsAction(c *cli.Context) error { } slog.Info(chain) + // Override params config for this network to get correct fork digests. + params.OverrideBeaconConfig(config.Beacon) + params.OverrideBeaconNetworkConfig(config.Network) + forkVersions := [][]byte{ config.Beacon.GenesisForkVersion, config.Beacon.AltairForkVersion, @@ -42,6 +45,7 @@ func cmdEthChainsAction(c *cli.Context) error { config.Beacon.CapellaForkVersion, config.Beacon.DenebForkVersion, config.Beacon.ElectraForkVersion, + config.Beacon.FuluForkVersion, } for _, forkVersion := range forkVersions { @@ -59,10 +63,7 @@ func cmdEthChainsAction(c *cli.Context) error { continue } - digest, err := signing.ComputeForkDigest(forkVersion, config.Genesis.GenesisValidatorRoot) - if err != nil { - return err - } + digest := params.ForkDigest(epoch) slog.Info(fmt.Sprintf("- %s: 0x%x (epoch %d)", forkName, digest, epoch)) } diff --git a/eth/discovery.go b/eth/discovery.go index 9ceb8ba..a5b6d26 100644 --- a/eth/discovery.go +++ b/eth/discovery.go @@ -9,8 +9,9 @@ import ( "log/slog" "net" - "github.com/OffchainLabs/prysm/v6/network/forks" + "github.com/OffchainLabs/prysm/v6/config/params" pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1" + "github.com/OffchainLabs/prysm/v6/time/slots" "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/enode" @@ -93,13 +94,10 @@ func (d *Discovery) Serve(ctx context.Context) (err error) { defer slog.Info("Stopped disv5 Discovery Service") defer func() { err = terminateSupervisorTreeOnErr(err) }() - genesisRoot := d.cfg.GenesisConfig.GenesisValidatorRoot genesisTime := d.cfg.GenesisConfig.GenesisTime - - digest, err := forks.CreateForkDigest(genesisTime, genesisRoot) - if err != nil { - return fmt.Errorf("create fork digest (%s, %x): %w", genesisTime, genesisRoot, err) - } + currentSlot := slots.CurrentSlot(genesisTime) + currentEpoch := slots.ToEpoch(currentSlot) + digest := params.ForkDigest(currentEpoch) ip := net.ParseIP(d.cfg.Addr) @@ -179,7 +177,7 @@ func (d *Discovery) Serve(ctx context.Context) (err error) { continue } sszEncodedForkEntry := make([]byte, 16) - entry := enr.WithEntry(d.cfg.NetworkConfig.ETH2Key, &sszEncodedForkEntry) + entry := enr.WithEntry("eth2", &sszEncodedForkEntry) if err = node.Record().Load(entry); err != nil { // failed reading eth2 enr entry, likely because it doesn't exist continue diff --git a/eth/discovery_config.go b/eth/discovery_config.go index c75d515..da9a08f 100644 --- a/eth/discovery_config.go +++ b/eth/discovery_config.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/OffchainLabs/prysm/v6/config/params" - "github.com/OffchainLabs/prysm/v6/network/forks" + "github.com/OffchainLabs/prysm/v6/consensus-types/primitives" pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1" "github.com/OffchainLabs/prysm/v6/time/slots" "github.com/ethereum/go-ethereum/p2p/enode" @@ -33,20 +33,19 @@ type DiscoveryConfig struct { // byte slice. Finally, it returns an ENR entry with the eth2 key and the // encoded fork information. func (d *DiscoveryConfig) enrEth2Entry() (enr.Entry, error) { - genesisRoot := d.GenesisConfig.GenesisValidatorRoot - genesisTime := d.GenesisConfig.GenesisTime + var ( + currentSlot = slots.CurrentSlot(d.GenesisConfig.GenesisTime) + currentEpoch = slots.ToEpoch(currentSlot) + digest = params.ForkDigest(currentEpoch) + nextEntry = params.NextNetworkScheduleEntry(currentEpoch) + nextForkVersion [4]byte + nextForkEpoch primitives.Epoch + ) - digest, err := forks.CreateForkDigest(genesisTime, genesisRoot) - if err != nil { - return nil, fmt.Errorf("create fork digest (%s, %x): %w", genesisTime, genesisRoot, err) - } - - currentSlot := slots.Since(genesisTime) - currentEpoch := slots.ToEpoch(currentSlot) - - nextForkVersion, nextForkEpoch, err := forks.NextForkData(currentEpoch) - if err != nil { - return nil, fmt.Errorf("calculate next fork data: %w", err) + // Is there another fork coming up? + if nextEntry.Epoch > currentEpoch { + copy(nextForkVersion[:], nextEntry.ForkVersion[:]) + nextForkEpoch = nextEntry.Epoch } enrForkID := &pb.ENRForkID{ @@ -60,7 +59,7 @@ func (d *DiscoveryConfig) enrEth2Entry() (enr.Entry, error) { return nil, fmt.Errorf("marshal enr fork id: %w", err) } - return enr.WithEntry(d.NetworkConfig.ETH2Key, enc), nil + return enr.WithEntry("eth2", enc), nil } func (d *DiscoveryConfig) enrAttnetsEntry() enr.Entry { diff --git a/eth/genesis.go b/eth/genesis.go index 3afbe7c..9ff273b 100644 --- a/eth/genesis.go +++ b/eth/genesis.go @@ -5,7 +5,6 @@ import ( "fmt" "time" - "github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing" "github.com/OffchainLabs/prysm/v6/config/params" "github.com/OffchainLabs/prysm/v6/consensus-types/primitives" ) @@ -25,6 +24,7 @@ var ( CapellaForkVersion ForkVersion DenebForkVersion ForkVersion ElectraForkVersion ForkVersion + FuluForkVersion ForkVersion GlobalBeaconConfig = params.MainnetConfig() // init with Mainnet (we would override if needed) ) @@ -37,6 +37,7 @@ func initNetworkForkVersions(beaconConfig *params.BeaconChainConfig) { CapellaForkVersion = ForkVersion(beaconConfig.CapellaForkVersion) DenebForkVersion = ForkVersion(beaconConfig.DenebForkVersion) ElectraForkVersion = ForkVersion(beaconConfig.ElectraForkVersion) + FuluForkVersion = ForkVersion(beaconConfig.FuluForkVersion) GlobalBeaconConfig = beaconConfig } @@ -96,38 +97,27 @@ func GetCurrentForkVersion(epoch primitives.Epoch, beaconConfg *params.BeaconCha case epoch < beaconConfg.ElectraForkEpoch: return [4]byte(beaconConfg.DenebForkVersion), nil - case epoch >= beaconConfg.ElectraForkEpoch: + case epoch < beaconConfg.FuluForkEpoch: return [4]byte(beaconConfg.ElectraForkVersion), nil + case epoch >= beaconConfg.FuluForkEpoch: + return [4]byte(beaconConfg.FuluForkVersion), nil + default: return [4]byte{}, fmt.Errorf("not recognized case for epoch %d", epoch) } } +// GetForkVersionFromForkDigest returns the fork version for a given fork digest. +// This function is BPO-aware as it uses params.ForkDataFromDigest which handles +// the network schedule including BPO phases for Fulu+. func GetForkVersionFromForkDigest(forkD [4]byte) (forkV ForkVersion, err error) { - genesisRoot := GenesisConfigs[GlobalBeaconConfig.ConfigName].GenesisValidatorRoot - phase0D, _ := signing.ComputeForkDigest(Phase0ForkVersion[:], genesisRoot) - altairD, _ := signing.ComputeForkDigest(AltairForkVersion[:], genesisRoot) - bellatrixD, _ := signing.ComputeForkDigest(BellatrixForkVersion[:], genesisRoot) - capellaD, _ := signing.ComputeForkDigest(CapellaForkVersion[:], genesisRoot) - denebD, _ := signing.ComputeForkDigest(DenebForkVersion[:], genesisRoot) - electraD, _ := signing.ComputeForkDigest(ElectraForkVersion[:], genesisRoot) - switch forkD { - case phase0D: - forkV = Phase0ForkVersion - case altairD: - forkV = AltairForkVersion - case bellatrixD: - forkV = BellatrixForkVersion - case capellaD: - forkV = CapellaForkVersion - case denebD: - forkV = DenebForkVersion - case electraD: - forkV = ElectraForkVersion - default: - forkV = ForkVersion{} - err = fmt.Errorf("not recognized fork_version for (%s)", hex.EncodeToString([]byte(forkD[:]))) + // Use params.ForkDataFromDigest which is BPO-aware and handles all fork digests + // including those modified by BPO schedule in Fulu+ + version, _, err := params.ForkDataFromDigest(forkD) + if err != nil { + return ForkVersion{}, fmt.Errorf("fork digest %s not found in network schedule", hex.EncodeToString(forkD[:])) } - return forkV, err + + return version, nil } diff --git a/eth/network_config.go b/eth/network_config.go index 658fc9c..f72a3a3 100644 --- a/eth/network_config.go +++ b/eth/network_config.go @@ -62,6 +62,7 @@ func DeriveKnownNetworkConfig(ctx context.Context, network string) (*NetworkConf CapellaForkVersion: []byte{0x03, 0x00, 0x00, 0x64}, DenebForkVersion: []byte{0x04, 0x00, 0x00, 0x64}, ElectraForkVersion: []byte{0x05, 0x00, 0x00, 0x64}, + FuluForkVersion: []byte{0x06, 0x00, 0x00, 0x64}, ForkVersionSchedule: map[[4]byte]primitives.Epoch{ {0x00, 0x00, 0x00, 0x64}: primitives.Epoch(0), {0x01, 0x00, 0x00, 0x64}: primitives.Epoch(512), diff --git a/eth/node.go b/eth/node.go index c6c7e48..2f9afb6 100644 --- a/eth/node.go +++ b/eth/node.go @@ -9,7 +9,9 @@ import ( "time" "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p" + "github.com/OffchainLabs/prysm/v6/config/params" eth "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1" + "github.com/OffchainLabs/prysm/v6/time/slots" "github.com/aws/aws-sdk-go-v2/service/kinesis" gk "github.com/dennis-tra/go-kinesis" "github.com/libp2p/go-libp2p/core/peer" @@ -195,6 +197,8 @@ func NewNode(cfg *NodeConfig) (*Node, error) { DataStream: ds, ReadTimeout: cfg.BeaconConfig.TtfbTimeoutDuration(), WriteTimeout: cfg.BeaconConfig.RespTimeoutDuration(), + BeaconConfig: cfg.BeaconConfig, + GenesisConfig: cfg.GenesisConfig, Tracer: cfg.Tracer, Meter: cfg.Meter, } @@ -204,29 +208,26 @@ func NewNode(cfg *NodeConfig) (*Node, error) { return nil, fmt.Errorf("new p2p server: %w", err) } - // initialize the pubsub topic handlers - pubSubConfig := &PubSubConfig{ - Topics: cfg.getDesiredFullTopics(cfg.GossipSubMessageEncoder), - ForkVersion: cfg.ForkVersion, - Encoder: cfg.GossipSubMessageEncoder, - SecondsPerSlot: time.Duration(cfg.BeaconConfig.SecondsPerSlot) * time.Second, - GenesisTime: cfg.GenesisConfig.GenesisTime, - DataStream: ds, - } - - pubSub, err := NewPubSub(h, pubSubConfig) - if err != nil { - return nil, fmt.Errorf("new PubSub service: %w", err) - } - // initialize the custom Prysm client to communicate with its API pryClient, err := NewPrysmClientWithTLS(cfg.PrysmHost, cfg.PrysmPortHTTP, cfg.PrysmPortGRPC, cfg.PrysmUseTLS, cfg.DialTimeout, cfg.GenesisConfig) if err != nil { return nil, fmt.Errorf("new prysm client: %w", err) } - // check if Prysm is valid + + // Fetch and set the BlobSchedule from Prysm for correct BPO fork digest calculation. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() + if err := pryClient.FetchAndSetBlobSchedule(ctx); err != nil { + // Continue even if this fails, as the network might not have BPO enabled. + slog.Warn("Failed to fetch BlobSchedule from Prysm", tele.LogAttrError(err)) + } + + // Recalculate fork digest after loading BlobSchedule. + currentSlot := slots.CurrentSlot(cfg.GenesisConfig.GenesisTime) + currentEpoch := slots.ToEpoch(currentSlot) + cfg.ForkDigest = params.ForkDigest(currentEpoch) + + // check if Prysm is valid onNetwork, err := pryClient.isOnNetwork(ctx, cfg.ForkDigest) if err != nil { return nil, fmt.Errorf("prysm client: %w", err) @@ -235,6 +236,20 @@ func NewNode(cfg *NodeConfig) (*Node, error) { return nil, fmt.Errorf("prysm client not in correct fork_digest") } + pubSubConfig := &PubSubConfig{ + Topics: cfg.getDesiredFullTopics(cfg.GossipSubMessageEncoder), + ForkVersion: cfg.ForkVersion, + Encoder: cfg.GossipSubMessageEncoder, + SecondsPerSlot: time.Duration(cfg.BeaconConfig.SecondsPerSlot) * time.Second, + GenesisTime: cfg.GenesisConfig.GenesisTime, + DataStream: ds, + } + + pubSub, err := NewPubSub(h, pubSubConfig) + if err != nil { + return nil, fmt.Errorf("new PubSub service: %w", err) + } + // finally, initialize hermes node n := &Node{ cfg: cfg, @@ -397,14 +412,34 @@ func (n *Node) Start(ctx context.Context) error { return fmt.Errorf("get finalized finality checkpoints: %w", err) } - status := ð.Status{ - ForkDigest: n.cfg.ForkDigest[:], - FinalizedRoot: chainHead.FinalizedBlockRoot, - FinalizedEpoch: chainHead.FinalizedEpoch, - HeadRoot: chainHead.HeadBlockRoot, - HeadSlot: chainHead.HeadSlot, + // Determine which status version to use based on the fork + currentSlot := slots.CurrentSlot(n.cfg.GenesisConfig.GenesisTime) + currentEpoch := slots.ToEpoch(currentSlot) + + // Use StatusV2 for Fulu fork and later, StatusV1 for earlier forks + if n.cfg.BeaconConfig.FuluForkEpoch != params.BeaconConfig().FarFutureEpoch && + currentEpoch >= n.cfg.BeaconConfig.FuluForkEpoch { + // Fulu or later - use StatusV2 + status := ð.StatusV2{ + ForkDigest: n.cfg.ForkDigest[:], + FinalizedRoot: chainHead.FinalizedBlockRoot, + FinalizedEpoch: chainHead.FinalizedEpoch, + HeadRoot: chainHead.HeadBlockRoot, + HeadSlot: chainHead.HeadSlot, + EarliestAvailableSlot: 0, // TODO: Get actual earliest slot from beacon node + } + n.reqResp.SetStatusV2(status) + } else { + // Pre-Fulu - use StatusV1 + status := ð.Status{ + ForkDigest: n.cfg.ForkDigest[:], + FinalizedRoot: chainHead.FinalizedBlockRoot, + FinalizedEpoch: chainHead.FinalizedEpoch, + HeadRoot: chainHead.HeadBlockRoot, + HeadSlot: chainHead.HeadSlot, + } + n.reqResp.SetStatusV1(status) } - n.reqResp.SetStatus(status) // Set stream handlers on our libp2p host if err := n.reqResp.RegisterHandlers(ctx); err != nil { diff --git a/eth/node_config.go b/eth/node_config.go index 0958392..8e6ac87 100644 --- a/eth/node_config.go +++ b/eth/node_config.go @@ -440,6 +440,7 @@ func desiredPubSubBaseTopics() []string { p2p.GossipSyncCommitteeMessage, p2p.GossipBlsToExecutionChangeMessage, p2p.GossipBlobSidecarMessage, + p2p.GossipDataColumnSidecarMessage, } } @@ -475,6 +476,9 @@ func topicFormatFromBase(topicBase string) (string, error) { case p2p.GossipBlobSidecarMessage: return p2p.BlobSubnetTopicFormat, nil + case p2p.GossipDataColumnSidecarMessage: + return p2p.DataColumnSubnetTopicFormat, nil + default: return "", fmt.Errorf("unrecognized gossip topic base: %s", topicBase) } diff --git a/eth/output_full.go b/eth/output_full.go index b4764d3..aaa9b00 100644 --- a/eth/output_full.go +++ b/eth/output_full.go @@ -40,6 +40,11 @@ type TraceEventElectraBlock struct { Block *ethtypes.SignedBeaconBlockElectra } +type TraceEventFuluBlock struct { + host.TraceEventPayloadMetaData + Block *ethtypes.SignedBeaconBlockFulu +} + type TraceEventAttestation struct { host.TraceEventPayloadMetaData Attestation *ethtypes.Attestation @@ -55,6 +60,11 @@ type TraceEventSingleAttestation struct { SingleAttestation *ethtypes.SingleAttestation } +type TraceEventDataColumnSidecar struct { + host.TraceEventPayloadMetaData + DataColumnSidecar *ethtypes.DataColumnSidecar +} + type TraceEventSignedAggregateAttestationAndProof struct { host.TraceEventPayloadMetaData SignedAggregateAttestationAndProof *ethtypes.SignedAggregateAttestationAndProof @@ -140,6 +150,8 @@ func (t *FullOutput) RenderPayload(evt *host.TraceEvent, msg *pubsub.Message, ds payload, err = t.renderDenebBlock(msg, d) case *ethtypes.SignedBeaconBlockElectra: payload, err = t.renderElectraBlock(msg, d) + case *ethtypes.SignedBeaconBlockFulu: + payload, err = t.renderFuluBlock(msg, d) case *ethtypes.Attestation: payload, err = t.renderAttestation(msg, d) case *ethtypes.AttestationElectra: @@ -160,6 +172,8 @@ func (t *FullOutput) RenderPayload(evt *host.TraceEvent, msg *pubsub.Message, ds payload, err = t.renderBLSToExecutionChange(msg, d) case *ethtypes.BlobSidecar: payload, err = t.renderBlobSidecar(msg, d) + case *ethtypes.DataColumnSidecar: + payload, err = t.renderDataColumnSidecar(msg, d) case *ethtypes.ProposerSlashing: payload, err = t.renderProposerSlashing(msg, d) case *ethtypes.AttesterSlashing: @@ -273,6 +287,22 @@ func (t *FullOutput) renderElectraBlock( }, nil } +func (t *FullOutput) renderFuluBlock( + msg *pubsub.Message, + block *ethtypes.SignedBeaconBlockFulu, +) (*TraceEventFuluBlock, error) { + return &TraceEventFuluBlock{ + TraceEventPayloadMetaData: host.TraceEventPayloadMetaData{ + PeerID: msg.ReceivedFrom.String(), + Topic: msg.GetTopic(), + Seq: msg.GetSeqno(), + MsgID: hex.EncodeToString([]byte(msg.ID)), + MsgSize: len(msg.Data), + }, + Block: block, + }, nil +} + func (t *FullOutput) renderAttestation( msg *pubsub.Message, attestation *ethtypes.Attestation, @@ -464,3 +494,19 @@ func (t *FullOutput) renderAttesterSlashing( AttesterSlashing: as, }, nil } + +func (t *FullOutput) renderDataColumnSidecar( + msg *pubsub.Message, + sidecar *ethtypes.DataColumnSidecar, +) (*TraceEventDataColumnSidecar, error) { + return &TraceEventDataColumnSidecar{ + TraceEventPayloadMetaData: host.TraceEventPayloadMetaData{ + PeerID: msg.ReceivedFrom.String(), + Topic: msg.GetTopic(), + Seq: msg.GetSeqno(), + MsgID: hex.EncodeToString([]byte(msg.ID)), + MsgSize: len(msg.Data), + }, + DataColumnSidecar: sidecar, + }, nil +} diff --git a/eth/output_kinesis.go b/eth/output_kinesis.go index af1f728..db2dfe3 100644 --- a/eth/output_kinesis.go +++ b/eth/output_kinesis.go @@ -52,6 +52,8 @@ func (k *KinesisOutput) RenderPayload(evt *host.TraceEvent, msg *pubsub.Message, payload, err = k.renderDenebBlock(msg, d) case *ethtypes.SignedBeaconBlockElectra: payload, err = k.renderElectraBlock(msg, d) + case *ethtypes.SignedBeaconBlockFulu: + payload, err = k.renderFuluBlock(msg, d) case *ethtypes.Attestation: payload, err = k.renderAttestation(msg, d) case *ethtypes.AttestationElectra: @@ -73,6 +75,8 @@ func (k *KinesisOutput) RenderPayload(evt *host.TraceEvent, msg *pubsub.Message, payload, err = k.renderBLSToExecutionChange(msg, d) case *ethtypes.BlobSidecar: payload, err = k.renderBlobSidecar(msg, d) + case *ethtypes.DataColumnSidecar: + payload, err = k.renderDataColumnSidecar(msg, d) case *ethtypes.ProposerSlashing: payload, err = k.renderProposerSlashing(msg, d) case *ethtypes.AttesterSlashing: @@ -222,6 +226,28 @@ func (k *KinesisOutput) renderElectraBlock( }, nil } +func (k *KinesisOutput) renderFuluBlock( + msg *pubsub.Message, + block *ethtypes.SignedBeaconBlockFulu, +) (map[string]any, error) { + root, err := block.GetBlock().HashTreeRoot() + if err != nil { + return nil, fmt.Errorf("failed to determine block hash tree root: %w", err) + } + + return map[string]any{ + "PeerID": msg.ReceivedFrom, + "Topic": msg.GetTopic(), + "Seq": hex.EncodeToString(msg.GetSeqno()), + "MsgID": hex.EncodeToString([]byte(msg.ID)), + "MsgSize": len(msg.Data), + "Slot": block.GetBlock().GetSlot(), + "Root": root, + "ValIdx": block.GetBlock().GetProposerIndex(), + "TimeInSlot": k.cfg.GenesisTime.Add(time.Duration(block.GetBlock().GetSlot()) * k.cfg.SecondsPerSlot), + }, nil +} + func (k *KinesisOutput) renderAttestation( msg *pubsub.Message, attestation *ethtypes.Attestation, @@ -445,3 +471,22 @@ func (k *KinesisOutput) renderAttesterSlashing( "Att2_indices": as.GetAttestation_2().GetAttestingIndices(), }, nil } + +func (k *KinesisOutput) renderDataColumnSidecar( + msg *pubsub.Message, + sidecar *ethtypes.DataColumnSidecar, +) (map[string]any, error) { + return map[string]any{ + "PeerID": msg.ReceivedFrom, + "MsgID": hex.EncodeToString([]byte(msg.ID)), + "MsgSize": len(msg.Data), + "Topic": msg.GetTopic(), + "Seq": hex.EncodeToString(msg.GetSeqno()), + "Slot": sidecar.GetSignedBlockHeader().GetHeader().GetSlot(), + "ValIdx": sidecar.GetSignedBlockHeader().GetHeader().GetProposerIndex(), + "Index": sidecar.GetIndex(), + "StateRoot": hexutil.Encode(sidecar.GetSignedBlockHeader().GetHeader().GetStateRoot()), + "BodyRoot": hexutil.Encode(sidecar.GetSignedBlockHeader().GetHeader().GetBodyRoot()), + "ParentRoot": hexutil.Encode(sidecar.GetSignedBlockHeader().GetHeader().GetParentRoot()), + }, nil +} diff --git a/eth/prysm.go b/eth/prysm.go index 82c50c5..22d630e 100644 --- a/eth/prysm.go +++ b/eth/prysm.go @@ -3,7 +3,6 @@ package eth import ( "bytes" "context" - "encoding/hex" "encoding/json" "errors" "fmt" @@ -16,9 +15,11 @@ import ( "github.com/OffchainLabs/prysm/v6/api/client" apiCli "github.com/OffchainLabs/prysm/v6/api/client/beacon" "github.com/OffchainLabs/prysm/v6/api/server/structs" - "github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing" + "github.com/OffchainLabs/prysm/v6/config/params" + "github.com/OffchainLabs/prysm/v6/consensus-types/primitives" "github.com/OffchainLabs/prysm/v6/network/httputil" eth "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1" + "github.com/OffchainLabs/prysm/v6/time/slots" "github.com/libp2p/go-libp2p/core/peer" ma "github.com/multiformats/go-multiaddr" "go.opentelemetry.io/otel" @@ -339,6 +340,86 @@ func (p *PrysmClient) Identity(ctx context.Context) (addrInfo *peer.AddrInfo, er return addrInfo, nil } +// FetchAndSetBlobSchedule fetches the BLOB_SCHEDULE from Prysm's spec endpoint +// and sets it in the params configuration to ensure correct fork digest calculation for BPO. +func (p *PrysmClient) FetchAndSetBlobSchedule(ctx context.Context) error { + ctx, cancel := context.WithTimeout(ctx, p.timeout) + defer cancel() + + specResp, err := p.beaconApiClient.GetConfigSpec(ctx) + if err != nil { + return fmt.Errorf("failed fetching config spec: %w", err) + } + + // Type assert Data to map[string]interface{} + specData, ok := specResp.Data.(map[string]interface{}) + if !ok { + return fmt.Errorf("unexpected spec response data type: %T", specResp.Data) + } + + // Check if BLOB_SCHEDULE exists in the spec, if no BLOB_SCHEDULE + // that means we're not on a BPO-enabled network. + blobScheduleRaw, exists := specData["BLOB_SCHEDULE"] + if !exists { + return nil + } + + // Parse the BLOB_SCHEDULE. + var blobScheduleData []struct { + Epoch string `json:"EPOCH"` + MaxBlobsPerBlock string `json:"MAX_BLOBS_PER_BLOCK"` + } + + switch v := blobScheduleRaw.(type) { + case string: + if err := json.Unmarshal([]byte(v), &blobScheduleData); err != nil { + return fmt.Errorf("failed parsing BLOB_SCHEDULE string: %w", err) + } + case []interface{}: + jsonBytes, err := json.Marshal(v) + if err != nil { + return fmt.Errorf("failed marshaling BLOB_SCHEDULE array: %w", err) + } + + if err := json.Unmarshal(jsonBytes, &blobScheduleData); err != nil { + return fmt.Errorf("failed parsing BLOB_SCHEDULE array: %w", err) + } + default: + return fmt.Errorf("BLOB_SCHEDULE has unexpected type: %T", blobScheduleRaw) + } + + // Convert to BlobScheduleEntry format. + blobSchedule := make([]params.BlobScheduleEntry, len(blobScheduleData)) + for i, entry := range blobScheduleData { + epoch, err := strconv.ParseUint(entry.Epoch, 10, 64) + if err != nil { + return fmt.Errorf("failed parsing EPOCH %s: %w", entry.Epoch, err) + } + + maxBlobs, err := strconv.ParseUint(entry.MaxBlobsPerBlock, 10, 64) + if err != nil { + return fmt.Errorf("failed parsing MAX_BLOBS_PER_BLOCK %s: %w", entry.MaxBlobsPerBlock, err) + } + + blobSchedule[i] = params.BlobScheduleEntry{ + Epoch: primitives.Epoch(epoch), + MaxBlobsPerBlock: maxBlobs, + } + } + + // Update the beacon config with the BlobSchedule + set GenesisValidatorsRoot. + // This gives us the correct details for InitializeForkSchedule(). + config := params.BeaconConfig().Copy() + config.BlobSchedule = blobSchedule + copy(config.GenesisValidatorsRoot[:], p.genesis.GenesisValidatorRoot) + config.InitializeForkSchedule() + + // Override the config with updated BlobSchedule. + params.OverrideBeaconConfig(config) + + return nil +} + func (p *PrysmClient) getActiveValidatorCount(ctx context.Context) (activeVals uint64, err error) { ctx, span := p.tracer.Start(ctx, "prysm_client.active_validators") defer func() { @@ -369,16 +450,19 @@ func (p *PrysmClient) isOnNetwork(ctx context.Context, hermesForkDigest [4]byte) }() // this checks whether the local fork_digest at hermes matches the one that the remote node keeps - // request the genesis - nodeFork, err := p.beaconApiClient.GetFork(ctx, apiCli.StateOrBlockId("head")) + // Get the chain head to determine the current epoch + chainHead, err := p.ChainHead(ctx) if err != nil { - return false, fmt.Errorf("request beacon fork to compose forkdigest: %w", err) + return false, fmt.Errorf("get chain head: %w", err) } - forkDigest, err := signing.ComputeForkDigest(nodeFork.CurrentVersion, p.genesis.GenesisValidatorRoot) - if err != nil { - return false, fmt.Errorf("create fork digest (%s, %x): %w", hex.EncodeToString(nodeFork.CurrentVersion), p.genesis.GenesisValidatorRoot, err) - } + // Calculate the current epoch from the head slot + currentEpoch := slots.ToEpoch(chainHead.HeadSlot) + + // We *must* use the current epoch from chain head, not the fork activation + // epoch in-order for our fork digests to be valid. + forkDigest := params.ForkDigest(currentEpoch) + // check if our version is within the versions of the node if forkDigest == hermesForkDigest { return true, nil diff --git a/eth/pubsub.go b/eth/pubsub.go index 9d4d648..ef3368b 100644 --- a/eth/pubsub.go +++ b/eth/pubsub.go @@ -137,6 +137,8 @@ func (p *PubSub) mapPubSubTopicWithHandlers(topic string) host.TopicHandler { return p.handleBlsToExecutionChangeMessage case strings.Contains(topic, p2p.GossipBlobSidecarMessage): return p.handleBlobSidecar + case strings.Contains(topic, p2p.GossipDataColumnSidecarMessage): + return p.handleDataColumnSidecar default: return p.host.TracedTopicHandler(host.NoopHandler) } @@ -184,6 +186,8 @@ func (p *PubSub) handleBeaconBlock(ctx context.Context, msg *pubsub.Message) err block = ðtypes.SignedBeaconBlockDeneb{} case ElectraForkVersion: block = ðtypes.SignedBeaconBlockElectra{} + case FuluForkVersion: + block = ðtypes.SignedBeaconBlockFulu{} default: return fmt.Errorf("handleBeaconBlock(): unrecognized fork-version: %s", p.cfg.ForkVersion.String()) } @@ -222,10 +226,12 @@ func (p *PubSub) handleAttestation(ctx context.Context, msg *pubsub.Message) err ) switch p.cfg.ForkVersion { - case ElectraForkVersion: + case Phase0ForkVersion, AltairForkVersion, BellatrixForkVersion, CapellaForkVersion, DenebForkVersion: + evt, err = p.dsr.RenderPayload(evt, msg, ðtypes.Attestation{}) + case ElectraForkVersion, FuluForkVersion: evt, err = p.dsr.RenderPayload(evt, msg, ðtypes.SingleAttestation{}) default: - evt, err = p.dsr.RenderPayload(evt, msg, ðtypes.Attestation{}) + return fmt.Errorf("handleAttestation(): unrecognized fork-version: %x", p.cfg.ForkVersion) } if err != nil { @@ -261,10 +267,12 @@ func (p *PubSub) handleAggregateAndProof(ctx context.Context, msg *pubsub.Messag ) switch p.cfg.ForkVersion { - case ElectraForkVersion: + case Phase0ForkVersion, AltairForkVersion, BellatrixForkVersion, CapellaForkVersion, DenebForkVersion: + evt, err = p.dsr.RenderPayload(evt, msg, ðtypes.SignedAggregateAttestationAndProof{}) + case ElectraForkVersion, FuluForkVersion: evt, err = p.dsr.RenderPayload(evt, msg, ðtypes.SignedAggregateAttestationAndProofElectra{}) default: - evt, err = p.dsr.RenderPayload(evt, msg, ðtypes.SignedAggregateAttestationAndProof{}) + return fmt.Errorf("handleAggregateAndProof(): unrecognized fork-version: %x", p.cfg.ForkVersion) } if err != nil { @@ -499,7 +507,7 @@ func (p *PubSub) handleBlobSidecar(ctx context.Context, msg *pubsub.Message) err ) switch p.cfg.ForkVersion { - case DenebForkVersion, ElectraForkVersion: + case DenebForkVersion, ElectraForkVersion, FuluForkVersion: blob := ethtypes.BlobSidecar{} evt, err = p.dsr.RenderPayload(evt, msg, &blob) @@ -522,3 +530,38 @@ func (p *PubSub) handleBlobSidecar(ctx context.Context, msg *pubsub.Message) err return nil } + +func (p *PubSub) handleDataColumnSidecar(ctx context.Context, msg *pubsub.Message) error { + if msg == nil || msg.Topic == nil || *msg.Topic == "" { + return fmt.Errorf("handleDataColumnSidecar(): nil message or topic") + } + + var ( + err error + evt = &host.TraceEvent{ + Type: eventTypeHandleMessage, + Topic: msg.GetTopic(), + PeerID: p.host.ID(), + Timestamp: time.Now(), + } + ) + + sidecar := ethtypes.DataColumnSidecar{} + + evt, err = p.dsr.RenderPayload(evt, msg, &sidecar) + if err != nil { + slog.Warn( + "failed rendering topic handler event", "topic", msg.GetTopic(), "err", tele.LogAttrError(err), + ) + + return nil + } + + if err := p.cfg.DataStream.PutRecord(ctx, evt); err != nil { + slog.Warn( + "failed putting topic handler event", "topic", msg.GetTopic(), "err", tele.LogAttrError(err), + ) + } + + return nil +} diff --git a/eth/reqresp.go b/eth/reqresp.go index 2ff6bec..3568829 100644 --- a/eth/reqresp.go +++ b/eth/reqresp.go @@ -18,10 +18,12 @@ import ( "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/encoder" "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/types" psync "github.com/OffchainLabs/prysm/v6/beacon-chain/sync" + "github.com/OffchainLabs/prysm/v6/config/params" "github.com/OffchainLabs/prysm/v6/consensus-types/blocks" "github.com/OffchainLabs/prysm/v6/consensus-types/interfaces" "github.com/OffchainLabs/prysm/v6/consensus-types/primitives" pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1" + "github.com/OffchainLabs/prysm/v6/time/slots" ssz "github.com/ferranbt/fastssz" "github.com/libp2p/go-libp2p/core" "github.com/libp2p/go-libp2p/core/host" @@ -49,6 +51,10 @@ type ReqRespConfig struct { ReadTimeout time.Duration WriteTimeout time.Duration + // Fork configuration for version-aware decisions + BeaconConfig *params.BeaconChainConfig + GenesisConfig *GenesisConfig + // Telemetry accessors Tracer trace.Tracer Meter metric.Meter @@ -61,12 +67,12 @@ type ReqResp struct { cfg *ReqRespConfig delegate peer.ID // peer ID that we delegate requests to - metaDataMu sync.RWMutex - metaData *pb.MetaDataV1 + metaDataMu sync.RWMutex + metadataHolder *MetadataHolder - statusMu sync.RWMutex - status *pb.Status - statusLim *rate.Limiter + statusMu sync.RWMutex + statusHolder *StatusHolder + statusLim *rate.Limiter // metrics meterRequestCounter metric.Int64Counter @@ -81,22 +87,82 @@ func NewReqResp(h host.Host, cfg *ReqRespConfig) (*ReqResp, error) { return nil, fmt.Errorf("req resp server config must not be nil") } - md := &pb.MetaDataV1{ - SeqNumber: 0, - Attnets: BitArrayFromAttestationSubnets(cfg.AttestationSubnetConfig.Subnets), - Syncnets: BitArrayFromSyncSubnets(cfg.SyncSubnetConfig.Subnets), + // Determine metadata version based on fork + metadataHolder := &MetadataHolder{} + attnets := BitArrayFromAttestationSubnets(cfg.AttestationSubnetConfig.Subnets) + + // Determine which metadata version to use based on fork configuration + var metadataVersion string + if cfg.BeaconConfig != nil && cfg.GenesisConfig != nil { + currentSlot := slots.CurrentSlot(cfg.GenesisConfig.GenesisTime) + currentEpoch := slots.ToEpoch(currentSlot) + + // Check for Fulu fork (V2 metadata with custody group count) + if cfg.BeaconConfig.FuluForkEpoch != params.BeaconConfig().FarFutureEpoch && + currentEpoch >= cfg.BeaconConfig.FuluForkEpoch { + // Fulu or later - use MetaDataV2 + md := &pb.MetaDataV2{ + SeqNumber: 0, + Attnets: attnets, + Syncnets: BitArrayFromSyncSubnets(cfg.SyncSubnetConfig.Subnets), + CustodyGroupCount: 0, // TODO: Get actual custody group count from config + } + metadataHolder.SetV2(md) + metadataVersion = "V2" + slog.Info("Composed local MetaData V2", + "attnets", md.Attnets, + "syncnets", md.Syncnets, + "custody_group_count", md.CustodyGroupCount, + ) + } else if cfg.BeaconConfig.AltairForkEpoch != params.BeaconConfig().FarFutureEpoch && + currentEpoch >= cfg.BeaconConfig.AltairForkEpoch { + // Altair or later - use MetaDataV1 (with syncnets) + md := &pb.MetaDataV1{ + SeqNumber: 0, + Attnets: attnets, + Syncnets: BitArrayFromSyncSubnets(cfg.SyncSubnetConfig.Subnets), + } + metadataHolder.SetV1(md) + metadataVersion = "V1" + slog.Info("Composed local MetaData V1", + "attnets", md.Attnets, + "syncnets", md.Syncnets, + ) + } else { + // Pre-Altair - use MetaDataV0 (no syncnets) + md := &pb.MetaDataV0{ + SeqNumber: 0, + Attnets: attnets, + } + metadataHolder.SetV0(md) + metadataVersion = "V0" + slog.Info("Composed local MetaData V0", + "attnets", md.Attnets, + ) + } + } else { + // Default to V1 if no fork config available (for backward compatibility) + md := &pb.MetaDataV1{ + SeqNumber: 0, + Attnets: attnets, + Syncnets: BitArrayFromSyncSubnets(cfg.SyncSubnetConfig.Subnets), + } + metadataHolder.SetV1(md) + metadataVersion = "V1 (default)" + slog.Info("Composed local MetaData V1 (default, no fork config)", + "attnets", md.Attnets, + "syncnets", md.Syncnets, + ) } - slog.Info("Composed local MetaData", - "attnets", md.Attnets, - "syncnets", md.Syncnets, - ) + slog.Info("Initialized ReqResp with metadata version", "version", metadataVersion) p := &ReqResp{ - host: h, - cfg: cfg, - metaData: md, - statusLim: rate.NewLimiter(1, 5), + host: h, + cfg: cfg, + metadataHolder: metadataHolder, + statusHolder: &StatusHolder{}, + statusLim: rate.NewLimiter(1, 5), } var err error @@ -128,62 +194,214 @@ func (r *ReqResp) SetMetaData(seq uint64) { r.metaDataMu.Lock() defer r.metaDataMu.Unlock() - if r.metaData.SeqNumber > seq { - slog.Warn("Updated metadata with lower sequence number", "old", r.metaData.SeqNumber, "new", seq) + currentSeq := r.metadataHolder.SeqNumber() + if currentSeq > seq { + slog.Warn("Updated metadata with lower sequence number", "old", currentSeq, "new", seq) } - r.metaData = &pb.MetaDataV1{ - SeqNumber: seq, - Attnets: r.metaData.Attnets, - Syncnets: r.metaData.Syncnets, + // Preserve existing subnet information + attnets := r.metadataHolder.Attnets() + syncnets, hasSyncnets := r.metadataHolder.Syncnets() + + if hasSyncnets { + r.metadataHolder.SetV1(&pb.MetaDataV1{ + SeqNumber: seq, + Attnets: attnets, + Syncnets: syncnets, + }) + } else { + // Fall back to V0 if no syncnets + r.metadataHolder.SetV0(&pb.MetaDataV0{ + SeqNumber: seq, + Attnets: attnets, + }) } } -func (r *ReqResp) SetStatus(status *pb.Status) { +// SetMetaDataV2 sets metadata with custody group count for DAS +func (r *ReqResp) SetMetaDataV2(seq uint64, custodyGroupCount uint64) { + r.metaDataMu.Lock() + defer r.metaDataMu.Unlock() + + currentSeq := r.metadataHolder.SeqNumber() + if currentSeq > seq { + slog.Warn("Updated metadata with lower sequence number", "old", currentSeq, "new", seq) + } + + // Preserve existing subnet information + attnets := r.metadataHolder.Attnets() + syncnets, _ := r.metadataHolder.Syncnets() + + r.metadataHolder.SetV2(&pb.MetaDataV2{ + SeqNumber: seq, + Attnets: attnets, + Syncnets: syncnets, + CustodyGroupCount: custodyGroupCount, + }) +} + +// SetStatusV1 sets the V1 status +func (r *ReqResp) SetStatusV1(status *pb.Status) { r.statusMu.Lock() defer r.statusMu.Unlock() // if the ForkDigest is not the same, we should drop updating the local status // TODO: this might be re-checked for hardforks (make the client resilient to them) - if r.status != nil && !bytes.Equal(r.status.ForkDigest, status.ForkDigest) { + if r.statusHolder.ForkDigest() != nil && !bytes.Equal(r.statusHolder.ForkDigest(), status.ForkDigest) { return } // check if anything has changed. Prevents the below log message to pollute // the log output. - if r.status != nil && bytes.Equal(r.status.ForkDigest, status.ForkDigest) && - bytes.Equal(r.status.FinalizedRoot, status.FinalizedRoot) && - r.status.FinalizedEpoch == status.FinalizedEpoch && - bytes.Equal(r.status.HeadRoot, status.HeadRoot) && - r.status.HeadSlot == status.HeadSlot { + if r.statusHolder.GetV1() != nil && bytes.Equal(r.statusHolder.ForkDigest(), status.ForkDigest) && + bytes.Equal(r.statusHolder.FinalizedRoot(), status.FinalizedRoot) && + r.statusHolder.FinalizedEpoch() == status.FinalizedEpoch && + bytes.Equal(r.statusHolder.HeadRoot(), status.HeadRoot) && + r.statusHolder.HeadSlot() == status.HeadSlot { // nothing has changed -> return return } - slog.Info("New status:") + slog.Info("New status V1:") + slog.Info(" fork_digest: " + hex.EncodeToString(status.ForkDigest)) + slog.Info(" finalized_root: " + hex.EncodeToString(status.FinalizedRoot)) + slog.Info(" finalized_epoch: " + strconv.FormatUint(uint64(status.FinalizedEpoch), 10)) + slog.Info(" head_root: " + hex.EncodeToString(status.HeadRoot)) + slog.Info(" head_slot: " + strconv.FormatUint(uint64(status.HeadSlot), 10)) + + r.statusHolder.SetV1(status) +} + +// SetStatusV2 sets the V2 status +func (r *ReqResp) SetStatusV2(status *pb.StatusV2) { + r.statusMu.Lock() + defer r.statusMu.Unlock() + + // if the ForkDigest is not the same, we should drop updating the local status + // TODO: this might be re-checked for hardforks (make the client resilient to them) + if r.statusHolder.ForkDigest() != nil && !bytes.Equal(r.statusHolder.ForkDigest(), status.ForkDigest) { + return + } + + // check if anything has changed. Prevents the below log message to pollute + // the log output. + if r.statusHolder.GetV2() != nil && bytes.Equal(r.statusHolder.ForkDigest(), status.ForkDigest) && + bytes.Equal(r.statusHolder.FinalizedRoot(), status.FinalizedRoot) && + r.statusHolder.FinalizedEpoch() == status.FinalizedEpoch && + bytes.Equal(r.statusHolder.HeadRoot(), status.HeadRoot) && + r.statusHolder.HeadSlot() == status.HeadSlot { + // Check V2-specific fields + if earliestSlot, hasEarliestSlot := r.statusHolder.EarliestAvailableSlot(); hasEarliestSlot && + earliestSlot == status.EarliestAvailableSlot { + // nothing has changed -> return + return + } + } + + slog.Info("New status V2:") slog.Info(" fork_digest: " + hex.EncodeToString(status.ForkDigest)) slog.Info(" finalized_root: " + hex.EncodeToString(status.FinalizedRoot)) slog.Info(" finalized_epoch: " + strconv.FormatUint(uint64(status.FinalizedEpoch), 10)) slog.Info(" head_root: " + hex.EncodeToString(status.HeadRoot)) slog.Info(" head_slot: " + strconv.FormatUint(uint64(status.HeadSlot), 10)) + slog.Info(" earliest_available_slot: " + strconv.FormatUint(uint64(status.EarliestAvailableSlot), 10)) - r.status = status + r.statusHolder.SetV2(status) } -func (r *ReqResp) cpyStatus() *pb.Status { +// SetStatus is deprecated - use SetStatusV1 or SetStatusV2 instead +// Kept for backward compatibility +func (r *ReqResp) SetStatus(status *pb.Status) { + r.SetStatusV1(status) +} + +// cpyStatusV1 returns a copy of the V1 status +func (r *ReqResp) cpyStatusV1() *pb.Status { r.statusMu.RLock() defer r.statusMu.RUnlock() - if r.status == nil { + if r.statusHolder == nil || r.statusHolder.GetV1() == nil { return nil } + status := r.statusHolder.GetV1() return &pb.Status{ - ForkDigest: bytes.Clone(r.status.ForkDigest), - FinalizedRoot: bytes.Clone(r.status.FinalizedRoot), - FinalizedEpoch: r.status.FinalizedEpoch, - HeadRoot: bytes.Clone(r.status.HeadRoot), - HeadSlot: r.status.HeadSlot, + ForkDigest: bytes.Clone(status.ForkDigest), + FinalizedRoot: bytes.Clone(status.FinalizedRoot), + FinalizedEpoch: status.FinalizedEpoch, + HeadRoot: bytes.Clone(status.HeadRoot), + HeadSlot: status.HeadSlot, + } +} + +// cpyStatusV2 returns a copy of the V2 status +func (r *ReqResp) cpyStatusV2() *pb.StatusV2 { + r.statusMu.RLock() + defer r.statusMu.RUnlock() + + if r.statusHolder == nil || r.statusHolder.GetV2() == nil { + return nil + } + + status := r.statusHolder.GetV2() + return &pb.StatusV2{ + ForkDigest: bytes.Clone(status.ForkDigest), + FinalizedRoot: bytes.Clone(status.FinalizedRoot), + FinalizedEpoch: status.FinalizedEpoch, + HeadRoot: bytes.Clone(status.HeadRoot), + HeadSlot: status.HeadSlot, + EarliestAvailableSlot: status.EarliestAvailableSlot, + } +} + +// cpyMetadataV0 returns a copy of the V0 metadata +func (r *ReqResp) cpyMetadataV0() *pb.MetaDataV0 { + r.metaDataMu.RLock() + defer r.metaDataMu.RUnlock() + + if r.metadataHolder == nil || r.metadataHolder.GetV0() == nil { + return nil + } + + md := r.metadataHolder.GetV0() + return &pb.MetaDataV0{ + SeqNumber: md.SeqNumber, + Attnets: md.Attnets, + } +} + +// cpyMetadataV1 returns a copy of the V1 metadata +func (r *ReqResp) cpyMetadataV1() *pb.MetaDataV1 { + r.metaDataMu.RLock() + defer r.metaDataMu.RUnlock() + + if r.metadataHolder == nil || r.metadataHolder.GetV1() == nil { + return nil + } + + md := r.metadataHolder.GetV1() + return &pb.MetaDataV1{ + SeqNumber: md.SeqNumber, + Attnets: md.Attnets, + Syncnets: md.Syncnets, + } +} + +// cpyMetadataV2 returns a copy of the V2 metadata +func (r *ReqResp) cpyMetadataV2() *pb.MetaDataV2 { + r.metaDataMu.RLock() + defer r.metaDataMu.RUnlock() + + if r.metadataHolder == nil || r.metadataHolder.GetV2() == nil { + return nil + } + + md := r.metadataHolder.GetV2() + return &pb.MetaDataV2{ + SeqNumber: md.SeqNumber, + Attnets: md.Attnets, + Syncnets: md.Syncnets, + CustodyGroupCount: md.CustodyGroupCount, } } @@ -193,13 +411,13 @@ func (r *ReqResp) cpyStatus() *pb.Status { func (r *ReqResp) RegisterHandlers(ctx context.Context) error { r.statusMu.RLock() defer r.statusMu.RUnlock() - if r.status == nil { + if r.statusHolder == nil || (r.statusHolder.GetV1() == nil && r.statusHolder.GetV2() == nil) { return fmt.Errorf("chain status is nil") } r.metaDataMu.RLock() defer r.metaDataMu.RUnlock() - if r.metaData == nil { + if r.metadataHolder == nil || (r.metadataHolder.GetV0() == nil && r.metadataHolder.GetV1() == nil && r.metadataHolder.GetV2() == nil) { return fmt.Errorf("chain metadata is nil") } @@ -207,8 +425,10 @@ func (r *ReqResp) RegisterHandlers(ctx context.Context) error { p2p.RPCPingTopicV1: r.pingHandler, p2p.RPCGoodByeTopicV1: r.goodbyeHandler, p2p.RPCStatusTopicV1: r.statusHandler, + p2p.RPCStatusTopicV2: r.statusV2Handler, p2p.RPCMetaDataTopicV1: r.metadataV1Handler, p2p.RPCMetaDataTopicV2: r.metadataV2Handler, + p2p.RPCMetaDataTopicV3: r.metadataV3Handler, p2p.RPCBlocksByRangeTopicV2: r.blocksByRangeV2Handler, p2p.RPCBlocksByRootTopicV2: r.blocksByRootV2Handler, p2p.RPCBlobSidecarsByRangeTopicV1: r.blobsByRangeV2Handler, @@ -311,7 +531,7 @@ func (r *ReqResp) pingHandler(ctx context.Context, stream network.Stream) (map[s } r.metaDataMu.RLock() - sq := primitives.SSZUint64(r.metaData.SeqNumber) + sq := primitives.SSZUint64(r.metadataHolder.SeqNumber()) r.metaDataMu.RUnlock() if err := r.writeResponse(ctx, stream, &sq); err != nil { @@ -396,7 +616,7 @@ func (r *ReqResp) statusHandler(ctx context.Context, upstream network.Stream) (m } // update status - r.SetStatus(resp) + r.SetStatusV1(resp) // mirror its own status back if err := r.writeResponse(ctx, upstream, resp); err != nil { @@ -418,7 +638,7 @@ func (r *ReqResp) statusHandler(ctx context.Context, upstream network.Stream) (m } // create response status from memory status - resp := r.cpyStatus() + resp := r.cpyStatusV1() // if the rate limiter allows requesting a new status, do that. if r.statusLim.Allow() { @@ -436,7 +656,7 @@ func (r *ReqResp) statusHandler(ctx context.Context, upstream network.Stream) (m // asking for the latest status failed. Use our own latest known status slog.Warn("Downstream status request failed, using the latest known status") - statusCpy := r.cpyStatus() + statusCpy := r.cpyStatusV1() if err := r.writeResponse(ctx, upstream, statusCpy); err != nil { return nil, fmt.Errorf("write mirrored status response to delegate: %w", err) } @@ -450,7 +670,7 @@ func (r *ReqResp) statusHandler(ctx context.Context, upstream network.Stream) (m } // we got a valid response from our delegate node. Update our own status - r.SetStatus(resp) + r.SetStatusV1(resp) } // let the upstream peer (who initiated the request) know the latest status @@ -467,12 +687,25 @@ func (r *ReqResp) statusHandler(ctx context.Context, upstream network.Stream) (m } func (r *ReqResp) metadataV1Handler(ctx context.Context, stream network.Stream) (map[string]any, error) { - r.metaDataMu.RLock() - metaData := &pb.MetaDataV0{ - SeqNumber: r.metaData.SeqNumber, - Attnets: r.metaData.Attnets, + metaData := r.cpyMetadataV0() + if metaData == nil { + // Try to downgrade from V1 or V2 + r.metaDataMu.RLock() + if r.metadataHolder.GetV1() != nil { + md := r.metadataHolder.GetV1() + metaData = &pb.MetaDataV0{ + SeqNumber: md.SeqNumber, + Attnets: md.Attnets, + } + } else if r.metadataHolder.GetV2() != nil { + md := r.metadataHolder.GetV2() + metaData = &pb.MetaDataV0{ + SeqNumber: md.SeqNumber, + Attnets: md.Attnets, + } + } + r.metaDataMu.RUnlock() } - r.metaDataMu.RUnlock() if err := r.writeResponse(ctx, stream, metaData); err != nil { return nil, fmt.Errorf("write meta data v1: %w", err) @@ -491,13 +724,27 @@ func (r *ReqResp) metadataV1Handler(ctx context.Context, stream network.Stream) } func (r *ReqResp) metadataV2Handler(ctx context.Context, stream network.Stream) (map[string]any, error) { - r.metaDataMu.RLock() - metaData := &pb.MetaDataV1{ - SeqNumber: r.metaData.SeqNumber, - Attnets: r.metaData.Attnets, - Syncnets: r.metaData.Syncnets, + metaData := r.cpyMetadataV1() + if metaData == nil { + // Try to downgrade from V2 or upgrade from V0 + r.metaDataMu.RLock() + if r.metadataHolder.GetV2() != nil { + md := r.metadataHolder.GetV2() + metaData = &pb.MetaDataV1{ + SeqNumber: md.SeqNumber, + Attnets: md.Attnets, + Syncnets: md.Syncnets, + } + } else if r.metadataHolder.GetV0() != nil { + md := r.metadataHolder.GetV0() + metaData = &pb.MetaDataV1{ + SeqNumber: md.SeqNumber, + Attnets: md.Attnets, + Syncnets: nil, // V0 doesn't have syncnets + } + } + r.metaDataMu.RUnlock() } - r.metaDataMu.RUnlock() if err := r.writeResponse(ctx, stream, metaData); err != nil { return nil, fmt.Errorf("write meta data v2: %w", err) @@ -516,6 +763,164 @@ func (r *ReqResp) metadataV2Handler(ctx context.Context, stream network.Stream) return traceData, stream.Close() } +// statusV2Handler handles StatusV2 protocol requests +func (r *ReqResp) statusV2Handler(ctx context.Context, upstream network.Stream) (map[string]any, error) { + statusTraceData := func(status *pb.StatusV2) map[string]any { + return map[string]any{ + "ForkDigest": hex.EncodeToString(status.ForkDigest), + "HeadRoot": hex.EncodeToString(status.HeadRoot), + "HeadSlot": status.HeadSlot, + "FinalizedRoot": hex.EncodeToString(status.FinalizedRoot), + "FinalizedEpoch": status.FinalizedEpoch, + "EarliestAvailableSlot": status.EarliestAvailableSlot, + } + } + + // check if the request comes from our delegate node. If so, just mirror + // its own status back and update our latest known status. + if upstream.Conn().RemotePeer() == r.delegate { + resp := &pb.StatusV2{} + if err := r.readRequest(ctx, upstream, resp); err != nil { + return nil, fmt.Errorf("read status V2 data from delegate: %w", err) + } + + // update status + r.SetStatusV2(resp) + + // mirror its own status back + if err := r.writeResponse(ctx, upstream, resp); err != nil { + return nil, fmt.Errorf("write mirrored status V2 response to delegate: %w", err) + } + + traceData := map[string]any{ + "Request": statusTraceData(resp), + "Response": statusTraceData(resp), + } + + return traceData, upstream.Close() + } + + // first, read the status from the remote peer + req := &pb.StatusV2{} + if err := r.readRequest(ctx, upstream, req); err != nil { + return nil, fmt.Errorf("read status V2 data from peer: %w", err) + } + + // create response status from memory status + resp := r.cpyStatusV2() + + // if the rate limiter allows requesting a new status, do that. + if r.statusLim.Allow() { + r.statusLim.Reserve() + + // ask our delegate node for the latest status + dialCtx := network.WithForceDirectDial(ctx, "prevent backoff") + var err error + resp, err = r.StatusV2(dialCtx, r.delegate) + if err != nil { + // asking for the latest status failed. Use our own latest known status + slog.Warn("Downstream status V2 request failed, using the latest known status") + + statusCpy := r.cpyStatusV2() + if statusCpy == nil { + // Try to upgrade from V1 if we don't have V2 + if v1 := r.cpyStatusV1(); v1 != nil { + statusCpy = &pb.StatusV2{ + ForkDigest: v1.ForkDigest, + FinalizedRoot: v1.FinalizedRoot, + FinalizedEpoch: v1.FinalizedEpoch, + HeadRoot: v1.HeadRoot, + HeadSlot: v1.HeadSlot, + EarliestAvailableSlot: 0, + } + } + } + + if statusCpy != nil { + if err := r.writeResponse(ctx, upstream, statusCpy); err != nil { + return nil, fmt.Errorf("write status V2 response to peer: %w", err) + } + + traceData := map[string]any{ + "Request": statusTraceData(req), + "Response": statusTraceData(statusCpy), + } + + return traceData, upstream.Close() + } + return nil, fmt.Errorf("no status available") + } + + // we got a valid response from our delegate node. Update our own status + r.SetStatusV2(resp) + } + + // let the upstream peer (who initiated the request) know the latest status + if err := r.writeResponse(ctx, upstream, resp); err != nil { + return nil, fmt.Errorf("respond status V2 to upstream: %w", err) + } + + traceData := map[string]any{ + "Request": statusTraceData(req), + "Response": statusTraceData(resp), + } + + return traceData, nil +} + +// metadataV3Handler handles MetadataV3 protocol requests (returns MetaDataV2 type) +func (r *ReqResp) metadataV3Handler(ctx context.Context, stream network.Stream) (map[string]any, error) { + metaData := r.cpyMetadataV2() + if metaData == nil { + // Try to upgrade from V1 or V0 + r.metaDataMu.RLock() + if r.metadataHolder.GetV1() != nil { + md := r.metadataHolder.GetV1() + metaData = &pb.MetaDataV2{ + SeqNumber: md.SeqNumber, + Attnets: md.Attnets, + Syncnets: md.Syncnets, + CustodyGroupCount: 0, // Default to 0 when upgrading + } + } else if r.metadataHolder.GetV0() != nil { + md := r.metadataHolder.GetV0() + metaData = &pb.MetaDataV2{ + SeqNumber: md.SeqNumber, + Attnets: md.Attnets, + Syncnets: nil, // V0 doesn't have syncnets + CustodyGroupCount: 0, // Default to 0 when upgrading + } + } + r.metaDataMu.RUnlock() + } + + if metaData == nil { + return nil, fmt.Errorf("no metadata available") + } + + if err := r.writeResponse(ctx, stream, metaData); err != nil { + return nil, fmt.Errorf("write meta data v3: %w", err) + } + + traceData := map[string]any{ + "SeqNumber": metaData.SeqNumber, + "Attnets": hex.EncodeToString(metaData.Attnets.Bytes()), + "CustodyGroupCount": metaData.CustodyGroupCount, + } + + if metaData.Syncnets != nil { + traceData["Syncnets"] = hex.EncodeToString(metaData.Syncnets.Bytes()) + } + + slog.Info( + "metadata V3 response", + "attnets", metaData.Attnets, + "synccommittees", metaData.Syncnets, + "custody_group_count", metaData.CustodyGroupCount, + ) + return traceData, stream.Close() +} + func (r *ReqResp) blocksByRangeV2Handler(ctx context.Context, stream network.Stream) (map[string]any, error) { if stream.Conn().RemotePeer() == r.delegate { return nil, fmt.Errorf("blocks by range request from delegate peer") @@ -600,6 +1005,7 @@ func (r *ReqResp) delegateStream(ctx context.Context, upstream network.Stream) e return nil } +// Status requests V1 status from a peer func (r *ReqResp) Status(ctx context.Context, pid peer.ID) (status *pb.Status, err error) { defer func() { av, err := r.host.Peerstore().Get(pid, "AgentVersion") @@ -642,7 +1048,7 @@ func (r *ReqResp) Status(ctx context.Context, pid peer.ID) (status *pb.Status, e r.meterRequestCounter.Add(traceCtx, 1, metric.WithAttributes(attrs...)) }() - slog.Info("Perform status request", tele.LogAttrPeerID(pid)) + slog.Info("Perform status V1 request", tele.LogAttrPeerID(pid)) stream, err := r.host.NewStream(ctx, pid, r.protocolID(p2p.RPCStatusTopicV1)) if err != nil { return nil, fmt.Errorf("new stream to peer %s: %w", pid, err) @@ -650,9 +1056,21 @@ func (r *ReqResp) Status(ctx context.Context, pid peer.ID) (status *pb.Status, e defer logDeferErr(stream.Reset, "failed closing stream") // no-op if closed // actually write the data to the stream - req := r.cpyStatus() + req := r.cpyStatusV1() if req == nil { - return nil, fmt.Errorf("status unknown") + // Try to downgrade from V2 if we only have V2 + if r.statusHolder.IsV2() { + v2 := r.statusHolder.GetV2() + req = &pb.Status{ + ForkDigest: v2.ForkDigest, + FinalizedRoot: v2.FinalizedRoot, + FinalizedEpoch: v2.FinalizedEpoch, + HeadRoot: v2.HeadRoot, + HeadSlot: v2.HeadSlot, + } + } else { + return nil, fmt.Errorf("status unknown") + } } if err := r.writeRequest(ctx, stream, req); err != nil { @@ -667,7 +1085,98 @@ func (r *ReqResp) Status(ctx context.Context, pid peer.ID) (status *pb.Status, e // if we requested the status from our delegate if stream.Conn().RemotePeer() == r.delegate { - r.SetStatus(resp) + r.SetStatusV1(resp) + } + + // we have the data that we want, so ignore error here + _ = stream.Close() // (both sides should actually be already closed) + + return resp, nil +} + +// StatusV2 requests V2 status from a peer +func (r *ReqResp) StatusV2(ctx context.Context, pid peer.ID) (status *pb.StatusV2, err error) { + defer func() { + av, err := r.host.Peerstore().Get(pid, "AgentVersion") + if err != nil { + av = "unknown" + } + + reqData := map[string]any{ + "AgentVersion": av, + "PeerID": pid.String(), + } + if status != nil { + reqData["ForkDigest"] = hex.EncodeToString(status.ForkDigest) + reqData["HeadRoot"] = hex.EncodeToString(status.HeadRoot) + reqData["HeadSlot"] = status.HeadSlot + reqData["FinalizedRoot"] = hex.EncodeToString(status.FinalizedRoot) + reqData["FinalizedEpoch"] = status.FinalizedEpoch + reqData["EarliestAvailableSlot"] = status.EarliestAvailableSlot + } + + if err != nil { + reqData["Error"] = err.Error() + } + + traceEvt := &hermeshost.TraceEvent{ + Type: "REQUEST_STATUS", + PeerID: r.host.ID(), + Timestamp: time.Now(), + Payload: reqData, + } + + traceCtx := context.Background() + if err := r.cfg.DataStream.PutRecord(traceCtx, traceEvt); err != nil { + slog.Warn("failed to put record", tele.LogAttrError(err)) + } + + attrs := []attribute.KeyValue{ + attribute.String("rpc", "status_v2"), + attribute.Bool("success", err == nil), + } + r.meterRequestCounter.Add(traceCtx, 1, metric.WithAttributes(attrs...)) + }() + + slog.Info("Perform status V2 request", tele.LogAttrPeerID(pid)) + stream, err := r.host.NewStream(ctx, pid, r.protocolID(p2p.RPCStatusTopicV2)) + if err != nil { + return nil, fmt.Errorf("new stream to peer %s: %w", pid, err) + } + defer logDeferErr(stream.Reset, "failed closing stream") // no-op if closed + + // actually write the data to the stream + req := r.cpyStatusV2() + if req == nil { + // If we don't have V2, upgrade from V1 + if !r.statusHolder.IsV2() && r.statusHolder.GetV1() != nil { + v1 := r.statusHolder.GetV1() + req = &pb.StatusV2{ + ForkDigest: v1.ForkDigest, + FinalizedRoot: v1.FinalizedRoot, + FinalizedEpoch: v1.FinalizedEpoch, + HeadRoot: v1.HeadRoot, + HeadSlot: v1.HeadSlot, + EarliestAvailableSlot: 0, // Default to 0 if upgrading from V1 + } + } else { + return nil, fmt.Errorf("status unknown") + } + } + + if err := r.writeRequest(ctx, stream, req); err != nil { + return nil, fmt.Errorf("write status V2 request: %w", err) + } + + // read and decode status response + resp := &pb.StatusV2{} + if err := r.readResponse(ctx, stream, resp); err != nil { + return nil, fmt.Errorf("read status V2 response: %w", err) + } + + // if we requested the status from our delegate + if stream.Conn().RemotePeer() == r.delegate { + r.SetStatusV2(resp) } // we have the data that we want, so ignore error here @@ -706,7 +1215,7 @@ func (r *ReqResp) Ping(ctx context.Context, pid peer.ID) (err error) { defer logDeferErr(stream.Reset, "failed closing stream") // no-op if closed r.metaDataMu.RLock() - seqNum := r.metaData.SeqNumber + seqNum := r.metadataHolder.SeqNumber() r.metaDataMu.RUnlock() req := primitives.SSZUint64(seqNum) @@ -726,6 +1235,7 @@ func (r *ReqResp) Ping(ctx context.Context, pid peer.ID) (err error) { return nil } +// MetaData requests V1 metadata from a peer func (r *ReqResp) MetaData(ctx context.Context, pid peer.ID) (resp *pb.MetaDataV1, err error) { defer func() { reqData := map[string]any{ @@ -760,17 +1270,72 @@ func (r *ReqResp) MetaData(ctx context.Context, pid peer.ID) (resp *pb.MetaDataV r.meterRequestCounter.Add(traceCtx, 1, metric.WithAttributes(attrs...)) }() - slog.Debug("Perform metadata request", tele.LogAttrPeerID(pid)) + slog.Debug("Perform metadata V1 request", tele.LogAttrPeerID(pid)) stream, err := r.host.NewStream(ctx, pid, r.protocolID(p2p.RPCMetaDataTopicV2)) if err != nil { return resp, fmt.Errorf("new %s stream to peer %s: %w", p2p.RPCMetaDataTopicV2, pid, err) } defer logDeferErr(stream.Reset, "failed closing stream") // no-op if closed - // read and decode status response + // read and decode metadata response resp = &pb.MetaDataV1{} if err := r.readResponse(ctx, stream, resp); err != nil { - return resp, fmt.Errorf("read ping response: %w", err) + return resp, fmt.Errorf("read metadata response: %w", err) + } + + // we have the data that we want, so ignore error here + _ = stream.Close() // (both sides should actually be already closed) + + return resp, nil +} + +// MetaDataV2 requests V2 metadata from a peer (includes custody group count) +func (r *ReqResp) MetaDataV2(ctx context.Context, pid peer.ID) (resp *pb.MetaDataV2, err error) { + defer func() { + reqData := map[string]any{ + "PeerID": pid.String(), + } + + if resp != nil { + reqData["SeqNumber"] = resp.SeqNumber + reqData["Attnets"] = resp.Attnets + reqData["Syncnets"] = resp.Syncnets + reqData["CustodyGroupCount"] = resp.CustodyGroupCount + } + + if err != nil { + reqData["Error"] = err.Error() + } + + traceEvt := &hermeshost.TraceEvent{ + Type: "REQUEST_METADATA_V2", + PeerID: r.host.ID(), + Timestamp: time.Now(), + Payload: reqData, + } + traceCtx := context.Background() + if err := r.cfg.DataStream.PutRecord(traceCtx, traceEvt); err != nil { + slog.Warn("failed to put record", tele.LogAttrError(err)) + } + + attrs := []attribute.KeyValue{ + attribute.String("rpc", "meta_data_v2"), + attribute.Bool("success", err == nil), + } + r.meterRequestCounter.Add(traceCtx, 1, metric.WithAttributes(attrs...)) + }() + + slog.Debug("Perform metadata V2 request", tele.LogAttrPeerID(pid)) + stream, err := r.host.NewStream(ctx, pid, r.protocolID(p2p.RPCMetaDataTopicV3)) + if err != nil { + return resp, fmt.Errorf("new %s stream to peer %s: %w", p2p.RPCMetaDataTopicV3, pid, err) + } + defer logDeferErr(stream.Reset, "failed closing stream") // no-op if closed + + // read and decode metadata response + resp = &pb.MetaDataV2{} + if err := r.readResponse(ctx, stream, resp); err != nil { + return resp, fmt.Errorf("read metadata V2 response: %w", err) } // we have the data that we want, so ignore error here diff --git a/eth/reqresp_test.go b/eth/reqresp_test.go index 0e0cd67..da3bb52 100644 --- a/eth/reqresp_test.go +++ b/eth/reqresp_test.go @@ -8,7 +8,12 @@ import ( "github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing" "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/encoder" + "github.com/OffchainLabs/prysm/v6/config/params" + "github.com/OffchainLabs/prysm/v6/consensus-types/primitives" + pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1" "github.com/probe-lab/hermes/host" + "github.com/prysmaticlabs/go-bitfield" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel" ) @@ -32,7 +37,9 @@ func TestReqResp_ProtocolRequests(t *testing.T) { // try all the request as the node is initialized requestPing(t, ctx, ethNode) requestStatus(t, ctx, ethNode) + requestStatusV2(t, ctx, ethNode) requestMetaDataV2(t, ctx, ethNode) + requestMetaDataV3(t, ctx, ethNode) requestBlockByRangeV2(t, ctx, ethNode) } @@ -46,11 +53,21 @@ func requestStatus(t *testing.T, ctx context.Context, ethNode *Node) { require.NoError(t, err) } +func requestStatusV2(t *testing.T, ctx context.Context, ethNode *Node) { + _, err := ethNode.reqResp.StatusV2(ctx, ethNode.pryInfo.ID) + require.NoError(t, err) +} + func requestMetaDataV2(t *testing.T, ctx context.Context, ethNode *Node) { _, err := ethNode.reqResp.MetaData(ctx, ethNode.pryInfo.ID) require.NoError(t, err) } +func requestMetaDataV3(t *testing.T, ctx context.Context, ethNode *Node) { + _, err := ethNode.reqResp.MetaDataV2(ctx, ethNode.pryInfo.ID) + require.NoError(t, err) +} + func requestBlockByRangeV2(t *testing.T, ctx context.Context, ethNode *Node) { chainHead, err := ethNode.pryClient.ChainHead(ctx) require.NoError(t, err) @@ -113,3 +130,231 @@ func composeLocalEthNode(t *testing.T, ctx context.Context) (*Node, context.Canc }() return ethNode, cancel } + +// TestStatusHolder tests the StatusHolder version-aware wrapper +func TestStatusHolder(t *testing.T) { + holder := &StatusHolder{} + + // Test V1 status + statusV1 := &pb.Status{ + ForkDigest: []byte{1, 2, 3, 4}, + FinalizedRoot: []byte("finalized_root_v1"), + FinalizedEpoch: 100, + HeadRoot: []byte("head_root_v1"), + HeadSlot: 1000, + } + + holder.SetV1(statusV1) + assert.True(t, holder.GetV1() != nil) + assert.False(t, holder.IsV2()) + assert.Equal(t, statusV1.ForkDigest, holder.ForkDigest()) + assert.Equal(t, statusV1.FinalizedEpoch, holder.FinalizedEpoch()) + assert.Equal(t, statusV1.HeadSlot, holder.HeadSlot()) + + // Test V2 status + statusV2 := &pb.StatusV2{ + ForkDigest: []byte{5, 6, 7, 8}, + FinalizedRoot: []byte("finalized_root_v2"), + FinalizedEpoch: 200, + HeadRoot: []byte("head_root_v2"), + HeadSlot: 2000, + EarliestAvailableSlot: 1500, + } + + holder.SetV2(statusV2) + assert.True(t, holder.GetV2() != nil) + assert.True(t, holder.IsV2()) + assert.Nil(t, holder.GetV1()) // V1 should be cleared + assert.Equal(t, statusV2.ForkDigest, holder.ForkDigest()) + assert.Equal(t, statusV2.FinalizedEpoch, holder.FinalizedEpoch()) + assert.Equal(t, statusV2.HeadSlot, holder.HeadSlot()) + + // Test EarliestAvailableSlot + slot, hasSlot := holder.EarliestAvailableSlot() + assert.True(t, hasSlot) + assert.Equal(t, primitives.Slot(1500), slot) + + // Test with V1 (no earliest slot) + holder.SetV1(statusV1) + slot, hasSlot = holder.EarliestAvailableSlot() + assert.False(t, hasSlot) + assert.Equal(t, primitives.Slot(0), slot) +} + +// TestMetadataHolder tests the MetadataHolder version-aware wrapper +func TestMetadataHolder(t *testing.T) { + holder := &MetadataHolder{} + + // Test V0 metadata + metaV0 := &pb.MetaDataV0{ + SeqNumber: 1, + Attnets: bitfield.Bitvector64{0xFF, 0x00}, + } + + holder.SetV0(metaV0) + assert.NotNil(t, holder.GetV0()) + assert.Nil(t, holder.GetV1()) + assert.Nil(t, holder.GetV2()) + assert.Equal(t, 0, holder.Version()) + assert.Equal(t, uint64(1), holder.SeqNumber()) + assert.Equal(t, metaV0.Attnets, holder.Attnets()) + + // V0 doesn't have syncnets + syncnets, hasSyncnets := holder.Syncnets() + assert.False(t, hasSyncnets) + assert.Equal(t, bitfield.Bitvector4{}, syncnets) + + // Test V1 metadata + metaV1 := &pb.MetaDataV1{ + SeqNumber: 2, + Attnets: bitfield.Bitvector64{0xAA, 0xBB}, + Syncnets: bitfield.Bitvector4{0x0F}, + } + + holder.SetV1(metaV1) + assert.Nil(t, holder.GetV0()) // V0 should be cleared + assert.NotNil(t, holder.GetV1()) + assert.Nil(t, holder.GetV2()) + assert.Equal(t, 1, holder.Version()) + assert.Equal(t, uint64(2), holder.SeqNumber()) + + syncnets, hasSyncnets = holder.Syncnets() + assert.True(t, hasSyncnets) + assert.Equal(t, metaV1.Syncnets, syncnets) + + // Test V2 metadata + metaV2 := &pb.MetaDataV2{ + SeqNumber: 3, + Attnets: bitfield.Bitvector64{0xCC, 0xDD}, + Syncnets: bitfield.Bitvector4{0x0A}, + CustodyGroupCount: 16, + } + + holder.SetV2(metaV2) + assert.Nil(t, holder.GetV0()) + assert.Nil(t, holder.GetV1()) // V1 should be cleared + assert.NotNil(t, holder.GetV2()) + assert.Equal(t, 2, holder.Version()) + assert.Equal(t, uint64(3), holder.SeqNumber()) + + // Test CustodyGroupCount + count, hasCount := holder.CustodyGroupCount() + assert.True(t, hasCount) + assert.Equal(t, uint64(16), count) + + // Test with V1 (no custody group count) + holder.SetV1(metaV1) + count, hasCount = holder.CustodyGroupCount() + assert.False(t, hasCount) + assert.Equal(t, uint64(0), count) +} + +// TestForkAwareMetadataInit tests that ReqResp initializes metadata correctly based on fork +func TestForkAwareMetadataInit(t *testing.T) { + // Mock host and data stream + mockHost := &host.Host{} + + // Test Pre-Altair (should use V0) + t.Run("PreAltair", func(t *testing.T) { + cfg := &ReqRespConfig{ + ForkDigest: [4]byte{1, 2, 3, 4}, + Encoder: encoder.SszNetworkEncoder{}, + BeaconConfig: ¶ms.BeaconChainConfig{ + AltairForkEpoch: 1000, // Future epoch + FuluForkEpoch: params.BeaconConfig().FarFutureEpoch, + }, + GenesisConfig: &GenesisConfig{ + GenesisTime: time.Now().Add(-time.Hour), // Started 1 hour ago + }, + AttestationSubnetConfig: &SubnetConfig{Subnets: []uint64{0, 1}}, + SyncSubnetConfig: &SubnetConfig{Subnets: []uint64{0}}, + Tracer: otel.GetTracerProvider().Tracer("test"), + Meter: otel.GetMeterProvider().Meter("test"), + } + + reqResp, err := NewReqResp(mockHost, cfg) + assert.NoError(t, err) + assert.NotNil(t, reqResp) + assert.Equal(t, 0, reqResp.metadataHolder.Version()) + assert.NotNil(t, reqResp.metadataHolder.GetV0()) + assert.Nil(t, reqResp.metadataHolder.GetV1()) + assert.Nil(t, reqResp.metadataHolder.GetV2()) + }) + + // Test Altair (should use V1) + t.Run("Altair", func(t *testing.T) { + cfg := &ReqRespConfig{ + ForkDigest: [4]byte{1, 2, 3, 4}, + Encoder: encoder.SszNetworkEncoder{}, + BeaconConfig: ¶ms.BeaconChainConfig{ + AltairForkEpoch: 0, // Already activated + FuluForkEpoch: params.BeaconConfig().FarFutureEpoch, + }, + GenesisConfig: &GenesisConfig{ + GenesisTime: time.Now().Add(-time.Hour), // Started 1 hour ago + }, + AttestationSubnetConfig: &SubnetConfig{Subnets: []uint64{0, 1}}, + SyncSubnetConfig: &SubnetConfig{Subnets: []uint64{0}}, + Tracer: otel.GetTracerProvider().Tracer("test"), + Meter: otel.GetMeterProvider().Meter("test"), + } + + reqResp, err := NewReqResp(mockHost, cfg) + assert.NoError(t, err) + assert.NotNil(t, reqResp) + assert.Equal(t, 1, reqResp.metadataHolder.Version()) + assert.Nil(t, reqResp.metadataHolder.GetV0()) + assert.NotNil(t, reqResp.metadataHolder.GetV1()) + assert.Nil(t, reqResp.metadataHolder.GetV2()) + }) + + // Test Fulu (should use V2) + t.Run("Fulu", func(t *testing.T) { + cfg := &ReqRespConfig{ + ForkDigest: [4]byte{1, 2, 3, 4}, + Encoder: encoder.SszNetworkEncoder{}, + BeaconConfig: ¶ms.BeaconChainConfig{ + AltairForkEpoch: 0, // Already activated + FuluForkEpoch: 0, // Already activated + }, + GenesisConfig: &GenesisConfig{ + GenesisTime: time.Now().Add(-time.Hour), // Started 1 hour ago + }, + AttestationSubnetConfig: &SubnetConfig{Subnets: []uint64{0, 1}}, + SyncSubnetConfig: &SubnetConfig{Subnets: []uint64{0}}, + Tracer: otel.GetTracerProvider().Tracer("test"), + Meter: otel.GetMeterProvider().Meter("test"), + } + + reqResp, err := NewReqResp(mockHost, cfg) + assert.NoError(t, err) + assert.NotNil(t, reqResp) + assert.Equal(t, 2, reqResp.metadataHolder.Version()) + assert.Nil(t, reqResp.metadataHolder.GetV0()) + assert.Nil(t, reqResp.metadataHolder.GetV1()) + assert.NotNil(t, reqResp.metadataHolder.GetV2()) + + // Check custody group count + count, hasCount := reqResp.metadataHolder.CustodyGroupCount() + assert.True(t, hasCount) + assert.Equal(t, uint64(0), count) // TODO: Should be configured value + }) + + // Test without fork config (should default to V1) + t.Run("NoForkConfig", func(t *testing.T) { + cfg := &ReqRespConfig{ + ForkDigest: [4]byte{1, 2, 3, 4}, + Encoder: encoder.SszNetworkEncoder{}, + AttestationSubnetConfig: &SubnetConfig{Subnets: []uint64{0, 1}}, + SyncSubnetConfig: &SubnetConfig{Subnets: []uint64{0}}, + Tracer: otel.GetTracerProvider().Tracer("test"), + Meter: otel.GetMeterProvider().Meter("test"), + } + + reqResp, err := NewReqResp(mockHost, cfg) + assert.NoError(t, err) + assert.NotNil(t, reqResp) + assert.Equal(t, 1, reqResp.metadataHolder.Version()) // Defaults to V1 + assert.NotNil(t, reqResp.metadataHolder.GetV1()) + }) +} diff --git a/eth/reqresp_types.go b/eth/reqresp_types.go new file mode 100644 index 0000000..582093c --- /dev/null +++ b/eth/reqresp_types.go @@ -0,0 +1,207 @@ +package eth + +import ( + "github.com/OffchainLabs/prysm/v6/consensus-types/primitives" + pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/go-bitfield" +) + +// StatusHolder wraps different status versions +type StatusHolder struct { + v1 *pb.Status + v2 *pb.StatusV2 +} + +// SetV1 sets the V1 status +func (s *StatusHolder) SetV1(status *pb.Status) { + s.v1 = status + s.v2 = nil +} + +// SetV2 sets the V2 status +func (s *StatusHolder) SetV2(status *pb.StatusV2) { + s.v2 = status + s.v1 = nil +} + +// GetV1 returns the V1 status or nil if not set +func (s *StatusHolder) GetV1() *pb.Status { + return s.v1 +} + +// GetV2 returns the V2 status or nil if not set +func (s *StatusHolder) GetV2() *pb.StatusV2 { + return s.v2 +} + +// IsV2 returns true if this holder contains a V2 status +func (s *StatusHolder) IsV2() bool { + return s.v2 != nil +} + +// ForkDigest returns the fork digest from either version +func (s *StatusHolder) ForkDigest() []byte { + if s.v2 != nil { + return s.v2.ForkDigest + } + if s.v1 != nil { + return s.v1.ForkDigest + } + return nil +} + +// FinalizedEpoch returns the finalized epoch from either version +func (s *StatusHolder) FinalizedEpoch() primitives.Epoch { + if s.v2 != nil { + return s.v2.FinalizedEpoch + } + if s.v1 != nil { + return s.v1.FinalizedEpoch + } + return 0 +} + +// FinalizedRoot returns the finalized root from either version +func (s *StatusHolder) FinalizedRoot() []byte { + if s.v2 != nil { + return s.v2.FinalizedRoot + } + if s.v1 != nil { + return s.v1.FinalizedRoot + } + return nil +} + +// HeadRoot returns the head root from either version +func (s *StatusHolder) HeadRoot() []byte { + if s.v2 != nil { + return s.v2.HeadRoot + } + if s.v1 != nil { + return s.v1.HeadRoot + } + return nil +} + +// HeadSlot returns the head slot from either version +func (s *StatusHolder) HeadSlot() primitives.Slot { + if s.v2 != nil { + return s.v2.HeadSlot + } + if s.v1 != nil { + return s.v1.HeadSlot + } + return 0 +} + +// EarliestAvailableSlot returns the earliest available slot if V2, otherwise returns 0 and false +func (s *StatusHolder) EarliestAvailableSlot() (primitives.Slot, bool) { + if s.v2 != nil { + return s.v2.EarliestAvailableSlot, true + } + return 0, false +} + +// MetadataHolder wraps different metadata versions +type MetadataHolder struct { + v0 *pb.MetaDataV0 + v1 *pb.MetaDataV1 + v2 *pb.MetaDataV2 +} + +// SetV0 sets the V0 metadata +func (m *MetadataHolder) SetV0(md *pb.MetaDataV0) { + m.v0 = md + m.v1 = nil + m.v2 = nil +} + +// SetV1 sets the V1 metadata +func (m *MetadataHolder) SetV1(md *pb.MetaDataV1) { + m.v0 = nil + m.v1 = md + m.v2 = nil +} + +// SetV2 sets the V2 metadata +func (m *MetadataHolder) SetV2(md *pb.MetaDataV2) { + m.v0 = nil + m.v1 = nil + m.v2 = md +} + +// GetV0 returns the V0 metadata or nil if not set +func (m *MetadataHolder) GetV0() *pb.MetaDataV0 { + return m.v0 +} + +// GetV1 returns the V1 metadata or nil if not set +func (m *MetadataHolder) GetV1() *pb.MetaDataV1 { + return m.v1 +} + +// GetV2 returns the V2 metadata or nil if not set +func (m *MetadataHolder) GetV2() *pb.MetaDataV2 { + return m.v2 +} + +// SeqNumber returns the sequence number from any version +func (m *MetadataHolder) SeqNumber() uint64 { + if m.v2 != nil { + return m.v2.SeqNumber + } + if m.v1 != nil { + return m.v1.SeqNumber + } + if m.v0 != nil { + return m.v0.SeqNumber + } + return 0 +} + +// Attnets returns the attestation subnets from any version +func (m *MetadataHolder) Attnets() bitfield.Bitvector64 { + if m.v2 != nil { + return m.v2.Attnets + } + if m.v1 != nil { + return m.v1.Attnets + } + if m.v0 != nil { + return m.v0.Attnets + } + return bitfield.Bitvector64{} +} + +// Syncnets returns the sync committee subnets if available (V1 and V2 only) +func (m *MetadataHolder) Syncnets() (bitfield.Bitvector4, bool) { + if m.v2 != nil { + return m.v2.Syncnets, true + } + if m.v1 != nil { + return m.v1.Syncnets, true + } + return bitfield.Bitvector4{}, false +} + +// CustodyGroupCount returns the custody group count if V2, otherwise returns 0 and false +func (m *MetadataHolder) CustodyGroupCount() (uint64, bool) { + if m.v2 != nil { + return m.v2.CustodyGroupCount, true + } + return 0, false +} + +// Version returns the version number of the stored metadata +func (m *MetadataHolder) Version() int { + if m.v2 != nil { + return 2 + } + if m.v1 != nil { + return 1 + } + if m.v0 != nil { + return 0 + } + return -1 +} diff --git a/eth/subnets.go b/eth/subnets.go index 9bbce6f..fc888f3 100644 --- a/eth/subnets.go +++ b/eth/subnets.go @@ -52,6 +52,9 @@ func HasSubnets(topic string) (subnets uint64, hasSubnets bool) { case p2p.GossipBlobSidecarMessage: return GlobalBeaconConfig.BlobsidecarSubnetCountElectra, true + case p2p.GossipDataColumnSidecarMessage: + return GlobalBeaconConfig.DataColumnSidecarSubnetCount, true + default: return uint64(0), false } diff --git a/eth/topic_score_params.go b/eth/topic_score_params.go index 4660070..949f22e 100644 --- a/eth/topic_score_params.go +++ b/eth/topic_score_params.go @@ -67,7 +67,9 @@ func topicToScoreParamsMapper(topic string, activeValidators uint64) *pubsub.Top case strings.Contains(topic, p2p.GossipBlsToExecutionChangeMessage): return defaultBlsToExecutionChangeTopicParams() - case strings.Contains(topic, p2p.GossipBlobSidecarMessage): + case strings.Contains(topic, p2p.GossipBlobSidecarMessage), + strings.Contains(topic, p2p.GossipDataColumnSidecarMessage): + // Using the same scoring as blocks for blob and data column sidecars (following prysm's approach). return defaultBlockTopicParams() default: diff --git a/go.mod b/go.mod index 2669fdd..63aef67 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,9 @@ module github.com/probe-lab/hermes -go 1.24.0 - -toolchain go1.24.2 +go 1.24.5 require ( - github.com/OffchainLabs/prysm/v6 v6.0.1 + github.com/OffchainLabs/prysm/v6 v6.0.5-rc.1.0.20250823011907-d48ed44c4c75 github.com/aws/aws-sdk-go-v2 v1.32.7 github.com/aws/aws-sdk-go-v2/config v1.28.7 github.com/aws/aws-sdk-go-v2/credentials v1.17.48 @@ -42,11 +40,11 @@ require ( go.opentelemetry.io/otel/exporters/prometheus v0.55.0 go.opentelemetry.io/otel/metric v1.36.0 go.opentelemetry.io/otel/sdk v1.34.0 - go.opentelemetry.io/otel/sdk/metric v1.33.0 + go.opentelemetry.io/otel/sdk/metric v1.34.0 go.opentelemetry.io/otel/trace v1.36.0 golang.org/x/crypto v0.39.0 golang.org/x/time v0.11.0 - google.golang.org/grpc v1.70.0 + google.golang.org/grpc v1.71.0 google.golang.org/protobuf v1.36.6 gopkg.in/yaml.v3 v3.0.1 ) @@ -88,7 +86,7 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/deckarep/golang-set/v2 v2.7.0 // indirect - github.com/dgraph-io/ristretto v0.2.0 // indirect + github.com/dgraph-io/ristretto/v2 v2.2.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/elastic/gosigar v0.14.3 // indirect @@ -231,7 +229,7 @@ require ( github.com/prometheus/procfs v0.16.1 // indirect github.com/prometheus/prom2json v1.4.1 // indirect github.com/prometheus/prometheus v0.301.0 // indirect - github.com/prysmaticlabs/gohashtree v0.0.4-beta.0.20240624100937-73632381301b // indirect + github.com/prysmaticlabs/gohashtree v0.0.5-beta // indirect github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c // indirect github.com/quic-go/qpack v0.5.1 // indirect github.com/quic-go/quic-go v0.51.0 // indirect diff --git a/go.sum b/go.sum index 8db5930..f710e24 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,8 @@ github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/OffchainLabs/prysm/v6 v6.0.1 h1:NwFsJTyPVQqhmEz4//GqAs+M6AjcWYqH9x+HvDGxgwk= -github.com/OffchainLabs/prysm/v6 v6.0.1/go.mod h1:7QuGy5ol0x0hx1Qmz0XcXJ3CnjWWKHpMiz++bUR0IIg= +github.com/OffchainLabs/prysm/v6 v6.0.5-rc.1.0.20250823011907-d48ed44c4c75 h1:Xypx50G+oKUjhSFKEzxDxnL9xtcAL4k4TnksNgjHWME= +github.com/OffchainLabs/prysm/v6 v6.0.5-rc.1.0.20250823011907-d48ed44c4c75/go.mod h1:IGaKrTBMkZO98GOZNBWof9mcnINwlczEJCCw+JotDEc= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s= @@ -192,12 +192,12 @@ github.com/dennis-tra/go-kinesis v0.0.0-20240326083914-7acf5f8dc24e/go.mod h1:5H github.com/dennis-tra/go-yamux/v5 v5.0.0-20250519183055-dde4b3083558 h1:N0mn/xSyVdXgfM493L8j38ukJme3ktY2Hf6L9UnR5vQ= github.com/dennis-tra/go-yamux/v5 v5.0.0-20250519183055-dde4b3083558/go.mod h1:tgIQ07ObtRR/I0IWsFOyQIL9/dR5UXgc2s8xKmNZv1o= github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= -github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE= -github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU= +github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM= +github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -1006,8 +1006,8 @@ github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516 h1:xuVAdtz5S github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516/go.mod h1:h2OlIZD/M6wFvV3YMZbW16lFgh3Rsye00G44J2cwLyU= github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 h1:lC8kiphgdOBTcbTvo8MwkvpKjO0SlAgjv4xIK5FGJ94= github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15/go.mod h1:8svFBIKKu31YriBG/pNizo9N0Jr9i5PQ+dFkxWg3x5k= -github.com/prysmaticlabs/gohashtree v0.0.4-beta.0.20240624100937-73632381301b h1:VK7thFOnhxAZ/5aolr5Os4beiubuD08WiuiHyRqgwks= -github.com/prysmaticlabs/gohashtree v0.0.4-beta.0.20240624100937-73632381301b/go.mod h1:HRuvtXLZ4WkaB1MItToVH2e8ZwKwZPY5/Rcby+CvvLY= +github.com/prysmaticlabs/gohashtree v0.0.5-beta h1:ct41mg7HyIZd7uoSM/ud23f+3DxQG9tlMlQG+BVX23c= +github.com/prysmaticlabs/gohashtree v0.0.5-beta/go.mod h1:HRuvtXLZ4WkaB1MItToVH2e8ZwKwZPY5/Rcby+CvvLY= github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c h1:9PHRCuO/VN0s9k+RmLykho7AjDxblNYI5bYKed16NPU= github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c/go.mod h1:ZRws458tYHS/Zs936OQ6oCrL+Ict5O4Xpwve1UQ6C9M= github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20230228205207-28762a7b9294 h1:q9wE0ZZRdTUAAeyFP/w0SwBEnCqlVy2+on6X2/e+eAU= @@ -1225,8 +1225,8 @@ go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCRE go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= -go.opentelemetry.io/otel/sdk/metric v1.33.0 h1:Gs5VK9/WUJhNXZgn8MR6ITatvAmKeIuCtNbsP3JkNqU= -go.opentelemetry.io/otel/sdk/metric v1.33.0/go.mod h1:dL5ykHZmm1B1nVRk9dDjChwDmt81MjVp3gLkQRwKf/Q= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= @@ -1503,8 +1503,8 @@ google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= -google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= +google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= From 42d9971ad6c9ff1a1fb1655ad298ad0e7dd3e69a Mon Sep 17 00:00:00 2001 From: Mikel Cortes <45786396+cortze@users.noreply.github.com> Date: Thu, 30 Oct 2025 18:08:45 +0100 Subject: [PATCH 60/65] working prototype Many changes in this single commit: - New Chain module being aware of the fork and the chain-head - make the chain-module update with the Prysm node through the gRPC the local status - Sync our Cgc, and Syncnets with the ENR, the subscriptions, and the Metadata . Reshape the internals so that each individual module reuses the Chain one - Improvements at the req/resp stream handling - Add missing fork-aware handshake --- eth/chain.go | 34 +-- eth/reqresp.go | 368 ++++++++++++++++++++++++++----- eth/reqresp_encoding.go | 473 ---------------------------------------- eth/reqresp_test.go | 141 +----------- eth/reqresp_types.go | 104 ++------- go.mod | 14 +- go.sum | 11 +- host/event_types.go | 6 +- 8 files changed, 382 insertions(+), 769 deletions(-) delete mode 100644 eth/reqresp_encoding.go diff --git a/eth/chain.go b/eth/chain.go index 3f7e158..da72a34 100644 --- a/eth/chain.go +++ b/eth/chain.go @@ -39,13 +39,13 @@ const ( const ( // chain fork - phase0Fork chainFork = iota - altairFork - bellatrixFork - capellaFork - denebFork - electraFork - fuluFork + phase0 chainFork = iota + altair + bellatrix + capella + deneb + electra + fulu ) type chainUpgradeSubFn func() error @@ -203,7 +203,7 @@ func (c *Chain) epochUpdate(ctx context.Context) error { func (c *Chain) epochStats() (primitives.Slot, primitives.Epoch, chainFork, [4]byte, error) { if c.cfg.BeaconConfig == nil || c.cfg.GenesisConfig == nil { - return 0, 0, phase0Fork, [4]byte{}, fmt.Errorf("chain internals doest have beacon config") + return 0, 0, phase0, [4]byte{}, fmt.Errorf("chain internals doest have beacon config") } var ( slot = slots.CurrentSlot(c.cfg.GenesisConfig.GenesisTime) @@ -215,19 +215,19 @@ func (c *Chain) epochStats() (primitives.Slot, primitives.Epoch, chainFork, [4]b } func (c *Chain) forkFromEpoch(epoch primitives.Epoch) chainFork { - var fork = phase0Fork + var fork = phase0 if c.cfg.BeaconConfig.FuluForkEpoch != params.BeaconConfig().FarFutureEpoch && epoch >= c.cfg.BeaconConfig.FuluForkEpoch { - fork = fuluFork + fork = fulu } else if c.cfg.BeaconConfig.ElectraForkEpoch != params.BeaconConfig().FarFutureEpoch && epoch >= c.cfg.BeaconConfig.ElectraForkEpoch { - fork = electraFork + fork = electra } else if c.cfg.BeaconConfig.DenebForkEpoch != params.BeaconConfig().FarFutureEpoch && epoch >= c.cfg.BeaconConfig.DenebForkEpoch { - fork = denebFork + fork = deneb } else if c.cfg.BeaconConfig.CapellaForkEpoch != params.BeaconConfig().FarFutureEpoch && epoch >= c.cfg.BeaconConfig.CapellaForkEpoch { - fork = capellaFork + fork = capella } else if c.cfg.BeaconConfig.BellatrixForkEpoch != params.BeaconConfig().FarFutureEpoch && epoch >= c.cfg.BeaconConfig.BellatrixForkEpoch { - fork = bellatrixFork + fork = bellatrix } else if c.cfg.BeaconConfig.AltairForkEpoch != params.BeaconConfig().FarFutureEpoch && epoch >= c.cfg.BeaconConfig.AltairForkEpoch { - fork = altairFork + fork = altair } return fork } @@ -325,7 +325,7 @@ func (c *Chain) GetStatus(v statusVersion) any { defer c.statusMu.RUnlock() switch v { case statusV0: - return &StatusV1{ + return &pb.Status{ ForkDigest: c.statusHolder.ForkDigest(), FinalizedRoot: c.statusHolder.FinalizedRoot(), FinalizedEpoch: c.statusHolder.FinalizedEpoch(), @@ -360,7 +360,7 @@ func (c *Chain) UpdateStatus(v statusVersion, st any) error { defer c.statusMu.Unlock() switch v { case statusV1, statusV0: - st1, ok := st.(*StatusV2) + st1, ok := st.(*pb.StatusV2) if !ok { return fmt.Errorf("chain internal: status-update: invalid type for md version %d", v+1) } diff --git a/eth/reqresp.go b/eth/reqresp.go index c1c38b3..553cef1 100644 --- a/eth/reqresp.go +++ b/eth/reqresp.go @@ -3,6 +3,7 @@ package eth import ( "context" "encoding/hex" + "errors" "fmt" "io" "log/slog" @@ -14,15 +15,19 @@ import ( "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p" "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/encoder" "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/types" + psync "github.com/OffchainLabs/prysm/v6/beacon-chain/sync" "github.com/OffchainLabs/prysm/v6/consensus-types/blocks" "github.com/OffchainLabs/prysm/v6/consensus-types/interfaces" "github.com/OffchainLabs/prysm/v6/consensus-types/primitives" pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1" + ssz "github.com/ferranbt/fastssz" + "github.com/libp2p/go-libp2p/core" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/protocol" "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" "golang.org/x/time/rate" @@ -209,13 +214,13 @@ func (r *ReqResp) wrapStreamHandler(ctx context.Context, name string, handler Co func (r *ReqResp) pingHandler(ctx context.Context, stream network.Stream) (map[string]any, error) { req := new(primitives.SSZUint64) - if err := r.readRequest(stream, req); err != nil { + if err := r.readRequest(ctx, stream, req); err != nil { stream.Reset() return nil, fmt.Errorf("read sequence number: %w", err) } sq := r.cfg.Chain.CurrentSeqNumber() - if err := r.writeResponse(stream, &sq); err != nil { + if err := r.writeResponse(ctx, stream, &sq); err != nil { stream.Reset() return nil, fmt.Errorf("write sequence number: %w", err) } @@ -231,13 +236,13 @@ func (r *ReqResp) pingHandler(ctx context.Context, stream network.Stream) (map[s } func (r *ReqResp) goodbyeHandler(ctx context.Context, stream network.Stream) (map[string]any, error) { - req := primitives.SSZUint64(0) - if err := r.readRequest(stream, &req); err != nil { + req := new(primitives.SSZUint64) + if err := r.readRequest(ctx, stream, req); err != nil { stream.Reset() return nil, fmt.Errorf("read sequence number: %w", err) } - msg, found := types.GoodbyeCodeMessages[req] + msg, found := types.GoodbyeCodeMessages[*req] if found { if _, err := r.host.Peerstore().Get(stream.Conn().RemotePeer(), peerstoreKeyIsHandshaked); err == nil { var ( @@ -260,7 +265,7 @@ func (r *ReqResp) goodbyeHandler(ctx context.Context, stream network.Stream) (ma r.goodbyeCounter.Add(ctx, 1, metric.WithAttributes( []attribute.KeyValue{ - attribute.Int64("code", int64(req)), + attribute.Int64("code", int64(*req)), attribute.String("reason", reason), attribute.String("agent", agentVersion), }..., @@ -273,7 +278,7 @@ func (r *ReqResp) goodbyeHandler(ctx context.Context, stream network.Stream) (ma } traceData := map[string]any{ - "Code": req, + "Code": *req, "Reason": msg, } @@ -295,7 +300,7 @@ func (r *ReqResp) statusHandler(ctx context.Context, upstream network.Stream) (m // first, read the status from the remote peer req := &pb.Status{} - if err := r.readRequest(upstream, req); err != nil { + if err := r.readRequest(ctx, upstream, req); err != nil { upstream.Reset() return nil, fmt.Errorf("read status data from remote peer: %w", err) } @@ -303,7 +308,7 @@ func (r *ReqResp) statusHandler(ctx context.Context, upstream network.Stream) (m // let the upstream peer (who initiated the request) know the latest status localStI := r.cfg.Chain.GetStatus(statusV0) localSt, _ := localStI.(*pb.Status) - if err := r.writeResponse(upstream, localSt); err != nil { + if err := r.writeResponse(ctx, upstream, localSt); err != nil { upstream.Reset() return nil, fmt.Errorf("respond status to upstream: %w", err) } @@ -341,7 +346,7 @@ func (r *ReqResp) statusV2Handler(ctx context.Context, upstream network.Stream) // first, read the status from the remote peer req := &pb.StatusV2{} - if err := r.readRequest(upstream, req); err != nil { + if err := r.readRequest(ctx, upstream, req); err != nil { upstream.Reset() return nil, fmt.Errorf("read status V2 data from peer: %w", err) } @@ -351,7 +356,7 @@ func (r *ReqResp) statusV2Handler(ctx context.Context, upstream network.Stream) localSt, _ := localStI.(*pb.StatusV2) // let the upstream peer (who initiated the request) know the latest status - if err := r.writeResponse(upstream, localSt); err != nil { + if err := r.writeResponse(ctx, upstream, localSt); err != nil { upstream.Reset() return nil, fmt.Errorf("respond status V2 to upstream: %w", err) } @@ -378,7 +383,7 @@ func (r *ReqResp) metadataV1Handler(ctx context.Context, stream network.Stream) mdI := r.cfg.Chain.GetMetadata(metadataV0) metaData, _ := mdI.(*pb.MetaDataV0) - if err := r.writeResponse(stream, metaData); err != nil { + if err := r.writeResponse(ctx, stream, metaData); err != nil { stream.Reset() return nil, fmt.Errorf("write meta data v1: %w", err) } @@ -403,12 +408,12 @@ func (r *ReqResp) metadataV2Handler(ctx context.Context, stream network.Stream) mdI := r.cfg.Chain.GetMetadata(metadataV1) metaData, _ := mdI.(*pb.MetaDataV1) - if err := r.writeResponse(stream, metaData); err != nil { + if err := r.writeResponse(ctx, stream, metaData); err != nil { stream.Reset() return nil, fmt.Errorf("write meta data v1: %w", err) } - if err := r.writeResponse(stream, metaData); err != nil { + if err := r.writeResponse(ctx, stream, metaData); err != nil { stream.Reset() return nil, fmt.Errorf("write meta data v2: %w", err) } @@ -438,7 +443,7 @@ func (r *ReqResp) metadataV3Handler(ctx context.Context, stream network.Stream) return nil, fmt.Errorf("no metadata available") } - if err := r.writeResponse(stream, metaData); err != nil { + if err := r.writeResponse(ctx, stream, metaData); err != nil { stream.Reset() return nil, fmt.Errorf("write meta data v3: %w", err) } @@ -466,7 +471,7 @@ func (r *ReqResp) metadataV3Handler(ctx context.Context, stream network.Stream) func (r *ReqResp) DataColumnsByRangeV1Handler(ctx context.Context, stream network.Stream) (map[string]any, error) { req := new(pb.DataColumnSidecarsByRangeRequest) - err := r.readRequest(stream, req) + err := r.readRequest(ctx, stream, req) if err != nil { stream.Reset() return nil, fmt.Errorf("error to read data-column-by-range request %w", err) @@ -496,7 +501,7 @@ func (r *ReqResp) DataColumnsByRangeV1Handler(ctx context.Context, stream networ func (r *ReqResp) DataColumnsByRootV1Handler(ctx context.Context, stream network.Stream) (map[string]any, error) { req := new(types.DataColumnsByRootIdentifiers) - err := r.readRequest(stream, req) + err := r.readRequest(ctx, stream, req) if err != nil { return nil, fmt.Errorf("error to read data-column-by-root request %w", err) } @@ -663,14 +668,14 @@ func (r *ReqResp) Status(ctx context.Context, pid peer.ID) (status *pb.Status, e stI := r.cfg.Chain.GetStatus(statusV0) stReq, _ := stI.(*pb.Status) - if err := r.writeRequest(stream, stReq); err != nil { + if err := r.writeRequest(ctx, stream, stReq); err != nil { stream.Reset() return nil, fmt.Errorf("write status request: %w", err) } // read and decode status response resp := &pb.Status{} - if err := r.readResponse(stream, resp); err != nil { + if err := r.readResponse(ctx, stream, resp); err != nil { stream.Reset() return nil, fmt.Errorf("read status response: %w", err) } @@ -734,41 +739,20 @@ func (r *ReqResp) StatusV2(ctx context.Context, pid peer.ID) (status *pb.StatusV localStI := r.cfg.Chain.GetStatus(statusV1) localSt, _ := localStI.(*pb.StatusV2) - slog.Info( - "sending local status v2 request", - "peer", stream.Conn().RemotePeer().String(), - "trusted-peer", stream.Conn().RemotePeer() == r.delegate, - "head-slot", localSt.HeadSlot, - "head-root", hex.EncodeToString(localSt.HeadRoot), - "finalized-root", hex.EncodeToString(localSt.FinalizedRoot), - "fork-digest", hex.EncodeToString(localSt.ForkDigest), - "eas", localSt.EarliestAvailableSlot, - ) - if err := r.writeRequest(stream, localSt); err != nil { + if err := r.writeRequest(ctx, stream, localSt); err != nil { stream.Reset() return nil, fmt.Errorf("write status V2 request: %w", err) } // read and decode status response resp := &pb.StatusV2{} - if err := r.readResponse(stream, resp); err != nil { + if err := r.readResponse(ctx, stream, resp); err != nil { stream.Reset() return nil, fmt.Errorf("read status V2 response: %w", err) } _ = stream.Close() - slog.Info( - "successful status v2 response", - "peer", stream.Conn().RemotePeer().String(), - "trusted-peer", stream.Conn().RemotePeer() == r.delegate, - "head-slot", resp.HeadSlot, - "head-root", hex.EncodeToString(resp.HeadRoot), - "finalized-root", hex.EncodeToString(resp.FinalizedRoot), - "fork-digest", hex.EncodeToString(resp.ForkDigest), - "eas", resp.EarliestAvailableSlot, - ) - return resp, nil } @@ -803,14 +787,14 @@ func (r *ReqResp) Ping(ctx context.Context, pid peer.ID) (err error) { seqNum := r.cfg.Chain.CurrentSeqNumber() req := primitives.SSZUint64(seqNum) - if err := r.writeRequest(stream, &req); err != nil { + if err := r.writeRequest(ctx, stream, &req); err != nil { stream.Reset() return fmt.Errorf("write ping request: %w", err) } // read and decode status response resp := new(primitives.SSZUint64) - if err := r.readResponse(stream, resp); err != nil { + if err := r.readResponse(ctx, stream, resp); err != nil { stream.Reset() return fmt.Errorf("read ping response: %w", err) } @@ -861,14 +845,14 @@ func (r *ReqResp) MetaDataV1(ctx context.Context, pid peer.ID) (resp *pb.MetaDat return resp, fmt.Errorf("new %s stream to peer %s: %w", p2p.RPCMetaDataTopicV2, pid, err) } - if err := r.writeRequest(stream, nil); err != nil { + if err := r.writeRequest(ctx, stream, nil); err != nil { stream.Reset() return nil, fmt.Errorf("write metadata v2 request %s", err) } // read and decode metadata response resp = &pb.MetaDataV1{} - if err := r.readResponse(stream, resp); err != nil { + if err := r.readResponse(ctx, stream, resp); err != nil { stream.Reset() return resp, fmt.Errorf("read metadata response: %w", err) } @@ -920,14 +904,14 @@ func (r *ReqResp) MetaDataV2(ctx context.Context, pid peer.ID) (resp *pb.MetaDat return resp, fmt.Errorf("new %s stream to peer %s: %w", p2p.RPCMetaDataTopicV3, pid, err) } - if err := r.writeRequest(stream, nil); err != nil { + if err := r.writeRequest(ctx, stream, nil); err != nil { stream.Reset() return nil, fmt.Errorf("write metadata v2 request %s", err) } // read and decode metadata response resp = &pb.MetaDataV2{} - if err := r.readResponse(stream, resp); err != nil { + if err := r.readResponse(ctx, stream, resp); err != nil { stream.Reset() return resp, fmt.Errorf("read metadata V2 response: %w", err) } @@ -938,8 +922,292 @@ func (r *ReqResp) MetaDataV2(ctx context.Context, pid peer.ID) (resp *pb.MetaDat } func (r *ReqResp) BlocksByRangeV2(ctx context.Context, pid peer.ID, firstSlot, lastSlot uint64) ([]interfaces.ReadOnlySignedBeaconBlock, error) { - // TODO: reimplement this logic usin the das-guardian logic? - return make([]interfaces.ReadOnlySignedBeaconBlock, 0, (lastSlot - firstSlot)), nil + var err error + blocks := make([]interfaces.ReadOnlySignedBeaconBlock, 0, (lastSlot - firstSlot)) + startT := time.Now() + defer func() { + reqData := map[string]any{ + "PeerID": pid.String(), + } + + if blocks != nil { + reqData["RequestedBlocks"] = lastSlot - firstSlot + reqData["ReceivedBlocks"] = len(blocks) + reqData["Duration"] = time.Since(startT) + } + + if err != nil { + reqData["Error"] = err.Error() + } + + traceEvt := &hermeshost.TraceEvent{ + Type: "REQUEST_BLOCKS_BY_RANGE", + PeerID: r.host.ID(), + Timestamp: time.Now(), + Payload: reqData, + } + traceCtx := context.Background() + if err := r.cfg.DataStream.PutRecord(traceCtx, traceEvt); err != nil { + slog.Warn("failed to put record", tele.LogAttrError(err)) + } + + attrs := []attribute.KeyValue{ + attribute.String("rpc", "block_by_range"), + attribute.Bool("success", err == nil), + } + r.meterRequestCounter.Add(traceCtx, 1, metric.WithAttributes(attrs...)) + }() + + slog.Debug("Perform blocks_by_range request", tele.LogAttrPeerID(pid)) + stream, err := r.host.NewStream(ctx, pid, r.protocolID(p2p.RPCBlocksByRangeTopicV2)) + if err != nil { + return blocks, fmt.Errorf("new %s stream to peer %s: %w", p2p.RPCBlocksByRangeTopicV2, pid, err) + } + + req := &pb.BeaconBlocksByRangeRequest{ + StartSlot: primitives.Slot(firstSlot), + Count: (lastSlot - firstSlot), + Step: 1, + } + if err := r.writeRequest(ctx, stream, req); err != nil { + stream.Reset() + return blocks, fmt.Errorf("write block_by_range request: %w", err) + } + + // read and decode status response + process := func(blk interfaces.ReadOnlySignedBeaconBlock) error { + blocks = append(blocks, blk) + slog.Info( + "got signed_beacon_block", + slog.Attr{Key: "block_number", Value: slog.AnyValue(blk.Block().Slot())}, + slog.Attr{Key: "from", Value: slog.AnyValue(pid.String())}, + ) + return nil + } + + for i := uint64(0); ; i++ { + isFirstChunk := i == 0 + blk, err := r.readChunkedBlock(stream, &encoder.SszNetworkEncoder{}, isFirstChunk) + if errors.Is(err, io.EOF) { + break + } + if err != nil { + stream.Reset() + return nil, fmt.Errorf("reading block_by_range request: %w", err) + } + if err := process(blk); err != nil { + return nil, fmt.Errorf("processing block_by_range chunk: %w", err) + } + } + + _ = stream.Close() + + return blocks, nil +} + +// readRequest reads a request from the given network stream and populates the +// data parameter with the decoded request. It also sets a read deadline on the +// stream and returns an error if it fails to do so. After reading the request, +// it closes the reading side of the stream and returns an error if it fails to +// do so. The method also records any errors encountered using the +// tracer configured at [ReqResp] initialization. +func (r *ReqResp) readRequest(ctx context.Context, stream network.Stream, data ssz.Unmarshaler) (err error) { + _, span := r.cfg.Tracer.Start(ctx, "read_request") + defer func() { + if err != nil { + slog.Error("reading request", "err", err.Error()) + span.RecordError(err) + span.SetStatus(codes.Error, err.Error()) + } + span.End() + }() + + if err = stream.SetReadDeadline(time.Now().Add(r.cfg.ReadTimeout)); err != nil { + return fmt.Errorf("failed setting read deadline on stream: %w", err) + } + + if err = r.cfg.Encoder.DecodeWithMaxLength(stream, data); err != nil { + return fmt.Errorf("read request data %T: %w", data, err) + } + + if err = stream.CloseRead(); err != nil { + return fmt.Errorf("failed to close reading side of stream: %w", err) + } + return nil +} + +// readResponse differs from readRequest in first reading a single byte that +// indicates the response code before actually reading the payload data. It also +// handles the response code in case it is not 0 (which would indicate success). +func (r *ReqResp) readResponse(ctx context.Context, stream network.Stream, data ssz.Unmarshaler) (err error) { + _, span := r.cfg.Tracer.Start(ctx, "read_response") + defer func() { + if err != nil { + slog.Error("reading response", "err", err.Error()) + span.RecordError(err) + span.SetStatus(codes.Error, err.Error()) + } + span.End() + }() + + if err = stream.SetReadDeadline(time.Now().Add(r.cfg.ReadTimeout)); err != nil { + return fmt.Errorf("failed setting read deadline on stream: %w", err) + } + + code := make([]byte, 1) + if _, err := io.ReadFull(stream, code); err != nil { + return fmt.Errorf("failed reading response code: %w", err) + } + + // code == 0 means success + // code != 0 means error + if int(code[0]) != 0 { + errData, err := io.ReadAll(stream) + if err != nil { + return fmt.Errorf("failed reading error data (code %d): %w", int(code[0]), err) + } + + return fmt.Errorf("received error response (code %d): %s", int(code[0]), string(errData)) + } + + if err = r.cfg.Encoder.DecodeWithMaxLength(stream, data); err != nil { + return fmt.Errorf("read request data %T: %w", data, err) + } + + if err = stream.CloseRead(); err != nil { + return fmt.Errorf("failed to close reading side of stream: %w", err) + } + + return nil +} + +// writeRequest writes the given payload data to the given stream. It sets the +// appropriate timeouts and closes the stream for further writes. +func (r *ReqResp) writeRequest(ctx context.Context, stream network.Stream, data ssz.Marshaler) (err error) { + _, span := r.cfg.Tracer.Start(ctx, "write_request") + defer func() { + if err != nil { + slog.Error("error writing request", "err", err.Error()) + span.RecordError(err) + span.SetStatus(codes.Error, err.Error()) + } + span.End() + if wErr := stream.CloseWrite(); wErr != nil { + slog.Error( + "failed to close writing side of stream", + "peer", stream.Conn().RemotePeer().String(), + "error", err.Error(), + ) + } + }() + + if err = stream.SetWriteDeadline(time.Now().Add(r.cfg.WriteTimeout)); err != nil { + return fmt.Errorf("failed setting write deadline on stream: %w", err) + } + + if _, err = r.cfg.Encoder.EncodeWithMaxLength(stream, data); err != nil { + return fmt.Errorf("read sequence number: %w", err) + } + + return nil +} + +// writeResponse differs from writeRequest in prefixing the payload data with +// a response code byte. +func (r *ReqResp) writeResponse(ctx context.Context, stream network.Stream, data ssz.Marshaler) (err error) { + _, span := r.cfg.Tracer.Start(ctx, "write_response") + defer func() { + if err != nil { + slog.Error("error writing response", "err", err.Error()) + span.RecordError(err) + span.SetStatus(codes.Error, err.Error()) + } + span.End() + if wErr := stream.CloseWrite(); wErr != nil { + slog.Error( + "failed to close writing side of stream", + "peer", stream.Conn().RemotePeer().String(), + "error", err.Error(), + ) + } + }() + + if err = stream.SetWriteDeadline(time.Now().Add(r.cfg.WriteTimeout)); err != nil { + return fmt.Errorf("failed setting write deadline on stream: %w", err) + } + + if _, err := stream.Write([]byte{0x00}); err != nil { // success response + return fmt.Errorf("write success response code: %w", err) + } + + if _, err = r.cfg.Encoder.EncodeWithMaxLength(stream, data); err != nil { + return fmt.Errorf("read sequence number: %w", err) + } + + return nil +} + +// ReadChunkedBlock handles each response chunk that is sent by the +// peer and converts it into a beacon block. +// Adaptation from Prysm's -> https://github.com/prysmaticlabs/prysm/blob/2e29164582c3665cdf5a472cd4ec9838655c9754/beacon-chain/sync/rpc_chunked_response.go#L85 +func (r *ReqResp) readChunkedBlock(stream core.Stream, encoding encoder.NetworkEncoding, isFirstChunk bool) (interfaces.ReadOnlySignedBeaconBlock, error) { + // Handle deadlines differently for first chunk + if isFirstChunk { + return r.readFirstChunkedBlock(stream, encoding) + } + return r.readResponseChunk(stream, encoding) +} + +// readFirstChunkedBlock reads the first chunked block and applies the appropriate deadlines to it. +func (r *ReqResp) readFirstChunkedBlock(stream core.Stream, encoding encoder.NetworkEncoding) (interfaces.ReadOnlySignedBeaconBlock, error) { + // read status + code, errMsg, err := psync.ReadStatusCode(stream, encoding) + if err != nil { + return nil, err + } + if code != 0 { + return nil, errors.New(errMsg) + } + // set deadline for reading from stream + if err = stream.SetWriteDeadline(time.Now().Add(r.cfg.WriteTimeout)); err != nil { + return nil, fmt.Errorf("failed setting write deadline on stream: %w", err) + } + // get fork version and block type + forkD, err := r.readForkDigestFromStream(stream) + if err != nil { + return nil, err + } + forkV, err := GetForkVersionFromForkDigest(forkD) + if err != nil { + return nil, err + } + return r.getBlockForForkVersion(forkV, encoding, stream) +} + +// readResponseChunk reads the response from the stream and decodes it into the +// provided message type. +func (r *ReqResp) readResponseChunk(stream core.Stream, encoding encoder.NetworkEncoding) (interfaces.ReadOnlySignedBeaconBlock, error) { + if err := stream.SetWriteDeadline(time.Now().Add(r.cfg.WriteTimeout)); err != nil { + return nil, fmt.Errorf("failed setting write deadline on stream: %w", err) + } + code, errMsg, err := psync.ReadStatusCode(stream, encoding) + if err != nil { + return nil, err + } + if code != 0 { + return nil, errors.New(errMsg) + } + // No-op for now with the rpc context. + forkD, err := r.readForkDigestFromStream(stream) + if err != nil { + return nil, err + } + forkV, err := GetForkVersionFromForkDigest(forkD) + if err != nil { + return nil, err + } + + return r.getBlockForForkVersion(forkV, encoding, stream) } // readForkDigestFromStream reads any attached context-bytes to the payload. diff --git a/eth/reqresp_encoding.go b/eth/reqresp_encoding.go deleted file mode 100644 index 0bb9d96..0000000 --- a/eth/reqresp_encoding.go +++ /dev/null @@ -1,473 +0,0 @@ -package eth - -import ( - "bytes" - "encoding/binary" - "fmt" - "io" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/golang/snappy" - "github.com/libp2p/go-libp2p/core/network" - dynssz "github.com/pk910/dynamic-ssz" - "github.com/pkg/errors" - log "github.com/sirupsen/logrus" -) - -type ErrorMessage []byte - -// Maximum message sizes -const ( - MaxRequestSize = 2048 // 2KB for requests - MaxResponseSize = 16 * 1024 * 1024 // 16MB for responses - MaxChunkSize = 1024 * 1024 // 1MB per chunk -) - -// Error codes for RPC responses -const ( - ResponseCodeSuccess = 0x00 - ResponseCodeInvalidRequest = 0x01 - ResponseCodeServerError = 0x02 - ResponseCodeResourceExhausted = 0x03 -) - -var sszCodec = dynssz.NewDynSsz(map[string]any{}) - -// Helper function to get response code names for debugging -func getResponseCodeName(code byte) string { - switch code { - case ResponseCodeSuccess: - return "SUCCESS" - case ResponseCodeInvalidRequest: - return "INVALID_REQUEST" - case ResponseCodeServerError: - return "SERVER_ERROR" - case ResponseCodeResourceExhausted: - return "RESOURCE_EXHAUSTED" - default: - return "UNKNOWN" - } -} - -// Sync pools for snappy readers and writers -var ( - bufReaderPool = &sync.Pool{} - bufWriterPool = &sync.Pool{} -) - -// Writes a bytes value through a snappy buffered writer. -func writeSnappyBuffer(w io.Writer, b []byte) (int, error) { - bufWriter := newBufferedWriter(w) - defer bufWriterPool.Put(bufWriter) - num, err := bufWriter.Write(b) - if err != nil { - // Close buf writer in the event of an error. - if err := bufWriter.Close(); err != nil { - return 0, err - } - return 0, err - } - return num, bufWriter.Close() -} - -// Instantiates a new instance of the snappy buffered reader -// using our sync pool. -func newBufferedReader(r io.Reader) *snappy.Reader { - rawReader := bufReaderPool.Get() - if rawReader == nil { - return snappy.NewReader(r) - } - bufR, ok := rawReader.(*snappy.Reader) - if !ok { - return snappy.NewReader(r) - } - bufR.Reset(r) - return bufR -} - -// Instantiates a new instance of the snappy buffered writer -// using our sync pool. -func newBufferedWriter(w io.Writer) *snappy.Writer { - rawBufWriter := bufWriterPool.Get() - if rawBufWriter == nil { - return snappy.NewBufferedWriter(w) - } - bufW, ok := rawBufWriter.(*snappy.Writer) - if !ok { - return snappy.NewBufferedWriter(w) - } - bufW.Reset(w) - return bufW -} - -// writeVarint writes a varint to the stream -func writeVarint(w io.Writer, val uint64) error { - buf := make([]byte, binary.MaxVarintLen64) - n := binary.PutUvarint(buf, val) - _, err := w.Write(buf[:n]) - return err -} - -// readVarint reads a varint from the stream -func readVarint(r io.Reader) (uint64, error) { - var buf [binary.MaxVarintLen64]byte - for i := 0; i < len(buf); i++ { - if _, err := r.Read(buf[i : i+1]); err != nil { - return 0, err - } - if buf[i] < 0x80 { - val, n := binary.Uvarint(buf[:i+1]) - if n <= 0 { - return 0, fmt.Errorf("invalid varint") - } - return val, nil - } - } - return 0, fmt.Errorf("varint too long") -} - -// writeRequest writes a request to the stream with SSZ+Snappy encoding -func (r *ReqResp) writeRequest(stream network.Stream, req any) error { - defer stream.CloseWrite() - - // Set write deadline - if err := stream.SetWriteDeadline(time.Now().Add(r.cfg.WriteTimeout)); err != nil { - return fmt.Errorf("failed to set write deadline: %w", err) - } - - if req == nil { - // we close the write side of the stream immediately, communicating we have no data to send - return nil - } - - // Marshal to SSZ if the request is not nil - data, err := sszCodec.MarshalSSZ(req) - if err != nil { - return fmt.Errorf("failed to marshal SSZ: %w", err) - } - - // Validate size - msgSize := len(data) - if msgSize > MaxRequestSize { - return fmt.Errorf("request too large: %d bytes", msgSize) - } - - // Write to buffer first for inspection - var buf bytes.Buffer - - // Write uncompressed length prefix (varint) - if err := writeVarint(&buf, uint64(msgSize)); err != nil { - return fmt.Errorf("failed to write uncompressed length to buffer: %w", err) - } - - // Compress with snappy buffered writer - if _, err := writeSnappyBuffer(&buf, data); err != nil { - return fmt.Errorf("failed to compress data: %w", err) - } - - log.WithFields(log.Fields{ - "protocol": stream.Protocol(), - "data": hexutil.Encode(data), - "data_len": len(data), - "wire_data": hexutil.Encode(buf.Bytes()), - "wire_len": buf.Len(), - }).Debug("writing request") - - // Write buffer to the stream - if _, err := io.Copy(stream, &buf); err != nil { - return fmt.Errorf("failed to write final payload to stream: %w", err) - } - - return nil -} - -// readRequest reads a request from the stream with SSZ+Snappy decoding -func (r *ReqResp) readRequest(stream network.Stream, req any) error { - // Set read deadline - if err := stream.SetReadDeadline(time.Now().Add(r.cfg.ReadTimeout)); err != nil { - return fmt.Errorf("failed to set read deadline: %w", err) - } - - // Read uncompressed length prefix - uncompressedLength, err := readVarint(stream) - if err != nil { - return fmt.Errorf("failed to read uncompressed length: %w", err) - } - - // Validate uncompressed size - if uncompressedLength > MaxRequestSize { - return fmt.Errorf("request too large: %d bytes", uncompressedLength) - } - - // Calculate maximum compressed length - maxCompressedLen := snappy.MaxEncodedLen(int(uncompressedLength)) - if maxCompressedLen < 0 { - return fmt.Errorf("max encoded length is negative: %d", maxCompressedLen) - } - - // Use limited reader to read compressed data - limitedReader := io.LimitReader(stream, int64(maxCompressedLen)) - - // Create buffered snappy reader - snappyReader := newBufferedReader(limitedReader) - defer bufReaderPool.Put(snappyReader) - - // Read decompressed data - data := make([]byte, uncompressedLength) - if _, err := io.ReadFull(snappyReader, data); err != nil { - return fmt.Errorf("failed to read decompressed data: %w", err) - } - - // Unmarshal from SSZ - if err := sszCodec.UnmarshalSSZ(req, data); err != nil { - return fmt.Errorf("failed to unmarshal SSZ: %w", err) - } - - return nil -} - -// writeResponse writes a response to the stream with SSZ+Snappy encoding -func (r *ReqResp) writeResponse(stream network.Stream, resp any) error { - // Set write deadline - if err := stream.SetWriteDeadline(time.Now().Add(r.cfg.WriteTimeout)); err != nil { - return fmt.Errorf("failed to set write deadline: %w", err) - } - - // Write success response code - if _, err := stream.Write([]byte{ResponseCodeSuccess}); err != nil { - return fmt.Errorf("failed to write response code: %w", err) - } - - // Marshal to SSZ - data, err := sszCodec.MarshalSSZ(resp) - if err != nil { - return fmt.Errorf("failed to marshal SSZ: %w", err) - } - - // Validate size - msgSize := len(data) - if msgSize > MaxChunkSize { - return fmt.Errorf("response too large: %d bytes", msgSize) - } - - // Write uncompressed length prefix (varint) - if err := writeVarint(stream, uint64(msgSize)); err != nil { - return fmt.Errorf("failed to write uncompressed length: %w", err) - } - - // Compress with snappy buffered writer - if _, err := writeSnappyBuffer(stream, data); err != nil { - return fmt.Errorf("failed to compress data: %w", err) - } - - return nil -} - -// readResponse reads a response from the stream with SSZ+Snappy decoding -func (r *ReqResp) readResponse(stream network.Stream, resp any) error { - // Get the response type for debug logging - responseType := fmt.Sprintf("%T", resp) - // Set read deadline - if err := stream.SetReadDeadline(time.Now().Add(r.cfg.ReadTimeout)); err != nil { - return fmt.Errorf("failed to set read deadline: %w", err) - } - - // Read response code - var code [1]byte - if _, err := stream.Read(code[:]); err != nil { - return fmt.Errorf("failed to read response code: %w", err) - } - - if log.GetLevel() >= log.DebugLevel { - log.WithFields(log.Fields{ - "response_type": responseType, - "response_code": code[0], - "response_code_hex": fmt.Sprintf("0x%02x", code[0]), - "is_success": code[0] == ResponseCodeSuccess, - }).Debug("Raw response code received") - } - - success := code[0] == ResponseCodeSuccess - if !success { - if log.GetLevel() >= log.DebugLevel { - errorType := getResponseCodeName(code[0]) - log.WithFields(log.Fields{ - "response_type": responseType, - "response_code": code[0], - "error_type": errorType, - }).Debug("Non-success response code received") - } - } - - // Read uncompressed length prefix - uncompressedLength, err := readVarint(stream) - if err != nil { - return fmt.Errorf("failed to read uncompressed length: %w", err) - } - - if log.GetLevel() >= log.DebugLevel { - log.WithFields(log.Fields{ - "response_type": responseType, - "uncompressed_length": uncompressedLength, - }).Debug("Read uncompressed length from response") - } - - // Validate uncompressed size - if uncompressedLength > MaxChunkSize { - return fmt.Errorf("response too large: %d bytes", uncompressedLength) - } - - // Calculate maximum compressed length - maxCompressedLen := snappy.MaxEncodedLen(int(uncompressedLength)) - if maxCompressedLen < 0 { - return fmt.Errorf("max encoded length is negative: %d", maxCompressedLen) - } - - // Use limited reader to read compressed data - limitedReader := io.LimitReader(stream, int64(maxCompressedLen)) - - // Create buffered snappy reader - snappyReader := newBufferedReader(limitedReader) - defer bufReaderPool.Put(snappyReader) - - // Read decompressed data - data := make([]byte, uncompressedLength) - if _, err := io.ReadFull(snappyReader, data); err != nil { - return fmt.Errorf("failed to read decompressed data: %w", err) - } - - // Log the raw response data - if log.GetLevel() >= log.DebugLevel { - log.WithFields(log.Fields{ - "response_type": responseType, - "uncompressed_length": uncompressedLength, - "raw_data_hex": fmt.Sprintf("0x%x", data), - "raw_data_len": len(data), - }).Debug("Raw response data received") - } - - if !success { - var errorMessage ErrorMessage - l := log.WithFields(log.Fields{ - "response_type": responseType, - "raw_data_hex": fmt.Sprintf("0x%x", data), - }) - if err := sszCodec.UnmarshalSSZ(&errorMessage, data); err != nil { - l.WithError(err).Error("failed to unmarshal SSZ error message") - return fmt.Errorf("failed to unmarshal SSZ error message: %w", err) - } - msg := string(errorMessage) - l.Warnf("RPC failed; error message: %s", msg) - return fmt.Errorf("RPC failed: %s", msg) - } - - // Unmarshal from SSZ - if err := sszCodec.UnmarshalSSZ(resp, data); err != nil { - if log.GetLevel() >= log.DebugLevel { - log.WithFields(log.Fields{ - "response_type": responseType, - "unmarshal_error": err, - "raw_data_hex": fmt.Sprintf("0x%x", data), - }).Debug("Failed to unmarshal SSZ response") - } - return fmt.Errorf("failed to unmarshal SSZ: %w", err) - } - - if log.GetLevel() >= log.DebugLevel { - log.WithFields(log.Fields{ - "response_type": responseType, - }).Debug("Successfully unmarshaled response") - } - - return nil -} - -// readChunkedResponse handles each response chunk that is sent by the -// peer and converts it into the given type. -// Adaptation from Prysm's -> https://github.com/prysmaticlabs/prysm/blob/2e29164582c3665cdf5a472cd4ec9838655c9754/beacon-chain/sync/rpc_chunked_response.go#L85 -func (r *ReqResp) readChunkedResponse(stream network.Stream, resp any, isFirstChunk bool, forkDigest []byte) error { - if !isFirstChunk { - if err := stream.SetWriteDeadline(time.Now().Add(r.cfg.WriteTimeout)); err != nil { - return fmt.Errorf("failed setting write deadline on stream: %w", err) - } - } - - var code [1]byte - if _, err := stream.Read(code[:]); err != nil { - return fmt.Errorf("failed to read response code: %w", err) - } - - if code[0] != ResponseCodeSuccess { - return fmt.Errorf("RPC error code: %d", code[0]) - } - - // Handle deadlines differently for first chunk - if isFirstChunk { - // set deadline for reading from stream - if err := stream.SetWriteDeadline(time.Now().Add(r.cfg.WriteTimeout)); err != nil { - return fmt.Errorf("failed setting write deadline on stream: %w", err) - } - } - - if len(forkDigest) > 0 { - // Retrieve the fork digest. - ctxBytes, err := readContextFromStream(stream) - if err != nil { - return errors.Wrap(err, "read context from stream") - } - - // Check if the fork digest is recognized. - if string(ctxBytes) != string(forkDigest) { - return errors.Errorf("unrecognized fork digest %#x", ctxBytes) - } - } - - // Read uncompressed length prefix - uncompressedLength, err := readVarint(stream) - if err != nil { - return fmt.Errorf("failed to read uncompressed length: %w", err) - } - - // Validate uncompressed size - if uncompressedLength > MaxChunkSize { - return fmt.Errorf("response too large: %d bytes", uncompressedLength) - } - - // Calculate maximum compressed length - maxCompressedLen := snappy.MaxEncodedLen(int(uncompressedLength)) - if maxCompressedLen < 0 { - return fmt.Errorf("max encoded length is negative: %d", maxCompressedLen) - } - - // Use limited reader to read compressed data - limitedReader := io.LimitReader(stream, int64(maxCompressedLen)) - - // Create buffered snappy reader - snappyReader := newBufferedReader(limitedReader) - defer bufReaderPool.Put(snappyReader) - - // Read decompressed data - data := make([]byte, uncompressedLength) - if _, err := io.ReadFull(snappyReader, data); err != nil { - return fmt.Errorf("failed to read decompressed data: %w", err) - } - - // Unmarshal from SSZ - if err := sszCodec.UnmarshalSSZ(resp, data); err != nil { - return fmt.Errorf("failed to unmarshal SSZ: %w", err) - } - - return nil -} - -// reads any attached context-bytes to the payload. -func readContextFromStream(stream network.Stream) ([]byte, error) { - // Read context (fork-digest) from stream - b := make([]byte, 4) - if _, err := io.ReadFull(stream, b); err != nil { - return nil, err - } - return b, nil -} diff --git a/eth/reqresp_test.go b/eth/reqresp_test.go index 257bb53..03a36a3 100644 --- a/eth/reqresp_test.go +++ b/eth/reqresp_test.go @@ -8,7 +8,6 @@ import ( "github.com/OffchainLabs/prysm/v6/beacon-chain/core/signing" "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/encoder" - "github.com/OffchainLabs/prysm/v6/config/params" "github.com/OffchainLabs/prysm/v6/consensus-types/primitives" pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1" "github.com/probe-lab/hermes/host" @@ -137,11 +136,11 @@ func TestStatusHolder(t *testing.T) { holder := &StatusHolder{} // Test V1 status - statusV1 := &StatusV1{ - ForkDigest: [4]byte{1, 2, 3, 4}, - FinalizedRoot: [32]byte("finalized_root_v1"), + statusV1 := &pb.Status{ + ForkDigest: []byte{1, 2, 3, 4}, + FinalizedRoot: []byte("finalized_root_v1"), FinalizedEpoch: 100, - HeadRoot: [32]byte("head_root_v1"), + HeadRoot: []byte("head_root_v1"), HeadSlot: 1000, } @@ -153,11 +152,11 @@ func TestStatusHolder(t *testing.T) { assert.Equal(t, statusV1.HeadSlot, holder.HeadSlot()) // Test V2 status - statusV2 := &StatusV2{ - ForkDigest: [4]byte{5, 6, 7, 8}, - FinalizedRoot: [32]byte("finalized_root_v2"), + statusV2 := &pb.StatusV2{ + ForkDigest: []byte{5, 6, 7, 8}, + FinalizedRoot: []byte("finalized_root_v2"), FinalizedEpoch: 200, - HeadRoot: [32]byte("head_root_v2"), + HeadRoot: []byte("head_root_v2"), HeadSlot: 2000, EarliestAvailableSlot: 1500, } @@ -249,127 +248,3 @@ func TestMetadataHolder(t *testing.T) { assert.False(t, hasCount) assert.Equal(t, uint64(0), count) } - -// TestForkAwareMetadataInit tests that ReqResp initializes metadata correctly based on fork -func TestForkAwareMetadataInit(t *testing.T) { - // Mock host and data stream - mockHost := &host.Host{} - - // Test Pre-Altair (should use V0) - t.Run("PreAltair", func(t *testing.T) { - cfg := &ReqRespConfig{ - Chain: &Chain{ - cfg: &ChainConfig{ - BeaconConfig: ¶ms.BeaconChainConfig{ - AltairForkEpoch: 1000, // Future epoch - FuluForkEpoch: params.BeaconConfig().FarFutureEpoch, - }, - GenesisConfig: &GenesisConfig{ - GenesisTime: time.Now().Add(-time.Hour), // Started 1 hour ago - }, - AttestationSubnetConfig: &SubnetConfig{Subnets: []uint64{0, 1}}, - SyncSubnetConfig: &SubnetConfig{Subnets: []uint64{0}}, - }, - }, - Encoder: encoder.SszNetworkEncoder{}, - Tracer: otel.GetTracerProvider().Tracer("test"), - Meter: otel.GetMeterProvider().Meter("test"), - } - - reqResp, err := NewReqResp(mockHost, cfg) - assert.NoError(t, err) - assert.NotNil(t, reqResp) - assert.Equal(t, 0, reqResp.cfg.Chain.metadataHolder.Version()) - assert.NotNil(t, reqResp.cfg.Chain.metadataHolder.GetV0()) - assert.Nil(t, reqResp.cfg.Chain.metadataHolder.GetV1()) - assert.Nil(t, reqResp.cfg.Chain.metadataHolder.GetV2()) - }) - - // Test Altair (should use V1) - t.Run("Altair", func(t *testing.T) { - cfg := &ReqRespConfig{ - Chain: &Chain{ - cfg: &ChainConfig{ - BeaconConfig: ¶ms.BeaconChainConfig{ - AltairForkEpoch: 0, // already activated - FuluForkEpoch: params.BeaconConfig().FarFutureEpoch, - }, - GenesisConfig: &GenesisConfig{ - GenesisTime: time.Now().Add(-time.Hour), // Started 1 hour ago - }, - AttestationSubnetConfig: &SubnetConfig{Subnets: []uint64{0, 1}}, - SyncSubnetConfig: &SubnetConfig{Subnets: []uint64{0}}, - ColumnSubnetConfig: &SubnetConfig{Subnets: []uint64{0}}, - }, - }, - Encoder: encoder.SszNetworkEncoder{}, - Tracer: otel.GetTracerProvider().Tracer("test"), - Meter: otel.GetMeterProvider().Meter("test"), - } - - reqResp, err := NewReqResp(mockHost, cfg) - assert.NoError(t, err) - assert.NotNil(t, reqResp) - assert.Equal(t, 1, reqResp.cfg.Chain.metadataHolder.Version()) - assert.Nil(t, reqResp.cfg.Chain.metadataHolder.GetV0()) - assert.NotNil(t, reqResp.cfg.Chain.metadataHolder.GetV1()) - assert.Nil(t, reqResp.cfg.Chain.metadataHolder.GetV2()) - }) - - // Test Fulu (should use V2) - t.Run("Fulu", func(t *testing.T) { - cfg := &ReqRespConfig{ - Chain: &Chain{ - cfg: &ChainConfig{ - BeaconConfig: ¶ms.BeaconChainConfig{ - AltairForkEpoch: 0, - FuluForkEpoch: 0, // already activated - }, - GenesisConfig: &GenesisConfig{ - GenesisTime: time.Now().Add(-time.Hour), // Started 1 hour ago - }, - AttestationSubnetConfig: &SubnetConfig{Subnets: []uint64{0, 1}}, - SyncSubnetConfig: &SubnetConfig{Subnets: []uint64{0}}, - }, - }, - Encoder: encoder.SszNetworkEncoder{}, - Tracer: otel.GetTracerProvider().Tracer("test"), - Meter: otel.GetMeterProvider().Meter("test"), - } - - reqResp, err := NewReqResp(mockHost, cfg) - assert.NoError(t, err) - assert.NotNil(t, reqResp) - assert.Equal(t, 2, reqResp.cfg.Chain.metadataHolder.Version()) - assert.Nil(t, reqResp.cfg.Chain.metadataHolder.GetV0()) - assert.Nil(t, reqResp.cfg.Chain.metadataHolder.GetV1()) - assert.NotNil(t, reqResp.cfg.Chain.metadataHolder.GetV2()) - - // Check custody group count - count, hasCount := reqResp.cfg.Chain.metadataHolder.CustodyGroupCount() - assert.True(t, hasCount) - assert.Equal(t, uint64(0), count) // TODO: Should be configured value - }) - - // Test without fork config (should default to V1) - t.Run("NoForkConfig", func(t *testing.T) { - cfg := &ReqRespConfig{ - Chain: &Chain{ - cfg: &ChainConfig{ - AttestationSubnetConfig: &SubnetConfig{Subnets: []uint64{0, 1}}, - SyncSubnetConfig: &SubnetConfig{Subnets: []uint64{0}}, - ColumnSubnetConfig: &SubnetConfig{Subnets: []uint64{0}}, - }, - }, - Encoder: encoder.SszNetworkEncoder{}, - Tracer: otel.GetTracerProvider().Tracer("test"), - Meter: otel.GetMeterProvider().Meter("test"), - } - - reqResp, err := NewReqResp(mockHost, cfg) - assert.NoError(t, err) - assert.NotNil(t, reqResp) - assert.Equal(t, 1, reqResp.cfg.Chain.metadataHolder.Version()) // Defaults to V1 - assert.NotNil(t, reqResp.cfg.Chain.metadataHolder.GetV1()) - }) -} diff --git a/eth/reqresp_types.go b/eth/reqresp_types.go index 2d59c04..582093c 100644 --- a/eth/reqresp_types.go +++ b/eth/reqresp_types.go @@ -1,108 +1,36 @@ package eth import ( + "github.com/OffchainLabs/prysm/v6/consensus-types/primitives" pb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1" "github.com/prysmaticlabs/go-bitfield" - - "github.com/attestantio/go-eth2-client/spec/phase0" ) -// Request/Response message types for Ethereum 2.0 P2P protocols -type SSZUint64 uint64 - -// StatusV1 represents the beacon chain status -type StatusV1 struct { - ForkDigest [4]byte `ssz-size:"4"` - FinalizedRoot [32]byte `ssz-size:"32"` - FinalizedEpoch uint64 - HeadRoot [32]byte `ssz-size:"32"` - HeadSlot uint64 -} - -// StatusV2 represents the beacon chain status -type StatusV2 struct { - ForkDigest [4]byte `ssz-size:"4"` - FinalizedRoot [32]byte `ssz-size:"32"` - FinalizedEpoch uint64 - HeadRoot [32]byte `ssz-size:"32"` - HeadSlot uint64 - EarliestAvailableSlot uint64 -} - -// MetaDataV1 represents the peer's metadata (Phase 0) -type MetaDataV1 struct { - SeqNumber uint64 - Attnets [8]byte `ssz-size:"8"` // Bitvector[ATTESTATION_SUBNET_COUNT] -} - -// MetaDataV2 represents the peer's metadata (Altair+ with syncnets) -type MetaDataV2 struct { - SeqNumber uint64 - Attnets [8]byte `ssz-size:"8"` // Bitvector[ATTESTATION_SUBNET_COUNT] - Syncnets [1]byte `ssz-size:"1"` // Bitvector[SYNC_COMMITTEE_SUBNET_COUNT] -} - -// MetaDataV3 represents the peer's metadata (Fulu+ with custody_group_count for PeerDAS) -type MetaDataV3 struct { - SeqNumber uint64 - Attnets [8]byte `ssz-size:"8"` // Bitvector[ATTESTATION_SUBNET_COUNT] - Syncnets [1]byte `ssz-size:"1"` // Bitvector[SYNC_COMMITTEE_SUBNET_COUNT] - CustodyGroupCount uint64 // custody_group_count (cgc) -} - -type BeaconBlocksByRangeRequestV1 struct { - StartSlot uint64 - Count uint64 - Step uint64 -} - -type DataColumnSidecarsByRangeRequestV1 struct { - StartSlot uint64 - Count uint64 - Columns []uint64 -} - -type DataColumnSidecarsByRootRequestV1 []DataColumnByRootIdentifier - -type DataColumnByRootIdentifier struct { - BlockRoot [32]byte `ssz-size:"32"` - Columns []uint64 -} - -type DataColumnSidecarV1 struct { - Index uint64 - Column [][]byte `ssz-max:"4096" ssz-size:"?,2048"` - KzgCommitments [][]byte `ssz-max:"4096" ssz-size:"?,48"` - KzgProofs [][]byte `ssz-max:"4096" ssz-size:"?,48"` - SignedBlockHeader *phase0.SignedBeaconBlockHeader - KzgCommitmentsInclusionProof [][]byte `ssz-size:"4,32"` -} - // StatusHolder wraps different status versions type StatusHolder struct { - v1 *StatusV1 - v2 *StatusV2 + v1 *pb.Status + v2 *pb.StatusV2 } // SetV1 sets the V1 status -func (s *StatusHolder) SetV1(status *StatusV1) { +func (s *StatusHolder) SetV1(status *pb.Status) { s.v1 = status s.v2 = nil } // SetV2 sets the V2 status -func (s *StatusHolder) SetV2(status *StatusV2) { +func (s *StatusHolder) SetV2(status *pb.StatusV2) { s.v2 = status s.v1 = nil } // GetV1 returns the V1 status or nil if not set -func (s *StatusHolder) GetV1() *StatusV1 { +func (s *StatusHolder) GetV1() *pb.Status { return s.v1 } // GetV2 returns the V2 status or nil if not set -func (s *StatusHolder) GetV2() *StatusV2 { +func (s *StatusHolder) GetV2() *pb.StatusV2 { return s.v2 } @@ -112,18 +40,18 @@ func (s *StatusHolder) IsV2() bool { } // ForkDigest returns the fork digest from either version -func (s *StatusHolder) ForkDigest() [4]byte { +func (s *StatusHolder) ForkDigest() []byte { if s.v2 != nil { return s.v2.ForkDigest } if s.v1 != nil { return s.v1.ForkDigest } - return [4]byte{} + return nil } // FinalizedEpoch returns the finalized epoch from either version -func (s *StatusHolder) FinalizedEpoch() uint64 { +func (s *StatusHolder) FinalizedEpoch() primitives.Epoch { if s.v2 != nil { return s.v2.FinalizedEpoch } @@ -134,29 +62,29 @@ func (s *StatusHolder) FinalizedEpoch() uint64 { } // FinalizedRoot returns the finalized root from either version -func (s *StatusHolder) FinalizedRoot() [32]byte { +func (s *StatusHolder) FinalizedRoot() []byte { if s.v2 != nil { return s.v2.FinalizedRoot } if s.v1 != nil { return s.v1.FinalizedRoot } - return [32]byte{} + return nil } // HeadRoot returns the head root from either version func (s *StatusHolder) HeadRoot() []byte { if s.v2 != nil { - return s.v2.HeadRoot[:] + return s.v2.HeadRoot } if s.v1 != nil { - return s.v1.HeadRoot[:] + return s.v1.HeadRoot } return nil } // HeadSlot returns the head slot from either version -func (s *StatusHolder) HeadSlot() uint64 { +func (s *StatusHolder) HeadSlot() primitives.Slot { if s.v2 != nil { return s.v2.HeadSlot } @@ -167,7 +95,7 @@ func (s *StatusHolder) HeadSlot() uint64 { } // EarliestAvailableSlot returns the earliest available slot if V2, otherwise returns 0 and false -func (s *StatusHolder) EarliestAvailableSlot() (uint64, bool) { +func (s *StatusHolder) EarliestAvailableSlot() (primitives.Slot, bool) { if s.v2 != nil { return s.v2.EarliestAvailableSlot, true } diff --git a/go.mod b/go.mod index 49260cf..d5a9652 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/probe-lab/hermes go 1.25.1 require ( - github.com/OffchainLabs/prysm/v6 v6.1.2 + github.com/OffchainLabs/prysm/v6 v6.1.4 github.com/aws/aws-sdk-go-v2 v1.32.7 github.com/aws/aws-sdk-go-v2/config v1.28.7 github.com/aws/aws-sdk-go-v2/credentials v1.17.48 @@ -12,6 +12,7 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 github.com/dennis-tra/go-kinesis v0.0.0-20240326083914-7acf5f8dc24e github.com/ethereum/go-ethereum v1.15.11 + github.com/ferranbt/fastssz v1.0.0 github.com/filecoin-project/go-f3 v0.8.4 github.com/filecoin-project/lotus v1.32.2 github.com/golang/snappy v0.0.5-0.20231225225746-43d5d4cd4e0e @@ -27,13 +28,10 @@ require ( github.com/lmittmann/tint v1.0.6 github.com/multiformats/go-multiaddr v0.16.0 github.com/parquet-go/parquet-go v0.24.0 - github.com/pk910/dynamic-ssz v1.1.1 - github.com/pkg/errors v0.9.1 github.com/probe-lab/eth-das-guardian v0.2.2 github.com/prometheus/client_golang v1.22.0 github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516 github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 - github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.10.0 github.com/thejerf/suture/v4 v4.0.6 github.com/urfave/cli/v2 v2.27.5 @@ -101,7 +99,6 @@ require ( github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/ferranbt/fastssz v1.0.0 // indirect github.com/filecoin-project/go-address v1.2.0 // indirect github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 // indirect github.com/filecoin-project/go-amt-ipld/v3 v3.1.0 // indirect @@ -133,6 +130,7 @@ require ( github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/gopacket v1.1.19 // indirect @@ -180,6 +178,7 @@ require ( github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/miekg/dns v1.1.66 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect @@ -228,11 +227,14 @@ require ( github.com/pion/transport/v3 v3.0.7 // indirect github.com/pion/turn/v4 v4.0.1 // indirect github.com/pion/webrtc/v4 v4.1.0 // indirect + github.com/pk910/dynamic-ssz v1.1.1 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/polydawn/refmt v0.89.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.63.0 // indirect github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/prom2json v1.3.0 // indirect github.com/prysmaticlabs/gohashtree v0.0.5-beta // indirect github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c // indirect github.com/quic-go/qpack v0.5.1 // indirect @@ -244,6 +246,7 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/progressbar/v3 v3.17.1 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/stretchr/objx v0.5.2 // indirect @@ -252,6 +255,7 @@ require ( github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/numcpus v0.9.0 // indirect + github.com/trailofbits/go-mutexasserts v0.0.0-20250212181730-4c2b8e9e784b // indirect github.com/wealdtech/go-bytesutil v1.2.1 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect diff --git a/go.sum b/go.sum index e26047f..81f52da 100644 --- a/go.sum +++ b/go.sum @@ -21,6 +21,8 @@ github.com/OffchainLabs/hashtree v0.2.1-0.20250530191054-577f0b75c7f7 h1:0r1HjEx github.com/OffchainLabs/hashtree v0.2.1-0.20250530191054-577f0b75c7f7/go.mod h1:b07+cRZs+eAR8TR57CB9TQlt5Gnl/06Xs76xt/1wq0M= github.com/OffchainLabs/prysm/v6 v6.1.2 h1:Kzu4BE6R39fj+Tx1Fmr1amNl60+eUnH+mS/YBQPVpF0= github.com/OffchainLabs/prysm/v6 v6.1.2/go.mod h1:VbMsULGbZkgM4kwbKxb/ywhhR/EtebwGPIAszIU59Ws= +github.com/OffchainLabs/prysm/v6 v6.1.4 h1:gwLBbGaYsEh9zpZL337uVjXPX3F86UNJ7KIiFiPsY7c= +github.com/OffchainLabs/prysm/v6 v6.1.4/go.mod h1:VbMsULGbZkgM4kwbKxb/ywhhR/EtebwGPIAszIU59Ws= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s= @@ -45,8 +47,6 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/attestantio/go-eth2-client v0.26.1-0.20250812165705-a4bcce29e341 h1:dU/4MfssPnMP8EQ0UNHnJp5JprVyt7lbmULp/LDWAT8= -github.com/attestantio/go-eth2-client v0.26.1-0.20250812165705-a4bcce29e341/go.mod h1:fvULSL9WtNskkOB4i+Yyr6BKpNHXvmpGZj9969fCrfY= github.com/attestantio/go-eth2-client v0.27.1 h1:g7bm+gG/p+gfzYdEuxuAepVWYb8EO+2KojV5/Lo2BxM= github.com/attestantio/go-eth2-client v0.27.1/go.mod h1:fvULSL9WtNskkOB4i+Yyr6BKpNHXvmpGZj9969fCrfY= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= @@ -638,6 +638,7 @@ github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYW github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= github.com/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU= @@ -764,6 +765,8 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= @@ -1028,6 +1031,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/prom2json v1.3.0 h1:BlqrtbT9lLH3ZsOVhXPsHzFrApCTKRifB7gjJuypu6Y= +github.com/prometheus/prom2json v1.3.0/go.mod h1:rMN7m0ApCowcoDlypBHlkNbp5eJQf/+1isKykIP5ZnM= github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516 h1:xuVAdtz5ShYblG2sPyb4gw01DF8InbOI/kBCQjk7NiM= github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516/go.mod h1:h2OlIZD/M6wFvV3YMZbW16lFgh3Rsye00G44J2cwLyU= github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 h1:lC8kiphgdOBTcbTvo8MwkvpKjO0SlAgjv4xIK5FGJ94= @@ -1163,6 +1168,8 @@ github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYN github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo= github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/trailofbits/go-mutexasserts v0.0.0-20250212181730-4c2b8e9e784b h1:EBoYk5zHOfuHDBqLFx4eSPRVcbnW+L3aFJzoCi8zRnk= +github.com/trailofbits/go-mutexasserts v0.0.0-20250212181730-4c2b8e9e784b/go.mod h1:4R6Qam+w871wOlyRq59zRLjhb5x9/De/wgPeaCTaCwI= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= diff --git a/host/event_types.go b/host/event_types.go index 8fabecd..5fa1669 100644 --- a/host/event_types.go +++ b/host/event_types.go @@ -1,11 +1,15 @@ package host -import "strings" +import ( + "fmt" + "strings" +) // EventTypeFromBeaconChainProtocol returns the event type for a given protocol string. func EventTypeFromBeaconChainProtocol(protocol string) string { // Usual protocol string: /eth2/beacon_chain/req/metadata/2/ssz_snappy parts := strings.Split(protocol, "/") + fmt.Println(parts) if len(parts) > 4 { return "HANDLE_" + strings.ToUpper(parts[4]) } From fdc1d3d3ec3992b75b9e80ea675f8ac455f99c94 Mon Sep 17 00:00:00 2001 From: Mikel Cortes <45786396+cortze@users.noreply.github.com> Date: Thu, 30 Oct 2025 18:31:49 +0100 Subject: [PATCH 61/65] tidy work --- go.sum | 2 -- 1 file changed, 2 deletions(-) diff --git a/go.sum b/go.sum index 81f52da..ce52743 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,6 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/OffchainLabs/hashtree v0.2.1-0.20250530191054-577f0b75c7f7 h1:0r1HjExe/tyypkt380UTpjvILd5kLw51Xzl6a+hknQ8= github.com/OffchainLabs/hashtree v0.2.1-0.20250530191054-577f0b75c7f7/go.mod h1:b07+cRZs+eAR8TR57CB9TQlt5Gnl/06Xs76xt/1wq0M= -github.com/OffchainLabs/prysm/v6 v6.1.2 h1:Kzu4BE6R39fj+Tx1Fmr1amNl60+eUnH+mS/YBQPVpF0= -github.com/OffchainLabs/prysm/v6 v6.1.2/go.mod h1:VbMsULGbZkgM4kwbKxb/ywhhR/EtebwGPIAszIU59Ws= github.com/OffchainLabs/prysm/v6 v6.1.4 h1:gwLBbGaYsEh9zpZL337uVjXPX3F86UNJ7KIiFiPsY7c= github.com/OffchainLabs/prysm/v6 v6.1.4/go.mod h1:VbMsULGbZkgM4kwbKxb/ywhhR/EtebwGPIAszIU59Ws= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= From 7fa0d142d8c2783239c7f373dbf335df9e4dd6a5 Mon Sep 17 00:00:00 2001 From: Mikel Cortes <45786396+cortze@users.noreply.github.com> Date: Thu, 30 Oct 2025 18:53:27 +0100 Subject: [PATCH 62/65] remove reqs by root and range --- eth/reqresp.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/eth/reqresp.go b/eth/reqresp.go index 553cef1..d77a266 100644 --- a/eth/reqresp.go +++ b/eth/reqresp.go @@ -120,13 +120,13 @@ func (r *ReqResp) RegisterHandlers(ctx context.Context) error { p2p.RPCMetaDataTopicV1: r.metadataV1Handler, p2p.RPCMetaDataTopicV2: r.metadataV2Handler, p2p.RPCMetaDataTopicV3: r.metadataV3Handler, - // TODO: get this back online + // TODO: this is just a test to see if we can avoid the extra BW // p2p.RPCBlocksByRangeTopicV2: r.blocksByRangeV2Handler, // p2p.RPCBlocksByRootTopicV2: r.blocksByRootV2Handler, // p2p.RPCBlobSidecarsByRangeTopicV1: r.blobsByRangeV2Handler, // p2p.RPCBlobSidecarsByRootTopicV1: r.blobsByRootV2Handler, - p2p.RPCDataColumnSidecarsByRangeTopicV1: r.DataColumnsByRangeV1Handler, - p2p.RPCDataColumnSidecarsByRootTopicV1: r.DataColumnsByRootV1Handler, + // p2p.RPCDataColumnSidecarsByRangeTopicV1: r.DataColumnsByRangeV1Handler, + // p2p.RPCDataColumnSidecarsByRootTopicV1: r.DataColumnsByRootV1Handler, } for id, handler := range handlers { @@ -393,7 +393,7 @@ func (r *ReqResp) metadataV1Handler(ctx context.Context, stream network.Stream) "Attnets": hex.EncodeToString(metaData.Attnets.Bytes()), } - slog.Info( + slog.Debug( "metadata response", "peer", stream.Conn().RemotePeer().String(), "attnets", metaData.Attnets, @@ -423,7 +423,7 @@ func (r *ReqResp) metadataV2Handler(ctx context.Context, stream network.Stream) "Attnets": hex.EncodeToString(metaData.Attnets.Bytes()), "Syncnets": hex.EncodeToString(metaData.Syncnets.Bytes()), } - slog.Info( + slog.Debug( "metadata response", "peer", stream.Conn().RemotePeer().String(), "attnets", metaData.Attnets, @@ -458,7 +458,7 @@ func (r *ReqResp) metadataV3Handler(ctx context.Context, stream network.Stream) traceData["Syncnets"] = hex.EncodeToString(metaData.Syncnets.Bytes()) } - slog.Info( + slog.Debug( "metadata V3 response", "attnets", metaData.Attnets, "synccommittees", metaData.Syncnets, From f82ab0309a827f3629b9bb26fbd3b10a64940330 Mon Sep 17 00:00:00 2001 From: Mikel Cortes <45786396+cortze@users.noreply.github.com> Date: Thu, 30 Oct 2025 19:05:01 +0100 Subject: [PATCH 63/65] more changes --- eth/discovery.go | 2 +- host/event_types.go | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/eth/discovery.go b/eth/discovery.go index 1830e47..da7dd31 100644 --- a/eth/discovery.go +++ b/eth/discovery.go @@ -57,7 +57,7 @@ func NewDiscovery(privKey *ecdsa.PrivateKey, cfg *DiscoveryConfig) (*Discovery, localNode.Set(cfg.enrAttnetsEntry()) localNode.Set(cfg.enrSyncnetsEntry()) localNode.Set(cfg.enrCustodyEntry()) - localNode.SetFallbackIP(net.ParseIP("127.0.0.1")) + localNode.SetFallbackIP(ip) localNode.SetFallbackUDP(cfg.TCPPort) enrEth2Entry, err := cfg.enrEth2Entry() diff --git a/host/event_types.go b/host/event_types.go index 5fa1669..bfcc059 100644 --- a/host/event_types.go +++ b/host/event_types.go @@ -1,7 +1,6 @@ package host import ( - "fmt" "strings" ) @@ -9,7 +8,6 @@ import ( func EventTypeFromBeaconChainProtocol(protocol string) string { // Usual protocol string: /eth2/beacon_chain/req/metadata/2/ssz_snappy parts := strings.Split(protocol, "/") - fmt.Println(parts) if len(parts) > 4 { return "HANDLE_" + strings.ToUpper(parts[4]) } From f3057908c819ecf2d07922b4f417cc271374d0d0 Mon Sep 17 00:00:00 2001 From: Mikel Cortes <45786396+cortze@users.noreply.github.com> Date: Fri, 31 Oct 2025 13:06:22 +0100 Subject: [PATCH 64/65] address comments from dennis --- eth/chain.go | 2 +- go.mod | 4 +--- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/eth/chain.go b/eth/chain.go index da72a34..d2bd579 100644 --- a/eth/chain.go +++ b/eth/chain.go @@ -113,7 +113,7 @@ func (c *Chain) init(ctx context.Context) error { slog.Warn("Failed to fetch BlobSchedule from Prysm", tele.LogAttrError(err)) } - // try to always set the highest versions (versions bellow can be obtained from there) + // try to always set the highest versions (versions below can be obtained from there) // Status st := &pb.StatusV2{ ForkDigest: forkDigest[:], diff --git a/go.mod b/go.mod index d5a9652..a6bfec2 100644 --- a/go.mod +++ b/go.mod @@ -172,7 +172,7 @@ require ( github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-netroute v0.2.2 // indirect github.com/libp2p/go-reuseport v0.4.0 // indirect - github.com/libp2p/go-yamux/v5 v5.0.1 // indirect + github.com/libp2p/go-yamux/v5 v5.1.0 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect @@ -301,5 +301,3 @@ require ( sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) - -replace github.com/libp2p/go-yamux/v5 => github.com/dennis-tra/go-yamux/v5 v5.0.0-20250519183055-dde4b3083558 diff --git a/go.sum b/go.sum index ce52743..4e2ec68 100644 --- a/go.sum +++ b/go.sum @@ -200,8 +200,6 @@ github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbz github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= github.com/dennis-tra/go-kinesis v0.0.0-20240326083914-7acf5f8dc24e h1:y6QyYh8YZyRQDdfnQqUgC5tRBmEwUFAjavnybKboCm4= github.com/dennis-tra/go-kinesis v0.0.0-20240326083914-7acf5f8dc24e/go.mod h1:5Hm3EOeNP1/lYm9qcFwWgYgjixQilwcZA+hZ05bUz54= -github.com/dennis-tra/go-yamux/v5 v5.0.0-20250519183055-dde4b3083558 h1:N0mn/xSyVdXgfM493L8j38ukJme3ktY2Hf6L9UnR5vQ= -github.com/dennis-tra/go-yamux/v5 v5.0.0-20250519183055-dde4b3083558/go.mod h1:tgIQ07ObtRR/I0IWsFOyQIL9/dR5UXgc2s8xKmNZv1o= github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM= github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI= @@ -734,6 +732,8 @@ github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjV github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo= github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux/v5 v5.1.0 h1:8Qlxj4E9JGJAQVW6+uj2o7mqkqsIVlSUGmTWhlXzoHE= +github.com/libp2p/go-yamux/v5 v5.1.0/go.mod h1:tgIQ07ObtRR/I0IWsFOyQIL9/dR5UXgc2s8xKmNZv1o= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lmittmann/tint v1.0.6 h1:vkkuDAZXc0EFGNzYjWcV0h7eEX+uujH48f/ifSkJWgc= From 1f7504706c595ff916afe514b4b4d288c9ccf8b0 Mon Sep 17 00:00:00 2001 From: Mikel Cortes <45786396+cortze@users.noreply.github.com> Date: Fri, 31 Oct 2025 16:41:27 +0100 Subject: [PATCH 65/65] update go-ymux + missing stream reset --- eth/reqresp.go | 1 + go.mod | 122 ++++++++++------------ go.sum | 269 +++++++++++++++++++++---------------------------- 3 files changed, 169 insertions(+), 223 deletions(-) diff --git a/eth/reqresp.go b/eth/reqresp.go index d77a266..477ce35 100644 --- a/eth/reqresp.go +++ b/eth/reqresp.go @@ -996,6 +996,7 @@ func (r *ReqResp) BlocksByRangeV2(ctx context.Context, pid peer.ID, firstSlot, l return nil, fmt.Errorf("reading block_by_range request: %w", err) } if err := process(blk); err != nil { + stream.Reset() return nil, fmt.Errorf("processing block_by_range chunk: %w", err) } } diff --git a/go.mod b/go.mod index a6bfec2..bb1f977 100644 --- a/go.mod +++ b/go.mod @@ -20,33 +20,33 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/iand/pontium v0.3.15 github.com/ipni/go-libipni v0.6.18 - github.com/klauspost/compress v1.18.0 - github.com/libp2p/go-libp2p v0.41.1 + github.com/klauspost/compress v1.18.1 + github.com/libp2p/go-libp2p v0.44.0 github.com/libp2p/go-libp2p-kad-dht v0.33.0 - github.com/libp2p/go-libp2p-mplex v0.10.0 + github.com/libp2p/go-libp2p-mplex v0.11.0 github.com/libp2p/go-libp2p-pubsub v0.15.0 github.com/lmittmann/tint v1.0.6 - github.com/multiformats/go-multiaddr v0.16.0 + github.com/multiformats/go-multiaddr v0.16.1 github.com/parquet-go/parquet-go v0.24.0 github.com/probe-lab/eth-das-guardian v0.2.2 - github.com/prometheus/client_golang v1.22.0 + github.com/prometheus/client_golang v1.23.2 github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516 github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 - github.com/stretchr/testify v1.10.0 + github.com/stretchr/testify v1.11.1 github.com/thejerf/suture/v4 v4.0.6 github.com/urfave/cli/v2 v2.27.5 github.com/whyrusleeping/cbor-gen v0.3.1 - go.opentelemetry.io/otel v1.36.0 + go.opentelemetry.io/otel v1.38.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 go.opentelemetry.io/otel/exporters/prometheus v0.55.0 - go.opentelemetry.io/otel/metric v1.36.0 + go.opentelemetry.io/otel/metric v1.38.0 go.opentelemetry.io/otel/sdk v1.34.0 go.opentelemetry.io/otel/sdk/metric v1.34.0 - go.opentelemetry.io/otel/trace v1.36.0 - golang.org/x/crypto v0.42.0 - golang.org/x/time v0.11.0 + go.opentelemetry.io/otel/trace v1.38.0 + golang.org/x/crypto v0.43.0 + golang.org/x/time v0.14.0 google.golang.org/grpc v1.71.0 - google.golang.org/protobuf v1.36.6 + google.golang.org/protobuf v1.36.10 gopkg.in/yaml.v3 v3.0.1 ) @@ -80,10 +80,7 @@ require ( github.com/casbin/govaluate v1.8.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/consensys/bavard v0.1.27 // indirect - github.com/consensys/gnark-crypto v0.16.0 // indirect - github.com/containerd/cgroups v1.1.0 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/consensys/gnark-crypto v0.18.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/crate-crypto/go-eth-kzg v1.3.0 // indirect github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect @@ -92,9 +89,7 @@ require ( github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/deckarep/golang-set/v2 v2.7.0 // indirect github.com/dgraph-io/ristretto/v2 v2.2.0 // indirect - github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/elastic/gosigar v0.14.3 // indirect github.com/emicklei/dot v1.9.0 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect @@ -107,8 +102,8 @@ require ( github.com/filecoin-project/go-clock v0.1.0 // indirect github.com/filecoin-project/go-hamt-ipld v0.1.5 // indirect github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 // indirect - github.com/filecoin-project/go-hamt-ipld/v3 v3.4.0 // indirect - github.com/filecoin-project/go-state-types v0.16.0 // indirect + github.com/filecoin-project/go-hamt-ipld/v3 v3.4.1 // indirect + github.com/filecoin-project/go-state-types v0.17.0 // indirect github.com/filecoin-project/specs-actors v0.9.15 // indirect github.com/filecoin-project/specs-actors/v2 v2.3.6 // indirect github.com/filecoin-project/specs-actors/v3 v3.1.2 // indirect @@ -124,9 +119,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-openapi/jsonreference v0.20.4 // indirect - github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/goccy/go-yaml v1.18.0 // indirect - github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect @@ -134,7 +127,6 @@ require ( github.com/google/go-cmp v0.7.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20250501235452-c0086092b71a // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect @@ -144,13 +136,13 @@ require ( github.com/invopop/jsonschema v0.12.0 // indirect github.com/ipfs/boxo v0.30.0 // indirect github.com/ipfs/go-block-format v0.2.0 // indirect - github.com/ipfs/go-cid v0.5.0 // indirect - github.com/ipfs/go-datastore v0.8.2 // indirect + github.com/ipfs/go-cid v0.6.0 // indirect + github.com/ipfs/go-datastore v0.9.0 // indirect github.com/ipfs/go-ipfs-util v0.0.3 // indirect github.com/ipfs/go-ipld-cbor v0.2.0 // indirect github.com/ipfs/go-ipld-format v0.6.0 // indirect github.com/ipfs/go-log v1.0.5 // indirect - github.com/ipfs/go-log/v2 v2.6.0 // indirect + github.com/ipfs/go-log/v2 v2.8.2 // indirect github.com/ipld/go-ipld-prime v0.21.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect @@ -158,35 +150,34 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect - github.com/koron/go-ssdp v0.0.6 // indirect + github.com/koron/go-ssdp v0.1.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect - github.com/libp2p/go-flow-metrics v0.2.0 // indirect + github.com/libp2p/go-flow-metrics v0.3.0 // indirect github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect github.com/libp2p/go-libp2p-kbucket v0.7.0 // indirect github.com/libp2p/go-libp2p-record v0.3.1 // indirect github.com/libp2p/go-libp2p-routing-helpers v0.7.5 // indirect github.com/libp2p/go-mplex v0.7.0 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect - github.com/libp2p/go-netroute v0.2.2 // indirect + github.com/libp2p/go-netroute v0.4.0 // indirect github.com/libp2p/go-reuseport v0.4.0 // indirect - github.com/libp2p/go-yamux/v5 v5.1.0 // indirect + github.com/libp2p/go-yamux/v5 v5.0.1 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/miekg/dns v1.1.66 // indirect + github.com/miekg/dns v1.1.68 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/minio/highwayhash v1.0.3 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect @@ -196,53 +187,51 @@ require ( github.com/multiformats/go-multiaddr-dns v0.4.1 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect - github.com/multiformats/go-multicodec v0.9.1 // indirect + github.com/multiformats/go-multicodec v0.10.0 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect github.com/multiformats/go-multistream v0.6.1 // indirect - github.com/multiformats/go-varint v0.0.7 // indirect + github.com/multiformats/go-varint v0.1.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/onsi/ginkgo/v2 v2.23.4 // indirect - github.com/opencontainers/runtime-spec v1.2.1 // indirect + github.com/onsi/gomega v1.36.3 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pion/datachannel v1.5.10 // indirect github.com/pion/dtls/v2 v2.2.12 // indirect - github.com/pion/dtls/v3 v3.0.6 // indirect + github.com/pion/dtls/v3 v3.0.7 // indirect github.com/pion/ice/v4 v4.0.10 // indirect - github.com/pion/interceptor v0.1.39 // indirect - github.com/pion/logging v0.2.3 // indirect + github.com/pion/interceptor v0.1.41 // indirect + github.com/pion/logging v0.2.4 // indirect github.com/pion/mdns/v2 v2.0.7 // indirect github.com/pion/randutil v0.1.0 // indirect - github.com/pion/rtcp v1.2.15 // indirect - github.com/pion/rtp v1.8.21 // indirect - github.com/pion/sctp v1.8.39 // indirect - github.com/pion/sdp/v3 v3.0.11 // indirect - github.com/pion/srtp/v3 v3.0.4 // indirect + github.com/pion/rtcp v1.2.16 // indirect + github.com/pion/rtp v1.8.25 // indirect + github.com/pion/sctp v1.8.40 // indirect + github.com/pion/sdp/v3 v3.0.16 // indirect + github.com/pion/srtp/v3 v3.0.8 // indirect github.com/pion/stun v0.6.1 // indirect - github.com/pion/stun/v3 v3.0.0 // indirect + github.com/pion/stun/v3 v3.0.1 // indirect github.com/pion/transport/v2 v2.2.10 // indirect - github.com/pion/transport/v3 v3.0.7 // indirect - github.com/pion/turn/v4 v4.0.1 // indirect - github.com/pion/webrtc/v4 v4.1.0 // indirect + github.com/pion/transport/v3 v3.0.8 // indirect + github.com/pion/turn/v4 v4.1.2 // indirect + github.com/pion/webrtc/v4 v4.1.6 // indirect github.com/pk910/dynamic-ssz v1.1.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/polydawn/refmt v0.89.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.63.0 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.2 // indirect + github.com/prometheus/procfs v0.19.2 // indirect github.com/prometheus/prom2json v1.3.0 // indirect github.com/prysmaticlabs/gohashtree v0.0.5-beta // indirect github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c // indirect github.com/quic-go/qpack v0.5.1 // indirect - github.com/quic-go/quic-go v0.51.0 // indirect - github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 // indirect - github.com/raulk/go-watchdog v1.3.0 // indirect + github.com/quic-go/quic-go v0.55.0 // indirect + github.com/quic-go/webtransport-go v0.9.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/rogpeppe/go-internal v1.13.1 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/progressbar/v3 v3.17.1 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect @@ -264,27 +253,27 @@ require ( github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.etcd.io/bbolt v1.3.11 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 // indirect go.opentelemetry.io/proto/otlp v1.5.0 // indirect - go.uber.org/automaxprocs v1.6.0 // indirect go.uber.org/dig v1.19.0 // indirect go.uber.org/fx v1.24.0 // indirect - go.uber.org/mock v0.5.2 // indirect + go.uber.org/mock v0.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 // indirect - golang.org/x/mod v0.28.0 // indirect - golang.org/x/net v0.44.0 // indirect - golang.org/x/oauth2 v0.25.0 // indirect + go.yaml.in/yaml/v2 v2.4.3 // indirect + golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect + golang.org/x/mod v0.29.0 // indirect + golang.org/x/net v0.46.0 // indirect + golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/sync v0.17.0 // indirect - golang.org/x/sys v0.36.0 // indirect - golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 // indirect - golang.org/x/term v0.35.0 // indirect - golang.org/x/text v0.29.0 // indirect - golang.org/x/tools v0.37.0 // indirect + golang.org/x/sys v0.37.0 // indirect + golang.org/x/telemetry v0.0.0-20251028164327-d7a2859f34e8 // indirect + golang.org/x/term v0.36.0 // indirect + golang.org/x/text v0.30.0 // indirect + golang.org/x/tools v0.38.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gonum.org/v1/gonum v0.16.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b // indirect @@ -296,7 +285,6 @@ require ( k8s.io/klog/v2 v2.130.1 // indirect k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect lukechampine.com/blake3 v1.4.1 // indirect - rsc.io/tmplfunc v0.0.3 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/go.sum b/go.sum index 4e2ec68..f74d27c 100644 --- a/go.sum +++ b/go.sum @@ -92,7 +92,6 @@ github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPn github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/bazelbuild/rules_go v0.23.2 h1:Wxu7JjqnF78cKZbsBsARLSXx/jlGaSLCnUV3mTlyHvM= github.com/bazelbuild/rules_go v0.23.2/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M= -github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -136,7 +135,6 @@ github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= @@ -153,23 +151,14 @@ github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/consensys/bavard v0.1.27 h1:j6hKUrGAy/H+gpNrpLU3I26n1yc+VMGmd6ID5+gAhOs= -github.com/consensys/bavard v0.1.27/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs= -github.com/consensys/gnark-crypto v0.16.0 h1:8Dl4eYmUWK9WmlP1Bj6je688gBRJCJbT8Mw4KoTAawo= -github.com/consensys/gnark-crypto v0.16.0/go.mod h1:Ke3j06ndtPTVvo++PhGNgvm+lgpLvzbcE2MqljY7diU= -github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= -github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= -github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/consensys/gnark-crypto v0.18.1 h1:RyLV6UhPRoYYzaFnPQA4qK3DyuDgkTgskDdoGqFt3fI= +github.com/consensys/gnark-crypto v0.18.1/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/crate-crypto/go-eth-kzg v1.3.0 h1:05GrhASN9kDAidaFJOda6A4BEvgvuXbazXg/0E3OOdI= @@ -207,7 +196,6 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38= github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -218,9 +206,6 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= -github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/uo= -github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/emicklei/dot v1.9.0 h1:FyaJNctdMfaEIbTQ1FkKZ1UCZyJJSkyvkrXOVoNZPKU= github.com/emicklei/dot v1.9.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= @@ -270,14 +255,14 @@ github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 h1:b3UDemBYN2HNfk3KOXNuxgTTxl github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0/go.mod h1:7aWZdaQ1b16BVoQUYR+eEvrDCGJoPLxFpDynFjYfBjI= github.com/filecoin-project/go-hamt-ipld/v3 v3.0.1/go.mod h1:gXpNmr3oQx8l3o7qkGyDjJjYSRX7hp/FGOStdqrWyDI= github.com/filecoin-project/go-hamt-ipld/v3 v3.1.0/go.mod h1:bxmzgT8tmeVQA1/gvBwFmYdT8SOFUwB3ovSUfG1Ux0g= -github.com/filecoin-project/go-hamt-ipld/v3 v3.4.0 h1:nYs6OPUF8KbZ3E8o9p9HJnQaE8iugjHR5WYVMcicDJc= -github.com/filecoin-project/go-hamt-ipld/v3 v3.4.0/go.mod h1:s0qiHRhFyrgW0SvdQMSJFQxNa4xEIG5XvqCBZUEgcbc= +github.com/filecoin-project/go-hamt-ipld/v3 v3.4.1 h1:wl+ZHruCcE9LvwU7blpwWn35XOcRS6+IBg75G7ZzxzY= +github.com/filecoin-project/go-hamt-ipld/v3 v3.4.1/go.mod h1:AqjryNfkxffpnqsa5mwnJHlazhVqF6W2nilu+VYKIq8= github.com/filecoin-project/go-state-types v0.0.0-20200928172055-2df22083d8ab/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-state-types v0.0.0-20201102161440-c8033295a1fc/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-state-types v0.1.0/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-state-types v0.1.6/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= -github.com/filecoin-project/go-state-types v0.16.0 h1:ajIREDzTGfq71ofIQ29iZR1WXxmkvd2nQNc6ApcP1wI= -github.com/filecoin-project/go-state-types v0.16.0/go.mod h1:YCESyrqnyu17y0MazbV6Uwma5+BrMvEKEQp5QWeIf9g= +github.com/filecoin-project/go-state-types v0.17.0 h1:HpBb6G+VSOOI6rQFSnvPVyRsnms8je94cwvU69DJ+9Y= +github.com/filecoin-project/go-state-types v0.17.0/go.mod h1:em4yo9mglrdyHbcsxelHCSKMjLdJLddLERWQe6J8vYc= github.com/filecoin-project/lotus v1.32.2 h1:UQsJgLeZVKE7dPc171va7LlIBYN5XTSqrCs8hooGcik= github.com/filecoin-project/lotus v1.32.2/go.mod h1:eNfZ0eXGMckDBFQmL1/MJk/0UgxVKHy74z40uMrGlg4= github.com/filecoin-project/specs-actors v0.9.13/go.mod h1:TS1AW/7LbG+615j4NsjMK1qlpAwaFsG9w0V2tg2gSao= @@ -343,15 +328,9 @@ github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= -github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= -github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -396,7 +375,6 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -411,10 +389,7 @@ github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20250501235452-c0086092b71a h1:rDA3FfmxwXR+BVKKdz55WwMJ1pD2hJQNW31d+l3mPk4= -github.com/google/pprof v0.0.0-20250501235452-c0086092b71a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -523,12 +498,12 @@ github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67Fexh github.com/ipfs/go-cid v0.0.6-0.20200501230655-7c82f3b81c00/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -github.com/ipfs/go-cid v0.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg= -github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk= +github.com/ipfs/go-cid v0.6.0 h1:DlOReBV1xhHBhhfy/gBNNTSyfOM6rLiIx9J7A4DGf30= +github.com/ipfs/go-cid v0.6.0/go.mod h1:NC4kS1LZjzfhK40UGmpXv5/qD2kcMzACYJNntCUiDhQ= github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= -github.com/ipfs/go-datastore v0.8.2 h1:Jy3wjqQR6sg/LhyY0NIePZC3Vux19nLtg7dx0TVqr6U= -github.com/ipfs/go-datastore v0.8.2/go.mod h1:W+pI1NsUsz3tcsAACMtfC+IZdnQTnC/7VfPoJBQuts0= +github.com/ipfs/go-datastore v0.9.0 h1:WocriPOayqalEsueHv6SdD4nPVl4rYMfYGLD4bqCZ+w= +github.com/ipfs/go-datastore v0.9.0/go.mod h1:uT77w/XEGrvJWwHgdrMr8bqCN6ZTW9gzmi+3uK+ouHg= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= @@ -566,8 +541,8 @@ github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= -github.com/ipfs/go-log/v2 v2.6.0 h1:2Nu1KKQQ2ayonKp4MPo6pXCjqw1ULc9iohRqWV5EYqg= -github.com/ipfs/go-log/v2 v2.6.0/go.mod h1:p+Efr3qaY5YXpx9TX7MoLCSEZX5boSWj9wh86P5HJa8= +github.com/ipfs/go-log/v2 v2.8.2 h1:nVG4nNHUwwI/sTs9Bi5iE8sXFQwXs3AjkkuWhg7+Y2I= +github.com/ipfs/go-log/v2 v2.8.2/go.mod h1:UhIYAwMV7Nb4ZmihUxfIRM2Istw/y9cAk3xaK+4Zs2c= github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= github.com/ipfs/go-merkledag v0.2.4/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= @@ -629,16 +604,16 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= +github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= -github.com/koron/go-ssdp v0.0.6 h1:Jb0h04599eq/CY7rB5YEqPS83HmRfHP2azkxMN2rFtU= -github.com/koron/go-ssdp v0.0.6/go.mod h1:0R9LfRJGek1zWTjN3JUNlm5INCDYGpRDfAptnct63fI= +github.com/koron/go-ssdp v0.1.0 h1:ckl5x5H6qSNFmi+wCuROvvGUu2FQnMbQrU95IHCcv3Y= +github.com/koron/go-ssdp v0.1.0/go.mod h1:GltaDBjtK1kemZOusWYLGotV0kBeEf59Bp0wtSB0uyU= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -663,12 +638,12 @@ github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38y github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= -github.com/libp2p/go-flow-metrics v0.2.0 h1:EIZzjmeOE6c8Dav0sNv35vhZxATIXWZg6j/C08XmmDw= -github.com/libp2p/go-flow-metrics v0.2.0/go.mod h1:st3qqfu8+pMfh+9Mzqb2GTiwrAGjIPszEjZmtksN8Jc= +github.com/libp2p/go-flow-metrics v0.3.0 h1:q31zcHUvHnwDO0SHaukewPYgwOBSxtt830uJtUx6784= +github.com/libp2p/go-flow-metrics v0.3.0/go.mod h1:nuhlreIwEguM1IvHAew3ij7A8BMlyHQJ279ao24eZZo= github.com/libp2p/go-libp2p v0.1.0/go.mod h1:6D/2OBauqLUoqcADOJpn9WbKqvaM07tDw68qHM0BxUM= github.com/libp2p/go-libp2p v0.1.1/go.mod h1:I00BRo1UuUSdpuc8Q2mN7yDF/oTUTRAX6JWpTiK9Rp8= -github.com/libp2p/go-libp2p v0.41.1 h1:8ecNQVT5ev/jqALTvisSJeVNvXYJyK4NhQx1nNRXQZE= -github.com/libp2p/go-libp2p v0.41.1/go.mod h1:DcGTovJzQl/I7HMrby5ZRjeD0kQkGiy+9w6aEkSZpRI= +github.com/libp2p/go-libp2p v0.44.0 h1:5Gtt8OrF8yiXmH+Mx4+/iBeFRMK1TY3a8OrEBDEqAvs= +github.com/libp2p/go-libp2p v0.44.0/go.mod h1:NovCojezAt4dnDd4fH048K7PKEqH0UFYYqJRjIIu8zc= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= @@ -686,8 +661,8 @@ github.com/libp2p/go-libp2p-kbucket v0.7.0/go.mod h1:blOINGIj1yiPYlVEX0Rj9QwEkmV github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= -github.com/libp2p/go-libp2p-mplex v0.10.0 h1:6NKusNu1cw1A/RKb+Lm5aPGFk7HWVIXxl2azpwWqUxc= -github.com/libp2p/go-libp2p-mplex v0.10.0/go.mod h1:7RT3qPFhDqz4yp5K5QwZB5vE902N8DmED3+e453fNrg= +github.com/libp2p/go-libp2p-mplex v0.11.0 h1:0vwpLXRSfkTzshEjETIEgJaVxXvg+orbxYoIb3Ty5qM= +github.com/libp2p/go-libp2p-mplex v0.11.0/go.mod h1:QrsdNY3lzjpdo9V1goJfPb0O65Nms0sUR8CDAO18f6k= github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= @@ -719,8 +694,8 @@ github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+ github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= -github.com/libp2p/go-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8= -github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE= +github.com/libp2p/go-netroute v0.4.0 h1:sZZx9hyANYUx9PZyqcgE/E1GUG3iEtTZHUEvdtXT7/Q= +github.com/libp2p/go-netroute v0.4.0/go.mod h1:Nkd5ShYgSMS5MUKy/MU2T57xFoOKvvLR92Lic48LEyA= github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= @@ -732,8 +707,8 @@ github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjV github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo= github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux/v5 v5.1.0 h1:8Qlxj4E9JGJAQVW6+uj2o7mqkqsIVlSUGmTWhlXzoHE= -github.com/libp2p/go-yamux/v5 v5.1.0/go.mod h1:tgIQ07ObtRR/I0IWsFOyQIL9/dR5UXgc2s8xKmNZv1o= +github.com/libp2p/go-yamux/v5 v5.0.1 h1:f0WoX/bEF2E8SbE4c/k1Mo+/9z0O4oC/hWEA+nfYRSg= +github.com/libp2p/go-yamux/v5 v5.0.1/go.mod h1:en+3cdX51U0ZslwRdRLrvQsdayFt3TSUKvBGErzpWbU= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lmittmann/tint v1.0.6 h1:vkkuDAZXc0EFGNzYjWcV0h7eEX+uujH48f/ifSkJWgc= @@ -745,6 +720,8 @@ github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0Q github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/marcopolo/simnet v0.0.1 h1:rSMslhPz6q9IvJeFWDoMGxMIrlsbXau3NkuIXHGJxfg= +github.com/marcopolo/simnet v0.0.1/go.mod h1:WDaQkgLAjqDUEBAOXz22+1j6wXKfGlC5sD5XWt3ddOs= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -768,8 +745,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfr github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE= -github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE= +github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA= +github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= @@ -800,9 +777,6 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= -github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= -github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= -github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -828,8 +802,8 @@ github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lg github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.16.0 h1:oGWEVKioVQcdIOBlYM8BH1rZDWOGJSqr9/BKl6zQ4qc= -github.com/multiformats/go-multiaddr v0.16.0/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0= +github.com/multiformats/go-multiaddr v0.16.1 h1:fgJ0Pitow+wWXzN9do+1b8Pyjmo8m5WhGfzpL82MpCw= +github.com/multiformats/go-multiaddr v0.16.1/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0= github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.4.1 h1:whi/uCLbDS3mSEUMb1MsoT4uzUeZB0N32yzufqS0i5M= @@ -842,8 +816,8 @@ github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/g github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= -github.com/multiformats/go-multicodec v0.9.1 h1:x/Fuxr7ZuR4jJV4Os5g444F7xC4XmyUaT/FWtE+9Zjo= -github.com/multiformats/go-multicodec v0.9.1/go.mod h1:LLWNMtyV5ithSBUo3vFIMaeDy+h3EbkMTek1m+Fybbo= +github.com/multiformats/go-multicodec v0.10.0 h1:UpP223cig/Cx8J76jWt91njpK3GTAO1w02sdcjZDSuc= +github.com/multiformats/go-multicodec v0.10.0/go.mod h1:wg88pM+s2kZJEQfRCKBNU+g32F5aWBEjyFHXvZLTcLI= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= @@ -856,8 +830,8 @@ github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wS github.com/multiformats/go-multistream v0.6.1 h1:4aoX5v6T+yWmc2raBHsTvzmFhOI8WVOer28DeBBEYdQ= github.com/multiformats/go-multistream v0.6.1/go.mod h1:ksQf6kqHAb6zIsyw7Zm+gAuVo57Qbq84E27YlYqavqw= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= -github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= +github.com/multiformats/go-varint v0.1.0 h1:i2wqFp4sdl3IcIxfAonHQV9qU5OsZ4Ts9IOoETFs5dI= +github.com/multiformats/go-varint v0.1.0/go.mod h1:5KVAVXegtfmNQQm/lCY+ATvDzvJJhSkUlGQV9wgObdI= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -872,9 +846,8 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= -github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= @@ -888,8 +861,6 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= -github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -899,9 +870,6 @@ github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9 github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU= github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww= -github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -934,45 +902,45 @@ github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oL github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= -github.com/pion/dtls/v3 v3.0.6 h1:7Hkd8WhAJNbRgq9RgdNh1aaWlZlGpYTzdqjy9x9sK2E= -github.com/pion/dtls/v3 v3.0.6/go.mod h1:iJxNQ3Uhn1NZWOMWlLxEEHAN5yX7GyPvvKw04v9bzYU= +github.com/pion/dtls/v3 v3.0.7 h1:bItXtTYYhZwkPFk4t1n3Kkf5TDrfj6+4wG+CZR8uI9Q= +github.com/pion/dtls/v3 v3.0.7/go.mod h1:uDlH5VPrgOQIw59irKYkMudSFprY9IEFCqz/eTz16f8= github.com/pion/ice/v4 v4.0.10 h1:P59w1iauC/wPk9PdY8Vjl4fOFL5B+USq1+xbDcN6gT4= github.com/pion/ice/v4 v4.0.10/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= -github.com/pion/interceptor v0.1.39 h1:Y6k0bN9Y3Lg/Wb21JBWp480tohtns8ybJ037AGr9UuA= -github.com/pion/interceptor v0.1.39/go.mod h1:Z6kqH7M/FYirg3frjGJ21VLSRJGBXB/KqaTIrdqnOic= +github.com/pion/interceptor v0.1.41 h1:NpvX3HgWIukTf2yTBVjVGFXtpSpWgXjqz7IIpu7NsOw= +github.com/pion/interceptor v0.1.41/go.mod h1:nEt4187unvRXJFyjiw00GKo+kIuXMWQI9K89fsosDLY= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= -github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI= -github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90= +github.com/pion/logging v0.2.4 h1:tTew+7cmQ+Mc1pTBLKH2puKsOvhm32dROumOZ655zB8= +github.com/pion/logging v0.2.4/go.mod h1:DffhXTKYdNZU+KtJ5pyQDjvOAh/GsNSyv1lbkFbe3so= github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM= github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA= github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= -github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= -github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= -github.com/pion/rtp v1.8.21 h1:3yrOwmZFyUpcIosNcWRpQaU+UXIJ6yxLuJ8Bx0mw37Y= -github.com/pion/rtp v1.8.21/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk= -github.com/pion/sctp v1.8.39 h1:PJma40vRHa3UTO3C4MyeJDQ+KIobVYRZQZ0Nt7SjQnE= -github.com/pion/sctp v1.8.39/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= -github.com/pion/sdp/v3 v3.0.11 h1:VhgVSopdsBKwhCFoyyPmT1fKMeV9nLMrEKxNOdy3IVI= -github.com/pion/sdp/v3 v3.0.11/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= -github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M= -github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ= +github.com/pion/rtcp v1.2.16 h1:fk1B1dNW4hsI78XUCljZJlC4kZOPk67mNRuQ0fcEkSo= +github.com/pion/rtcp v1.2.16/go.mod h1:/as7VKfYbs5NIb4h6muQ35kQF/J0ZVNz2Z3xKoCBYOo= +github.com/pion/rtp v1.8.25 h1:b8+y44GNbwOJTYWuVan7SglX/hMlicVCAtL50ztyZHw= +github.com/pion/rtp v1.8.25/go.mod h1:rF5nS1GqbR7H/TCpKwylzeq6yDM+MM6k+On5EgeThEM= +github.com/pion/sctp v1.8.40 h1:bqbgWYOrUhsYItEnRObUYZuzvOMsVplS3oNgzedBlG8= +github.com/pion/sctp v1.8.40/go.mod h1:SPBBUENXE6ThkEksN5ZavfAhFYll+h+66ZiG6IZQuzo= +github.com/pion/sdp/v3 v3.0.16 h1:0dKzYO6gTAvuLaAKQkC02eCPjMIi4NuAr/ibAwrGDCo= +github.com/pion/sdp/v3 v3.0.16/go.mod h1:9tyKzznud3qiweZcD86kS0ff1pGYB3VX+Bcsmkx6IXo= +github.com/pion/srtp/v3 v3.0.8 h1:RjRrjcIeQsilPzxvdaElN0CpuQZdMvcl9VZ5UY9suUM= +github.com/pion/srtp/v3 v3.0.8/go.mod h1:2Sq6YnDH7/UDCvkSoHSDNDeyBcFgWL0sAVycVbAsXFg= github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= -github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw= -github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU= +github.com/pion/stun/v3 v3.0.1 h1:jx1uUq6BdPihF0yF33Jj2mh+C9p0atY94IkdnW174kA= +github.com/pion/stun/v3 v3.0.1/go.mod h1:RHnvlKFg+qHgoKIqtQWMOJF52wsImCAf/Jh5GjX+4Tw= github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= -github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= -github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= -github.com/pion/turn/v4 v4.0.1 h1:01UTBhYToe8PDC8piB++i66q1mmctfhhoeguaFqB84c= -github.com/pion/turn/v4 v4.0.1/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7IToA1zs= -github.com/pion/webrtc/v4 v4.1.0 h1:yq/p0G5nKGbHISf0YKNA8Yk+kmijbblBvuSLwaJ4QYg= -github.com/pion/webrtc/v4 v4.1.0/go.mod h1:cgEGkcpxGkT6Di2ClBYO5lP9mFXbCfEOrkYUpjjCQO4= +github.com/pion/transport/v3 v3.0.8 h1:oI3myyYnTKUSTthu/NZZ8eu2I5sHbxbUNNFW62olaYc= +github.com/pion/transport/v3 v3.0.8/go.mod h1:+c2eewC5WJQHiAA46fkMMzoYZSuGzA/7E2FPrOYHctQ= +github.com/pion/turn/v4 v4.1.2 h1:Em2svpl6aBFa88dLhxypMUzaLjC79kWZWx8FIov01cc= +github.com/pion/turn/v4 v4.1.2/go.mod h1:ISYWfZYy0Z3tXzRpyYZHTL+U23yFQIspfxogdQ8pn9Y= +github.com/pion/webrtc/v4 v4.1.6 h1:srHH2HwvCGwPba25EYJgUzgLqCQoXl1VCUnrGQMSzUw= +github.com/pion/webrtc/v4 v4.1.6/go.mod h1:wKecGRlkl3ox/As/MYghJL+b/cVXMEhoPMJWPuGQFhU= github.com/pk910/dynamic-ssz v1.1.1 h1:b8sPR8fyhBvz8SHa2RH20SNtt5VDzAEY6fKsPCUcYX4= github.com/pk910/dynamic-ssz v1.1.1/go.mod h1:3zyemisUysY2PWACZ8LeZS2tAw8AkuTb2GaLmqYsg1I= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -991,8 +959,6 @@ github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXx github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= -github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/probe-lab/eth-das-guardian v0.2.2 h1:ygQjHt9jVD6yvujtBLuWPA3fYnPe6D5b2S7xOASYfm4= github.com/probe-lab/eth-das-guardian v0.2.2/go.mod h1:xkhVpnhL1y2tmQERuaJTUGFAMb4eKWSVEBr0rhAB6ZM= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -1002,8 +968,8 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU= -github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= -github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1018,8 +984,8 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= -github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= +github.com/prometheus/common v0.67.2 h1:PcBAckGFTIHt2+L3I33uNRTlKTplNzFctXcWhPyAEN8= +github.com/prometheus/common v0.67.2/go.mod h1:63W3KZb1JOKgcjlIr64WW/LvFGAqKPj0atm+knVGEko= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -1027,8 +993,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/prometheus/prom2json v1.3.0 h1:BlqrtbT9lLH3ZsOVhXPsHzFrApCTKRifB7gjJuypu6Y= github.com/prometheus/prom2json v1.3.0/go.mod h1:rMN7m0ApCowcoDlypBHlkNbp5eJQf/+1isKykIP5ZnM= github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516 h1:xuVAdtz5ShYblG2sPyb4gw01DF8InbOI/kBCQjk7NiM= @@ -1043,14 +1009,12 @@ github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20230228205207-28762a7b9294 h github.com/prysmaticlabs/protoc-gen-go-cast v0.0.0-20230228205207-28762a7b9294/go.mod h1:ZVEbRdnMkGhp/pu35zq4SXxtvUwWK0J1MATtekZpH2Y= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.51.0 h1:K8exxe9zXxeRKxaXxi/GpUqYiTrtdiWP8bo1KFya6Wc= -github.com/quic-go/quic-go v0.51.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ= -github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 h1:4WFk6u3sOT6pLa1kQ50ZVdm8BQFgJNA117cepZxtLIg= -github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66/go.mod h1:Vp72IJajgeOL6ddqrAhmp7IM9zbTcgkQxD/YdxrVwMw= +github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk= +github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U= +github.com/quic-go/webtransport-go v0.9.0 h1:jgys+7/wm6JarGDrW+lD/r9BGqBAmqY/ssklE09bA70= +github.com/quic-go/webtransport-go v0.9.0/go.mod h1:4FUYIiUc75XSsF6HShcLeXXYZJ9AGwo/xh3L8M/P1ao= github.com/raulk/clock v1.1.0 h1:dpb29+UKMbLqiU/jqIJptgLR1nn23HLgMY0sTCDza5Y= github.com/raulk/clock v1.1.0/go.mod h1:3MpVxdZ/ODBQDxbN+kzshf5OSZwPjtMDx6BBXBmOeY0= -github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= -github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= @@ -1058,8 +1022,8 @@ github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -1100,7 +1064,6 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -1127,8 +1090,8 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= @@ -1149,8 +1112,8 @@ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1F github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe h1:nbdqkIGOGfUAD54q1s2YBcBz/WcsxCO9HUQ4aGV5hUw= github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= @@ -1170,7 +1133,6 @@ github.com/trailofbits/go-mutexasserts v0.0.0-20250212181730-4c2b8e9e784b h1:EBo github.com/trailofbits/go-mutexasserts v0.0.0-20250212181730-4c2b8e9e784b/go.mod h1:4R6Qam+w871wOlyRq59zRLjhb5x9/De/wgPeaCTaCwI= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= @@ -1238,12 +1200,12 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I= -go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= -go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 h1:5pojmb1U1AogINhN3SurB+zm/nIcusopeBNp42f45QM= @@ -1252,30 +1214,28 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 h1:BEj3S go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0/go.mod h1:9cKLGBDzI/F3NoHLQGm4ZrYdIHsvGt6ej6hUowxY0J4= go.opentelemetry.io/otel/exporters/prometheus v0.55.0 h1:sSPw658Lk2NWAv74lkD3B/RSDb+xRFx46GjkrL3VUZo= go.opentelemetry.io/otel/exporters/prometheus v0.55.0/go.mod h1:nC00vyCmQixoeaxF6KNyP42II/RHa9UdruK02qBmHvI= -go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= -go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= -go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= -go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= -go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/dig v1.19.0 h1:BACLhebsYdpQ7IROQ1AGPjrXcP5dF80U3gKoFzbaq/4= go.uber.org/dig v1.19.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= go.uber.org/fx v1.24.0 h1:wE8mruvpg2kiiL1Vqd0CC+tr0/24XIB10Iwp2lLWzkg= go.uber.org/fx v1.24.0/go.mod h1:AmDeGyS+ZARGKM4tlH4FY2Jr63VjbEDJHtqXTGP5hbo= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= -go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -1289,6 +1249,8 @@ go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= +go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1313,11 +1275,11 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4= -golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= +golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= +golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -1331,8 +1293,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= -golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1371,14 +1333,14 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= -golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= -golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= +golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1392,7 +1354,6 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1419,12 +1380,10 @@ golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1449,10 +1408,10 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= -golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 h1:dHQOQddU4YHS5gY33/6klKjq7Gp3WwMyOXGNp5nzRj8= -golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE= +golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= +golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/telemetry v0.0.0-20251028164327-d7a2859f34e8 h1:DwMAzqwLj2rVin75cRFh1kfhwQY3hyHrU1oCEDZXPmQ= +golang.org/x/telemetry v0.0.0-20251028164327-d7a2859f34e8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -1460,8 +1419,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -1472,13 +1431,13 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= -golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= +golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= +golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= -golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1501,8 +1460,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1554,8 +1513,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1608,8 +1567,6 @@ k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJ k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= -rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= -rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk=