mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 13:58:09 -05:00
Compare commits
11 Commits
fix-ethspe
...
findPeersW
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
663b53829c | ||
|
|
4b09dd4aa5 | ||
|
|
1dab5a9f8a | ||
|
|
d681232fe6 | ||
|
|
1d24f89c96 | ||
|
|
967193e6a2 | ||
|
|
9e40551852 | ||
|
|
a8cab58f7e | ||
|
|
df86f57507 | ||
|
|
9b0a3e9632 | ||
|
|
5e079aa62c |
@@ -27,7 +27,7 @@ go_library(
|
||||
"receive_block.go",
|
||||
"receive_data_column.go",
|
||||
"service.go",
|
||||
"setup_forchoice.go",
|
||||
"setup_forkchoice.go",
|
||||
"tracked_proposer.go",
|
||||
"weak_subjectivity_checks.go",
|
||||
],
|
||||
|
||||
@@ -78,7 +78,10 @@ func (s *Service) setupForkchoiceTree(st state.BeaconState) error {
|
||||
}
|
||||
s.cfg.ForkChoiceStore.Lock()
|
||||
defer s.cfg.ForkChoiceStore.Unlock()
|
||||
return s.cfg.ForkChoiceStore.InsertChain(s.ctx, chain)
|
||||
if err := s.cfg.ForkChoiceStore.InsertChain(s.ctx, chain); err != nil {
|
||||
return errors.Wrap(err, "could not insert forkchoice chain")
|
||||
}
|
||||
return s.cfg.ForkChoiceStore.InsertNode(s.ctx, st, chain[0].Block)
|
||||
}
|
||||
|
||||
func (s *Service) buildForkchoiceChain(ctx context.Context, head interfaces.ReadOnlySignedBeaconBlock) ([]*forkchoicetypes.BlockAndCheckpoints, error) {
|
||||
@@ -124,5 +124,5 @@ func Test_setupForkchoiceTree_Head(t *testing.T) {
|
||||
require.NotEqual(t, fRoot, root)
|
||||
require.Equal(t, root, service.startupHeadRoot())
|
||||
require.NoError(t, service.setupForkchoiceTree(st))
|
||||
require.Equal(t, 2, service.cfg.ForkChoiceStore.NodeCount())
|
||||
require.Equal(t, 3, service.cfg.ForkChoiceStore.NodeCount())
|
||||
}
|
||||
|
||||
@@ -621,35 +621,55 @@ func (b *BeaconNode) startStateGen(ctx context.Context, bfs coverage.AvailableBl
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseIPNetStrings(ipWhitelist []string) ([]*net.IPNet, error) {
|
||||
ipNets := make([]*net.IPNet, 0, len(ipWhitelist))
|
||||
for _, cidr := range ipWhitelist {
|
||||
_, ipNet, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("cidr", cidr).Error("Invalid CIDR in IP colocation whitelist")
|
||||
return nil, err
|
||||
}
|
||||
ipNets = append(ipNets, ipNet)
|
||||
log.WithField("cidr", cidr).Info("Added IP to colocation whitelist")
|
||||
}
|
||||
return ipNets, nil
|
||||
}
|
||||
|
||||
func (b *BeaconNode) registerP2P(cliCtx *cli.Context) error {
|
||||
bootstrapNodeAddrs, dataDir, err := registration.P2PPreregistration(cliCtx)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not register p2p service")
|
||||
}
|
||||
|
||||
colocationWhitelist, err := parseIPNetStrings(slice.SplitCommaSeparated(cliCtx.StringSlice(cmd.P2PColocationWhitelist.Name)))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to register p2p service: %w", err)
|
||||
}
|
||||
|
||||
svc, err := p2p.NewService(b.ctx, &p2p.Config{
|
||||
NoDiscovery: cliCtx.Bool(cmd.NoDiscovery.Name),
|
||||
StaticPeers: slice.SplitCommaSeparated(cliCtx.StringSlice(cmd.StaticPeers.Name)),
|
||||
Discv5BootStrapAddrs: p2p.ParseBootStrapAddrs(bootstrapNodeAddrs),
|
||||
RelayNodeAddr: cliCtx.String(cmd.RelayNode.Name),
|
||||
DataDir: dataDir,
|
||||
DiscoveryDir: filepath.Join(dataDir, "discovery"),
|
||||
LocalIP: cliCtx.String(cmd.P2PIP.Name),
|
||||
HostAddress: cliCtx.String(cmd.P2PHost.Name),
|
||||
HostDNS: cliCtx.String(cmd.P2PHostDNS.Name),
|
||||
PrivateKey: cliCtx.String(cmd.P2PPrivKey.Name),
|
||||
StaticPeerID: cliCtx.Bool(cmd.P2PStaticID.Name),
|
||||
QUICPort: cliCtx.Uint(cmd.P2PQUICPort.Name),
|
||||
TCPPort: cliCtx.Uint(cmd.P2PTCPPort.Name),
|
||||
UDPPort: cliCtx.Uint(cmd.P2PUDPPort.Name),
|
||||
MaxPeers: cliCtx.Uint(cmd.P2PMaxPeers.Name),
|
||||
QueueSize: cliCtx.Uint(cmd.PubsubQueueSize.Name),
|
||||
AllowListCIDR: cliCtx.String(cmd.P2PAllowList.Name),
|
||||
DenyListCIDR: slice.SplitCommaSeparated(cliCtx.StringSlice(cmd.P2PDenyList.Name)),
|
||||
EnableUPnP: cliCtx.Bool(cmd.EnableUPnPFlag.Name),
|
||||
StateNotifier: b,
|
||||
DB: b.db,
|
||||
ClockWaiter: b.clockWaiter,
|
||||
NoDiscovery: cliCtx.Bool(cmd.NoDiscovery.Name),
|
||||
StaticPeers: slice.SplitCommaSeparated(cliCtx.StringSlice(cmd.StaticPeers.Name)),
|
||||
Discv5BootStrapAddrs: p2p.ParseBootStrapAddrs(bootstrapNodeAddrs),
|
||||
RelayNodeAddr: cliCtx.String(cmd.RelayNode.Name),
|
||||
DataDir: dataDir,
|
||||
DiscoveryDir: filepath.Join(dataDir, "discovery"),
|
||||
LocalIP: cliCtx.String(cmd.P2PIP.Name),
|
||||
HostAddress: cliCtx.String(cmd.P2PHost.Name),
|
||||
HostDNS: cliCtx.String(cmd.P2PHostDNS.Name),
|
||||
PrivateKey: cliCtx.String(cmd.P2PPrivKey.Name),
|
||||
StaticPeerID: cliCtx.Bool(cmd.P2PStaticID.Name),
|
||||
QUICPort: cliCtx.Uint(cmd.P2PQUICPort.Name),
|
||||
TCPPort: cliCtx.Uint(cmd.P2PTCPPort.Name),
|
||||
UDPPort: cliCtx.Uint(cmd.P2PUDPPort.Name),
|
||||
MaxPeers: cliCtx.Uint(cmd.P2PMaxPeers.Name),
|
||||
QueueSize: cliCtx.Uint(cmd.PubsubQueueSize.Name),
|
||||
AllowListCIDR: cliCtx.String(cmd.P2PAllowList.Name),
|
||||
DenyListCIDR: slice.SplitCommaSeparated(cliCtx.StringSlice(cmd.P2PDenyList.Name)),
|
||||
IPColocationWhitelist: colocationWhitelist,
|
||||
EnableUPnP: cliCtx.Bool(cmd.EnableUPnPFlag.Name),
|
||||
StateNotifier: b,
|
||||
DB: b.db,
|
||||
ClockWaiter: b.clockWaiter,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -262,3 +262,46 @@ func TestCORS(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseIPNetStrings(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
whitelist []string
|
||||
wantCount int
|
||||
wantError string
|
||||
}{
|
||||
{
|
||||
name: "empty whitelist",
|
||||
whitelist: []string{},
|
||||
wantCount: 0,
|
||||
},
|
||||
{
|
||||
name: "single IP whitelist",
|
||||
whitelist: []string{"192.168.1.1/32"},
|
||||
wantCount: 1,
|
||||
},
|
||||
{
|
||||
name: "multiple IPs whitelist",
|
||||
whitelist: []string{"192.168.1.0/24", "10.0.0.0/8", "34.42.19.170/32"},
|
||||
wantCount: 3,
|
||||
},
|
||||
{
|
||||
name: "invalid CIDR returns error",
|
||||
whitelist: []string{"192.168.1.0/24", "invalid-cidr", "10.0.0.0/8"},
|
||||
wantCount: 0,
|
||||
wantError: "invalid CIDR address",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := parseIPNetStrings(tt.whitelist)
|
||||
assert.Equal(t, tt.wantCount, len(result))
|
||||
if len(tt.wantError) == 0 {
|
||||
assert.Equal(t, nil, err)
|
||||
} else {
|
||||
assert.ErrorContains(t, tt.wantError, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@ go_library(
|
||||
"@com_github_libp2p_go_libp2p//core/peer:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//core/peerstore:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//core/protocol:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//p2p/net/connmgr:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//p2p/security/noise:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//p2p/transport/quic:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//p2p/transport/tcp:go_default_library",
|
||||
@@ -184,6 +185,7 @@ go_test(
|
||||
"@com_github_ethereum_go_ethereum//p2p/enr:go_default_library",
|
||||
"@com_github_golang_snappy//:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//core/connmgr:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//core/crypto:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//core/host:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//core/network:go_default_library",
|
||||
|
||||
@@ -123,9 +123,6 @@ func (s *Service) internalBroadcastAttestation(ctx context.Context, subnet uint6
|
||||
if !hasPeer {
|
||||
attestationBroadcastAttempts.Inc()
|
||||
if err := func() error {
|
||||
s.subnetLocker(subnet).Lock()
|
||||
defer s.subnetLocker(subnet).Unlock()
|
||||
|
||||
if err := s.FindAndDialPeersWithSubnets(ctx, AttestationSubnetTopicFormat, forkDigest, minimumPeersPerSubnetForBroadcast, map[uint64]bool{subnet: true}); err != nil {
|
||||
return errors.Wrap(err, "find peers with subnets")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package p2p
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
statefeed "github.com/OffchainLabs/prysm/v6/beacon-chain/core/feed/state"
|
||||
@@ -10,34 +11,56 @@ import (
|
||||
|
||||
// This is the default queue size used if we have specified an invalid one.
|
||||
const defaultPubsubQueueSize = 600
|
||||
const (
|
||||
// defaultConnManagerPruneAbove sets the number of peers where ConnectionManager
|
||||
// will begin to internally prune peers. This value is set based on the internal
|
||||
// value of the libp2p DefaultConectionManager "high water mark". The "low water mark"
|
||||
// is the number of peers where ConnManager will stop pruning. This value is computed
|
||||
// by subtracting connManagerPruneAmount from the high water mark.
|
||||
defaultConnManagerPruneAbove = 192
|
||||
connManagerPruneAmount = 32
|
||||
)
|
||||
|
||||
// Config for the p2p service. These parameters are set from application level flags
|
||||
// to initialize the p2p service.
|
||||
type Config struct {
|
||||
NoDiscovery bool
|
||||
EnableUPnP bool
|
||||
StaticPeerID bool
|
||||
DisableLivenessCheck bool
|
||||
StaticPeers []string
|
||||
Discv5BootStrapAddrs []string
|
||||
RelayNodeAddr string
|
||||
LocalIP string
|
||||
HostAddress string
|
||||
HostDNS string
|
||||
PrivateKey string
|
||||
DataDir string
|
||||
DiscoveryDir string
|
||||
QUICPort uint
|
||||
TCPPort uint
|
||||
UDPPort uint
|
||||
PingInterval time.Duration
|
||||
MaxPeers uint
|
||||
QueueSize uint
|
||||
AllowListCIDR string
|
||||
DenyListCIDR []string
|
||||
StateNotifier statefeed.Notifier
|
||||
DB db.ReadOnlyDatabaseWithSeqNum
|
||||
ClockWaiter startup.ClockWaiter
|
||||
NoDiscovery bool
|
||||
EnableUPnP bool
|
||||
StaticPeerID bool
|
||||
DisableLivenessCheck bool
|
||||
StaticPeers []string
|
||||
Discv5BootStrapAddrs []string
|
||||
RelayNodeAddr string
|
||||
LocalIP string
|
||||
HostAddress string
|
||||
HostDNS string
|
||||
PrivateKey string
|
||||
DataDir string
|
||||
DiscoveryDir string
|
||||
QUICPort uint
|
||||
TCPPort uint
|
||||
UDPPort uint
|
||||
PingInterval time.Duration
|
||||
MaxPeers uint
|
||||
QueueSize uint
|
||||
AllowListCIDR string
|
||||
DenyListCIDR []string
|
||||
IPColocationWhitelist []*net.IPNet
|
||||
StateNotifier statefeed.Notifier
|
||||
DB db.ReadOnlyDatabaseWithSeqNum
|
||||
ClockWaiter startup.ClockWaiter
|
||||
}
|
||||
|
||||
// connManagerLowHigh picks the low and high water marks for the connection manager based
|
||||
// on the MaxPeers setting. The high water mark will be at least the default high water mark
|
||||
// (192), or MaxPeers + 32, whichever is higher. The low water mark is set to be 32 less than
|
||||
// the high water mark. This is done to ensure the ConnManager never prunes peers that the
|
||||
// node has connected to based on the MaxPeers setting.
|
||||
func (cfg *Config) connManagerLowHigh() (int, int) {
|
||||
maxPeersPlusMargin := int(cfg.MaxPeers) + connManagerPruneAmount
|
||||
high := max(maxPeersPlusMargin, defaultConnManagerPruneAbove)
|
||||
low := high - connManagerPruneAmount
|
||||
return low, high
|
||||
}
|
||||
|
||||
// validateConfig validates whether the values provided are accurate and will set
|
||||
|
||||
@@ -3,6 +3,7 @@ package p2p
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"net"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -75,7 +76,7 @@ var (
|
||||
tenEpochs = 10 * oneEpochDuration()
|
||||
)
|
||||
|
||||
func peerScoringParams() (*pubsub.PeerScoreParams, *pubsub.PeerScoreThresholds) {
|
||||
func peerScoringParams(colocationWhitelist []*net.IPNet) (*pubsub.PeerScoreParams, *pubsub.PeerScoreThresholds) {
|
||||
thresholds := &pubsub.PeerScoreThresholds{
|
||||
GossipThreshold: -4000,
|
||||
PublishThreshold: -8000,
|
||||
@@ -83,6 +84,7 @@ func peerScoringParams() (*pubsub.PeerScoreParams, *pubsub.PeerScoreThresholds)
|
||||
AcceptPXThreshold: 100,
|
||||
OpportunisticGraftThreshold: 5,
|
||||
}
|
||||
|
||||
scoreParams := &pubsub.PeerScoreParams{
|
||||
Topics: make(map[string]*pubsub.TopicScoreParams),
|
||||
TopicScoreCap: 32.72,
|
||||
@@ -92,7 +94,7 @@ func peerScoringParams() (*pubsub.PeerScoreParams, *pubsub.PeerScoreThresholds)
|
||||
AppSpecificWeight: 1,
|
||||
IPColocationFactorWeight: -35.11,
|
||||
IPColocationFactorThreshold: 10,
|
||||
IPColocationFactorWhitelist: nil,
|
||||
IPColocationFactorWhitelist: colocationWhitelist,
|
||||
BehaviourPenaltyWeight: -15.92,
|
||||
BehaviourPenaltyThreshold: 6,
|
||||
BehaviourPenaltyDecay: scoreDecay(tenEpochs),
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
mplex "github.com/libp2p/go-libp2p-mplex"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/p2p/net/connmgr"
|
||||
"github.com/libp2p/go-libp2p/p2p/security/noise"
|
||||
libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic"
|
||||
libp2ptcp "github.com/libp2p/go-libp2p/p2p/transport/tcp"
|
||||
@@ -58,6 +59,22 @@ func MultiAddressBuilder(ip net.IP, tcpPort, quicPort uint) ([]ma.Multiaddr, err
|
||||
return multiaddrs, nil
|
||||
}
|
||||
|
||||
// setConnManagerOption sets the connection manager option for libp2p based on the
|
||||
// MaxPeers setting in the p2p config. If MaxPeers is set to a value higher than the
|
||||
// default high water mark, we create a new connection manager with a high water mark
|
||||
// that is higher than MaxPeers. Otherwise, we do not set a connection manager option
|
||||
// and allow the libp2p fallback defaults to be applied. Rationale below:
|
||||
// see: https://github.com/OffchainLabs/prysm/issues/15607
|
||||
func setConnManagerOption(cfg *Config, opts []libp2p.Option) ([]libp2p.Option, error) {
|
||||
low, high := cfg.connManagerLowHigh()
|
||||
cm, err := connmgr.NewConnManager(low, high)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "new ConnManager")
|
||||
}
|
||||
opts = append(opts, libp2p.ConnectionManager(cm))
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
// buildOptions for the libp2p host.
|
||||
func (s *Service) buildOptions(ip net.IP, priKey *ecdsa.PrivateKey) ([]libp2p.Option, error) {
|
||||
cfg := s.cfg
|
||||
@@ -84,7 +101,6 @@ func (s *Service) buildOptions(ip net.IP, priKey *ecdsa.PrivateKey) ([]libp2p.Op
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot get ID from public key: %s", ifaceKey.GetPublic().Type().String())
|
||||
}
|
||||
|
||||
log.Infof("Running node with peer id of %s ", id.String())
|
||||
|
||||
options := []libp2p.Option{
|
||||
@@ -98,6 +114,10 @@ func (s *Service) buildOptions(ip net.IP, priKey *ecdsa.PrivateKey) ([]libp2p.Op
|
||||
libp2p.Security(noise.ID, noise.New),
|
||||
libp2p.Ping(false), // Disable Ping Service.
|
||||
}
|
||||
options, err = setConnManagerOption(s.cfg, options)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "set connection manager option")
|
||||
}
|
||||
|
||||
if features.Get().EnableQUIC {
|
||||
options = append(options, libp2p.Transport(libp2pquic.NewTransport))
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||
"github.com/libp2p/go-libp2p"
|
||||
"github.com/libp2p/go-libp2p/core/connmgr"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
@@ -134,6 +135,59 @@ func TestDefaultMultiplexers(t *testing.T) {
|
||||
assert.Equal(t, protocol.ID("/mplex/6.7.0"), cfg.Muxers[1].ID)
|
||||
}
|
||||
|
||||
func TestSetConnManagerOption(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
maxPeers uint
|
||||
highWater int
|
||||
}{
|
||||
{
|
||||
name: "MaxPeers lower than default high water mark",
|
||||
maxPeers: defaultConnManagerPruneAbove - 1,
|
||||
highWater: defaultConnManagerPruneAbove,
|
||||
},
|
||||
{
|
||||
name: "MaxPeers equal to default high water mark",
|
||||
maxPeers: defaultConnManagerPruneAbove,
|
||||
highWater: defaultConnManagerPruneAbove,
|
||||
},
|
||||
{
|
||||
name: "MaxPeers higher than default high water mark",
|
||||
maxPeers: defaultConnManagerPruneAbove + 1,
|
||||
highWater: defaultConnManagerPruneAbove + 1 + connManagerPruneAmount,
|
||||
},
|
||||
}
|
||||
for _, tt := range cases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg := &Config{MaxPeers: tt.maxPeers}
|
||||
opts, err := setConnManagerOption(cfg, []libp2p.Option{})
|
||||
assert.NoError(t, err)
|
||||
_, high := cfg.connManagerLowHigh()
|
||||
require.Equal(t, true, high > int(cfg.MaxPeers))
|
||||
|
||||
var libCfg libp2p.Config
|
||||
require.NoError(t, libCfg.Apply(append(opts, libp2p.FallbackDefaults)...))
|
||||
checkLimit(t, libCfg.ConnManager, high)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type connLimitGetter int
|
||||
|
||||
func (m connLimitGetter) GetConnLimit() int {
|
||||
return int(m)
|
||||
}
|
||||
|
||||
// CheckLimit will return an error if the result of calling lg.GetConnLimit is greater than
|
||||
// the high water mark. So by checking the result of calling it with a value equal to and lower
|
||||
// than the expected value, we can determine the value it holds internally.
|
||||
func checkLimit(t *testing.T, cm connmgr.ConnManager, expected int) {
|
||||
require.NoError(t, cm.CheckLimit(connLimitGetter(expected)), "Connection manager limit check failed")
|
||||
if err := cm.CheckLimit(connLimitGetter(expected - 1)); err == nil {
|
||||
t.Errorf("connection manager limit is below the expected value of %d", expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiAddressBuilderWithID(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
|
||||
@@ -25,6 +25,7 @@ package peers
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"net"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -87,11 +88,12 @@ const (
|
||||
|
||||
// Status is the structure holding the peer status information.
|
||||
type Status struct {
|
||||
ctx context.Context
|
||||
scorers *scorers.Service
|
||||
store *peerdata.Store
|
||||
ipTracker map[string]uint64
|
||||
rand *rand.Rand
|
||||
ctx context.Context
|
||||
scorers *scorers.Service
|
||||
store *peerdata.Store
|
||||
ipTracker map[string]uint64
|
||||
rand *rand.Rand
|
||||
ipColocationWhitelist []*net.IPNet
|
||||
}
|
||||
|
||||
// StatusConfig represents peer status service params.
|
||||
@@ -100,6 +102,8 @@ type StatusConfig struct {
|
||||
PeerLimit int
|
||||
// ScorerParams holds peer scorer configuration params.
|
||||
ScorerParams *scorers.Config
|
||||
// IPColocationWhitelist contains CIDR ranges that are exempt from IP colocation limits.
|
||||
IPColocationWhitelist []*net.IPNet
|
||||
}
|
||||
|
||||
// NewStatus creates a new status entity.
|
||||
@@ -107,11 +111,13 @@ func NewStatus(ctx context.Context, config *StatusConfig) *Status {
|
||||
store := peerdata.NewStore(ctx, &peerdata.StoreConfig{
|
||||
MaxPeers: maxLimitBuffer + config.PeerLimit,
|
||||
})
|
||||
|
||||
return &Status{
|
||||
ctx: ctx,
|
||||
store: store,
|
||||
scorers: scorers.NewService(ctx, store, config.ScorerParams),
|
||||
ipTracker: map[string]uint64{},
|
||||
ctx: ctx,
|
||||
store: store,
|
||||
scorers: scorers.NewService(ctx, store, config.ScorerParams),
|
||||
ipTracker: map[string]uint64{},
|
||||
ipColocationWhitelist: config.IPColocationWhitelist,
|
||||
// Random generator used to calculate dial backoff period.
|
||||
// It is ok to use deterministic generator, no need for true entropy.
|
||||
rand: rand.NewDeterministicGenerator(),
|
||||
@@ -1046,6 +1052,13 @@ func (p *Status) isfromBadIP(pid peer.ID) error {
|
||||
|
||||
if val, ok := p.ipTracker[ip.String()]; ok {
|
||||
if val > CollocationLimit {
|
||||
// Check if IP is in the whitelist
|
||||
for _, ipNet := range p.ipColocationWhitelist {
|
||||
if ipNet.Contains(ip) {
|
||||
// IP is whitelisted, skip colocation limit check
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.Errorf(
|
||||
"colocation limit exceeded: got %d - limit %d for peer %v with IP %v",
|
||||
val, CollocationLimit, pid, ip.String(),
|
||||
|
||||
@@ -145,7 +145,7 @@ func (s *Service) pubsubOptions() []pubsub.Option {
|
||||
pubsub.WithPeerOutboundQueueSize(int(s.cfg.QueueSize)),
|
||||
pubsub.WithMaxMessageSize(int(MaxMessageSize())), // lint:ignore uintcast -- Max Message Size is a config value and is naturally bounded by networking limitations.
|
||||
pubsub.WithValidateQueueSize(int(s.cfg.QueueSize)),
|
||||
pubsub.WithPeerScore(peerScoringParams()),
|
||||
pubsub.WithPeerScore(peerScoringParams(s.cfg.IPColocationWhitelist)),
|
||||
pubsub.WithPeerScoreInspect(s.peerInspector, time.Minute),
|
||||
pubsub.WithGossipSubParams(pubsubGossipParam()),
|
||||
pubsub.WithRawTracer(gossipTracer{host: s.host}),
|
||||
|
||||
@@ -178,7 +178,8 @@ func NewService(ctx context.Context, cfg *Config) (*Service, error) {
|
||||
s.pubsub = gs
|
||||
|
||||
s.peers = peers.NewStatus(ctx, &peers.StatusConfig{
|
||||
PeerLimit: int(s.cfg.MaxPeers),
|
||||
PeerLimit: int(s.cfg.MaxPeers),
|
||||
IPColocationWhitelist: s.cfg.IPColocationWhitelist,
|
||||
ScorerParams: &scorers.Config{
|
||||
BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
||||
Threshold: maxBadResponses,
|
||||
|
||||
@@ -110,6 +110,11 @@ func (s *Service) FindAndDialPeersWithSubnets(
|
||||
}
|
||||
|
||||
peersToDial, err := func() ([]*enode.Node, error) {
|
||||
for subnet := range defectiveSubnets {
|
||||
s.subnetLocker(subnet).Lock()
|
||||
defer s.subnetLocker(subnet).Unlock()
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, batchPeriod)
|
||||
defer cancel()
|
||||
|
||||
|
||||
@@ -1230,6 +1230,7 @@ func (s *Service) prysmBeaconEndpoints(
|
||||
methods: []string{http.MethodGet},
|
||||
},
|
||||
{
|
||||
// Warning: no longer supported post Fulu fork
|
||||
template: "/prysm/v1/beacon/blobs",
|
||||
name: namespace + ".PublishBlobs",
|
||||
middleware: []middleware.Middleware{
|
||||
|
||||
@@ -186,6 +186,7 @@ func (s *Server) GetChainHead(w http.ResponseWriter, r *http.Request) {
|
||||
httputil.WriteJson(w, response)
|
||||
}
|
||||
|
||||
// Warning: no longer supported post Fulu blobs
|
||||
func (s *Server) PublishBlobs(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "beacon.PublishBlobs")
|
||||
defer span.End()
|
||||
@@ -215,6 +216,15 @@ func (s *Server) PublishBlobs(w http.ResponseWriter, r *http.Request) {
|
||||
httputil.HandleError(w, "Could not decode blob sidecar: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
scEpoch := slots.ToEpoch(sc.SignedBlockHeader.Header.Slot)
|
||||
if scEpoch < params.BeaconConfig().DenebForkEpoch {
|
||||
httputil.HandleError(w, "Blob sidecars not supported for pre deneb", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if scEpoch > params.BeaconConfig().FuluForkEpoch {
|
||||
httputil.HandleError(w, "Blob sidecars not supported for post fulu blobs", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
readOnlySc, err := blocks.NewROBlobWithRoot(sc, bytesutil.ToBytes32(root))
|
||||
if err != nil {
|
||||
|
||||
@@ -1017,6 +1017,11 @@ func TestPublishBlobs_BadBlockRoot(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPublishBlobs(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.DenebForkEpoch = 0 // Set Deneb fork to epoch 0 so slot 0 is valid
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
server := &Server{
|
||||
BlobReceiver: &chainMock.ChainService{},
|
||||
Broadcaster: &mockp2p.MockBroadcaster{},
|
||||
@@ -1032,3 +1037,94 @@ func TestPublishBlobs(t *testing.T) {
|
||||
assert.Equal(t, len(server.BlobReceiver.(*chainMock.ChainService).Blobs), 1)
|
||||
assert.Equal(t, server.Broadcaster.(*mockp2p.MockBroadcaster).BroadcastCalled.Load(), true)
|
||||
}
|
||||
|
||||
func TestPublishBlobs_PreDeneb(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.DenebForkEpoch = 10 // Set Deneb fork to epoch 10, so slot 0 is pre-Deneb
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
server := &Server{
|
||||
BlobReceiver: &chainMock.ChainService{},
|
||||
Broadcaster: &mockp2p.MockBroadcaster{},
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodPost, "http://foo.example", bytes.NewReader([]byte(rpctesting.PublishBlobsRequest)))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.PublishBlobs(writer, request)
|
||||
assert.Equal(t, http.StatusBadRequest, writer.Code)
|
||||
assert.StringContains(t, "Blob sidecars not supported for pre deneb", writer.Body.String())
|
||||
|
||||
assert.Equal(t, len(server.BlobReceiver.(*chainMock.ChainService).Blobs), 0)
|
||||
assert.Equal(t, server.Broadcaster.(*mockp2p.MockBroadcaster).BroadcastCalled.Load(), false)
|
||||
}
|
||||
|
||||
func TestPublishBlobs_PostFulu(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.DenebForkEpoch = 0
|
||||
cfg.FuluForkEpoch = 0 // Set Fulu fork to epoch 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
server := &Server{
|
||||
BlobReceiver: &chainMock.ChainService{},
|
||||
Broadcaster: &mockp2p.MockBroadcaster{},
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
}
|
||||
|
||||
// Create a custom request with a slot in epoch 1 (which is > FuluForkEpoch of 0)
|
||||
postFuluRequest := fmt.Sprintf(`{
|
||||
"block_root" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"blob_sidecars" : {
|
||||
"sidecars" : [
|
||||
{
|
||||
"blob" : "%s",
|
||||
"index" : "0",
|
||||
"kzg_commitment" : "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"kzg_commitment_inclusion_proof" : [
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
],
|
||||
"kzg_proof" : "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"signed_block_header" : {
|
||||
"message" : {
|
||||
"body_root" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"parent_root" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"proposer_index" : "0",
|
||||
"slot" : "33",
|
||||
"state_root" : "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"signature" : "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}`, rpctesting.Blob)
|
||||
|
||||
request := httptest.NewRequest(http.MethodPost, "http://foo.example", bytes.NewReader([]byte(postFuluRequest)))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.PublishBlobs(writer, request)
|
||||
assert.Equal(t, http.StatusBadRequest, writer.Code)
|
||||
assert.StringContains(t, "Blob sidecars not supported for post fulu blobs", writer.Body.String())
|
||||
|
||||
assert.Equal(t, len(server.BlobReceiver.(*chainMock.ChainService).Blobs), 0)
|
||||
assert.Equal(t, server.Broadcaster.(*mockp2p.MockBroadcaster).BroadcastCalled.Load(), false)
|
||||
}
|
||||
|
||||
@@ -171,6 +171,7 @@ go_test(
|
||||
"decode_pubsub_test.go",
|
||||
"error_test.go",
|
||||
"fork_watcher_test.go",
|
||||
"kzg_batch_verifier_test.go",
|
||||
"pending_attestations_queue_test.go",
|
||||
"pending_blocks_queue_test.go",
|
||||
"rate_limiter_test.go",
|
||||
|
||||
@@ -4,6 +4,9 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/peerdas"
|
||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
||||
"github.com/OffchainLabs/prysm/v6/crypto/bls"
|
||||
"github.com/OffchainLabs/prysm/v6/monitoring/tracing"
|
||||
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
|
||||
@@ -18,6 +21,11 @@ type signatureVerifier struct {
|
||||
resChan chan error
|
||||
}
|
||||
|
||||
type kzgVerifier struct {
|
||||
dataColumns []blocks.RODataColumn
|
||||
resChan chan error
|
||||
}
|
||||
|
||||
// A routine that runs in the background to perform batch
|
||||
// verifications of incoming messages from gossip.
|
||||
func (s *Service) verifierRoutine() {
|
||||
@@ -47,6 +55,32 @@ func (s *Service) verifierRoutine() {
|
||||
}
|
||||
}
|
||||
|
||||
// A routine that runs in the background to perform batch
|
||||
// KZG verifications by draining the channel and processing all pending requests.
|
||||
func (s *Service) kzgVerifierRoutine() {
|
||||
for {
|
||||
kzgBatch := make([]*kzgVerifier, 0, 1)
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
return
|
||||
case kzg := <-s.kzgChan:
|
||||
kzgBatch = append(kzgBatch, kzg)
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
return
|
||||
case kzg := <-s.kzgChan:
|
||||
kzgBatch = append(kzgBatch, kzg)
|
||||
continue
|
||||
default:
|
||||
verifyKzgBatch(kzgBatch)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) validateWithBatchVerifier(ctx context.Context, message string, set *bls.SignatureBatch) (pubsub.ValidationResult, error) {
|
||||
_, span := trace.StartSpan(ctx, "sync.validateWithBatchVerifier")
|
||||
defer span.End()
|
||||
@@ -56,7 +90,6 @@ func (s *Service) validateWithBatchVerifier(ctx context.Context, message string,
|
||||
s.signatureChan <- verificationSet
|
||||
|
||||
resErr := <-resChan
|
||||
close(resChan)
|
||||
// If verification fails we fallback to individual verification
|
||||
// of each signature set.
|
||||
if resErr != nil {
|
||||
@@ -120,3 +153,62 @@ func performBatchAggregation(aggSet *bls.SignatureBatch) (*bls.SignatureBatch, e
|
||||
}
|
||||
return aggSet, nil
|
||||
}
|
||||
|
||||
func (s *Service) validateWithKzgBatchVerifier(ctx context.Context, dataColumns []blocks.RODataColumn) (pubsub.ValidationResult, error) {
|
||||
_, span := trace.StartSpan(ctx, "sync.validateWithKzgBatchVerifier")
|
||||
defer span.End()
|
||||
|
||||
timeout := time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second
|
||||
|
||||
resChan := make(chan error)
|
||||
verificationSet := &kzgVerifier{dataColumns: dataColumns, resChan: resChan}
|
||||
s.kzgChan <- verificationSet
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return pubsub.ValidationIgnore, ctx.Err() // parent context canceled, give up
|
||||
case err := <-resChan:
|
||||
if err != nil {
|
||||
log.WithError(err).Trace("Could not perform batch verification")
|
||||
tracing.AnnotateError(span, err)
|
||||
return s.validateUnbatchedColumnsKzg(ctx, dataColumns)
|
||||
}
|
||||
}
|
||||
return pubsub.ValidationAccept, nil
|
||||
}
|
||||
|
||||
func (s *Service) validateUnbatchedColumnsKzg(ctx context.Context, columns []blocks.RODataColumn) (pubsub.ValidationResult, error) {
|
||||
_, span := trace.StartSpan(ctx, "sync.validateUnbatchedColumnsKzg")
|
||||
defer span.End()
|
||||
if err := peerdas.VerifyDataColumnsSidecarKZGProofs(columns); err != nil {
|
||||
err = errors.Wrap(err, "could not verify")
|
||||
tracing.AnnotateError(span, err)
|
||||
return pubsub.ValidationReject, err
|
||||
}
|
||||
return pubsub.ValidationAccept, nil
|
||||
}
|
||||
|
||||
func verifyKzgBatch(kzgBatch []*kzgVerifier) {
|
||||
if len(kzgBatch) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
allDataColumns := make([]blocks.RODataColumn, 0, len(kzgBatch))
|
||||
for _, kzgVerifier := range kzgBatch {
|
||||
allDataColumns = append(allDataColumns, kzgVerifier.dataColumns...)
|
||||
}
|
||||
|
||||
var verificationErr error
|
||||
err := peerdas.VerifyDataColumnsSidecarKZGProofs(allDataColumns)
|
||||
if err != nil {
|
||||
verificationErr = errors.Wrap(err, "batch KZG verification failed")
|
||||
}
|
||||
|
||||
// Send the same result to all verifiers in the batch
|
||||
for _, verifier := range kzgBatch {
|
||||
verifier.resChan <- verificationErr
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,6 +456,9 @@ func (f *blocksFetcher) fetchBlocksFromPeer(
|
||||
"count": req.Count,
|
||||
"step": req.Step,
|
||||
}).WithError(err).Debug("Could not request blocks by range from peer")
|
||||
if errors.Is(err, prysmsync.ErrInvalidFetchedData) {
|
||||
f.downscorePeer(p, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
f.p2p.Peers().Scorers().BlockProviderScorer().Touch(p)
|
||||
@@ -876,6 +879,12 @@ func dedupPeers(peers []peer.ID) []peer.ID {
|
||||
return newPeerList
|
||||
}
|
||||
|
||||
// downscorePeer increments the bad responses score for the peer and logs the event.
|
||||
func (f *blocksFetcher) downscorePeer(peerID peer.ID, reason error) {
|
||||
newScore := f.p2p.Peers().Scorers().BadResponsesScorer().Increment(peerID)
|
||||
log.WithFields(logrus.Fields{"peerID": peerID, "reason": reason, "newScore": newScore}).Debug("Downscore peer")
|
||||
}
|
||||
|
||||
// findFirstFuluIndex returns the index of the first block with a version >= Fulu.
|
||||
// It returns an error if blocks are not correctly sorted by version regarding Fulu.
|
||||
func findFirstFuluIndex(bwScs []blocks.BlockWithROSidecars) (int, error) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/filesystem"
|
||||
dbtest "github.com/OffchainLabs/prysm/v6/beacon-chain/db/testing"
|
||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
|
||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/peers/peerdata"
|
||||
p2ptest "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/testing"
|
||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/startup"
|
||||
beaconsync "github.com/OffchainLabs/prysm/v6/beacon-chain/sync"
|
||||
@@ -910,6 +911,55 @@ func TestBlocksFetcher_requestBlocksFromPeerReturningInvalidBlocks(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlocksFetcher_requestBlocksDownscoreOnInvalidData(t *testing.T) {
|
||||
p1 := p2ptest.NewTestP2P(t)
|
||||
p2 := p2ptest.NewTestP2P(t)
|
||||
p1.Connect(p2)
|
||||
|
||||
topic := p2p.RPCBlocksByRangeTopicV1
|
||||
protocol := libp2pcore.ProtocolID(topic + p1.Encoding().ProtocolSuffix())
|
||||
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
defer cancel()
|
||||
|
||||
fetcher := newBlocksFetcher(ctx, &blocksFetcherConfig{
|
||||
p2p: p1,
|
||||
chain: &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}},
|
||||
})
|
||||
fetcher.rateLimiter = leakybucket.NewCollector(0.000001, 640, 1*time.Second, false)
|
||||
|
||||
// Set up handler that returns blocks in wrong order (will trigger ErrInvalidFetchedData)
|
||||
p2.BHost.SetStreamHandler(protocol, func(stream network.Stream) {
|
||||
blk := util.NewBeaconBlock()
|
||||
blk.Block.Slot = 163
|
||||
tor := startup.NewClock(time.Now(), [32]byte{})
|
||||
wsb, err := blocks.NewSignedBeaconBlock(blk)
|
||||
require.NoError(t, err)
|
||||
assert.NoError(t, beaconsync.WriteBlockChunk(stream, tor, p1.Encoding(), wsb))
|
||||
|
||||
blk = util.NewBeaconBlock()
|
||||
blk.Block.Slot = 162
|
||||
wsb, err = blocks.NewSignedBeaconBlock(blk)
|
||||
require.NoError(t, err)
|
||||
assert.NoError(t, beaconsync.WriteBlockChunk(stream, tor, p1.Encoding(), wsb))
|
||||
assert.NoError(t, stream.Close())
|
||||
})
|
||||
|
||||
// Verify the peer has no bad responses before the request
|
||||
scoreBeforeRequest, err := p1.Peers().Scorers().BadResponsesScorer().Count(p2.PeerID())
|
||||
require.ErrorIs(t, err, peerdata.ErrPeerUnknown)
|
||||
assert.Equal(t, -1, scoreBeforeRequest)
|
||||
|
||||
// Use fetchBlocksFromPeer which includes the downscoring logic
|
||||
_, _, err = fetcher.fetchBlocksFromPeer(ctx, 100, 64, []peer.ID{p2.PeerID()})
|
||||
assert.ErrorContains(t, errNoPeersAvailable.Error(), err)
|
||||
|
||||
// Verify the peer was downscored
|
||||
scoreAfterRequest, err := p1.Peers().Scorers().BadResponsesScorer().Count(p2.PeerID())
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, scoreAfterRequest)
|
||||
}
|
||||
|
||||
func TestTimeToWait(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
327
beacon-chain/sync/kzg_batch_verifier_test.go
Normal file
327
beacon-chain/sync/kzg_batch_verifier_test.go
Normal file
@@ -0,0 +1,327 @@
|
||||
package sync
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain/kzg"
|
||||
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/util"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
)
|
||||
|
||||
func TestValidateWithKzgBatchVerifier(t *testing.T) {
|
||||
err := kzg.Start()
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
dataColumns []blocks.RODataColumn
|
||||
expectedResult pubsub.ValidationResult
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "single valid data column",
|
||||
dataColumns: createValidTestDataColumns(t, 1),
|
||||
expectedResult: pubsub.ValidationAccept,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "multiple valid data columns",
|
||||
dataColumns: createValidTestDataColumns(t, 3),
|
||||
expectedResult: pubsub.ValidationAccept,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "single invalid data column",
|
||||
dataColumns: createInvalidTestDataColumns(t, 1),
|
||||
expectedResult: pubsub.ValidationReject,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "empty data column slice",
|
||||
dataColumns: []blocks.RODataColumn{},
|
||||
expectedResult: pubsub.ValidationAccept,
|
||||
expectError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
service := &Service{
|
||||
ctx: ctx,
|
||||
kzgChan: make(chan *kzgVerifier, 100),
|
||||
}
|
||||
go service.kzgVerifierRoutine()
|
||||
|
||||
result, err := service.validateWithKzgBatchVerifier(ctx, tt.dataColumns)
|
||||
|
||||
require.Equal(t, tt.expectedResult, result)
|
||||
if tt.expectError {
|
||||
assert.NotNil(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifierRoutine(t *testing.T) {
|
||||
err := kzg.Start()
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("processes single request", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
service := &Service{
|
||||
ctx: ctx,
|
||||
kzgChan: make(chan *kzgVerifier, 100),
|
||||
}
|
||||
go service.kzgVerifierRoutine()
|
||||
|
||||
dataColumns := createValidTestDataColumns(t, 1)
|
||||
resChan := make(chan error, 1)
|
||||
service.kzgChan <- &kzgVerifier{dataColumns: dataColumns, resChan: resChan}
|
||||
|
||||
select {
|
||||
case err := <-resChan:
|
||||
require.NoError(t, err)
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("timeout waiting for verification result")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("batches multiple requests", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
service := &Service{
|
||||
ctx: ctx,
|
||||
kzgChan: make(chan *kzgVerifier, 100),
|
||||
}
|
||||
go service.kzgVerifierRoutine()
|
||||
|
||||
const numRequests = 5
|
||||
resChans := make([]chan error, numRequests)
|
||||
|
||||
for i := range numRequests {
|
||||
dataColumns := createValidTestDataColumns(t, 1)
|
||||
resChan := make(chan error, 1)
|
||||
resChans[i] = resChan
|
||||
service.kzgChan <- &kzgVerifier{dataColumns: dataColumns, resChan: resChan}
|
||||
}
|
||||
|
||||
for i := range numRequests {
|
||||
select {
|
||||
case err := <-resChans[i]:
|
||||
require.NoError(t, err)
|
||||
case <-time.After(time.Second):
|
||||
t.Fatalf("timeout waiting for verification result %d", i)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("context cancellation stops routine", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
service := &Service{
|
||||
ctx: ctx,
|
||||
kzgChan: make(chan *kzgVerifier, 100),
|
||||
}
|
||||
|
||||
routineDone := make(chan struct{})
|
||||
go func() {
|
||||
service.kzgVerifierRoutine()
|
||||
close(routineDone)
|
||||
}()
|
||||
|
||||
cancel()
|
||||
|
||||
select {
|
||||
case <-routineDone:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("timeout waiting for routine to exit")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestVerifyKzgBatch(t *testing.T) {
|
||||
err := kzg.Start()
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("all valid data columns succeed", func(t *testing.T) {
|
||||
dataColumns := createValidTestDataColumns(t, 3)
|
||||
resChan := make(chan error, 1)
|
||||
kzgVerifiers := []*kzgVerifier{{dataColumns: dataColumns, resChan: resChan}}
|
||||
|
||||
verifyKzgBatch(kzgVerifiers)
|
||||
|
||||
select {
|
||||
case err := <-resChan:
|
||||
require.NoError(t, err)
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("timeout waiting for batch verification")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("invalid proofs fail entire batch", func(t *testing.T) {
|
||||
validColumns := createValidTestDataColumns(t, 1)
|
||||
invalidColumns := createInvalidTestDataColumns(t, 1)
|
||||
allColumns := append(validColumns, invalidColumns...)
|
||||
|
||||
resChan := make(chan error, 1)
|
||||
kzgVerifiers := []*kzgVerifier{{dataColumns: allColumns, resChan: resChan}}
|
||||
|
||||
verifyKzgBatch(kzgVerifiers)
|
||||
|
||||
select {
|
||||
case err := <-resChan:
|
||||
assert.NotNil(t, err)
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("timeout waiting for batch verification")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("empty batch handling", func(t *testing.T) {
|
||||
verifyKzgBatch([]*kzgVerifier{})
|
||||
})
|
||||
}
|
||||
|
||||
func TestKzgBatchVerifierConcurrency(t *testing.T) {
|
||||
err := kzg.Start()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
service := &Service{
|
||||
ctx: ctx,
|
||||
kzgChan: make(chan *kzgVerifier, 100),
|
||||
}
|
||||
go service.kzgVerifierRoutine()
|
||||
|
||||
const numGoroutines = 10
|
||||
const numRequestsPerGoroutine = 5
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(numGoroutines)
|
||||
|
||||
// Multiple goroutines sending verification requests simultaneously
|
||||
for i := range numGoroutines {
|
||||
go func(goroutineID int) {
|
||||
defer wg.Done()
|
||||
|
||||
for range numRequestsPerGoroutine {
|
||||
dataColumns := createValidTestDataColumns(t, 1)
|
||||
result, err := service.validateWithKzgBatchVerifier(ctx, dataColumns)
|
||||
require.Equal(t, pubsub.ValidationAccept, result)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestKzgBatchVerifierFallback(t *testing.T) {
|
||||
err := kzg.Start()
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("fallback handles mixed valid/invalid batch correctly", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
service := &Service{
|
||||
ctx: ctx,
|
||||
kzgChan: make(chan *kzgVerifier, 100),
|
||||
}
|
||||
go service.kzgVerifierRoutine()
|
||||
|
||||
validColumns := createValidTestDataColumns(t, 1)
|
||||
invalidColumns := createInvalidTestDataColumns(t, 1)
|
||||
|
||||
result, err := service.validateWithKzgBatchVerifier(ctx, validColumns)
|
||||
require.Equal(t, pubsub.ValidationAccept, result)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err = service.validateWithKzgBatchVerifier(ctx, invalidColumns)
|
||||
require.Equal(t, pubsub.ValidationReject, result)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
|
||||
t.Run("empty data columns fallback", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
service := &Service{
|
||||
ctx: ctx,
|
||||
kzgChan: make(chan *kzgVerifier, 100),
|
||||
}
|
||||
go service.kzgVerifierRoutine()
|
||||
|
||||
result, err := service.validateWithKzgBatchVerifier(ctx, []blocks.RODataColumn{})
|
||||
require.Equal(t, pubsub.ValidationAccept, result)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func createValidTestDataColumns(t *testing.T, count int) []blocks.RODataColumn {
|
||||
_, roSidecars, _ := util.GenerateTestFuluBlockWithSidecars(t, count)
|
||||
if len(roSidecars) >= count {
|
||||
return roSidecars[:count]
|
||||
}
|
||||
return roSidecars
|
||||
}
|
||||
|
||||
func createInvalidTestDataColumns(t *testing.T, count int) []blocks.RODataColumn {
|
||||
dataColumns := createValidTestDataColumns(t, count)
|
||||
|
||||
if len(dataColumns) > 0 {
|
||||
sidecar := dataColumns[0].DataColumnSidecar
|
||||
if len(sidecar.Column) > 0 && len(sidecar.Column[0]) > 0 {
|
||||
corruptedSidecar := ðpb.DataColumnSidecar{
|
||||
Index: sidecar.Index,
|
||||
KzgCommitments: make([][]byte, len(sidecar.KzgCommitments)),
|
||||
KzgProofs: make([][]byte, len(sidecar.KzgProofs)),
|
||||
KzgCommitmentsInclusionProof: make([][]byte, len(sidecar.KzgCommitmentsInclusionProof)),
|
||||
SignedBlockHeader: sidecar.SignedBlockHeader,
|
||||
Column: make([][]byte, len(sidecar.Column)),
|
||||
}
|
||||
|
||||
for i, commitment := range sidecar.KzgCommitments {
|
||||
corruptedSidecar.KzgCommitments[i] = make([]byte, len(commitment))
|
||||
copy(corruptedSidecar.KzgCommitments[i], commitment)
|
||||
}
|
||||
|
||||
for i, proof := range sidecar.KzgProofs {
|
||||
corruptedSidecar.KzgProofs[i] = make([]byte, len(proof))
|
||||
copy(corruptedSidecar.KzgProofs[i], proof)
|
||||
}
|
||||
|
||||
for i, proof := range sidecar.KzgCommitmentsInclusionProof {
|
||||
corruptedSidecar.KzgCommitmentsInclusionProof[i] = make([]byte, len(proof))
|
||||
copy(corruptedSidecar.KzgCommitmentsInclusionProof[i], proof)
|
||||
}
|
||||
|
||||
for i, col := range sidecar.Column {
|
||||
corruptedSidecar.Column[i] = make([]byte, len(col))
|
||||
copy(corruptedSidecar.Column[i], col)
|
||||
}
|
||||
corruptedSidecar.Column[0][0] ^= 0xFF // Flip bits to corrupt
|
||||
|
||||
corruptedRO, err := blocks.NewRODataColumn(corruptedSidecar)
|
||||
require.NoError(t, err)
|
||||
dataColumns[0] = corruptedRO
|
||||
}
|
||||
}
|
||||
return dataColumns
|
||||
}
|
||||
@@ -164,6 +164,7 @@ type Service struct {
|
||||
syncContributionBitsOverlapLock sync.RWMutex
|
||||
syncContributionBitsOverlapCache *lru.Cache
|
||||
signatureChan chan *signatureVerifier
|
||||
kzgChan chan *kzgVerifier
|
||||
clockWaiter startup.ClockWaiter
|
||||
initialSyncComplete chan struct{}
|
||||
verifierWaiter *verification.InitializerWaiter
|
||||
@@ -203,6 +204,10 @@ func NewService(ctx context.Context, opts ...Option) *Service {
|
||||
}
|
||||
// Initialize signature channel with configured limit
|
||||
r.signatureChan = make(chan *signatureVerifier, r.cfg.batchVerifierLimit)
|
||||
// Initialize KZG channel with fixed buffer size of 100.
|
||||
// This buffer size is designed to handle burst traffic of data column gossip messages:
|
||||
// - Data columns arrive less frequently than attestations (default batchVerifierLimit=1000)
|
||||
r.kzgChan = make(chan *kzgVerifier, 100)
|
||||
// Correctly remove it from our seen pending block map.
|
||||
// The eviction method always assumes that the mutex is held.
|
||||
r.slotToPendingBlocks.OnEvicted(func(s string, i interface{}) {
|
||||
@@ -255,6 +260,7 @@ func (s *Service) Start() {
|
||||
s.newColumnsVerifier = newDataColumnsVerifierFromInitializer(v)
|
||||
|
||||
go s.verifierRoutine()
|
||||
go s.kzgVerifierRoutine()
|
||||
go s.startDiscoveryAndSubscriptions()
|
||||
go s.processDataColumnLogs()
|
||||
|
||||
|
||||
@@ -145,9 +145,12 @@ func (s *Service) validateDataColumn(ctx context.Context, pid peer.ID, msg *pubs
|
||||
}
|
||||
|
||||
// [REJECT] The sidecar's column data is valid as verified by `verify_data_column_sidecar_kzg_proofs(sidecar)`.
|
||||
if err := verifier.SidecarKzgProofVerified(); err != nil {
|
||||
return pubsub.ValidationReject, err
|
||||
validationResult, err := s.validateWithKzgBatchVerifier(ctx, roDataColumns)
|
||||
if validationResult != pubsub.ValidationAccept {
|
||||
return validationResult, err
|
||||
}
|
||||
// Mark KZG verification as satisfied since we did it via batch verifier
|
||||
verifier.SatisfyRequirement(verification.RequireSidecarKzgProofVerified)
|
||||
|
||||
// [IGNORE] The sidecar is the first sidecar for the tuple `(block_header.slot, block_header.proposer_index, sidecar.index)`
|
||||
// with valid header signature, sidecar inclusion proof, and kzg proof.
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain/kzg"
|
||||
mock "github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain/testing"
|
||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
|
||||
p2ptest "github.com/OffchainLabs/prysm/v6/beacon-chain/p2p/testing"
|
||||
@@ -25,6 +26,9 @@ import (
|
||||
)
|
||||
|
||||
func TestValidateDataColumn(t *testing.T) {
|
||||
err := kzg.Start()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := t.Context()
|
||||
|
||||
t.Run("from self", func(t *testing.T) {
|
||||
@@ -63,10 +67,14 @@ func TestValidateDataColumn(t *testing.T) {
|
||||
|
||||
clock := startup.NewClock(chainService.Genesis, chainService.ValidatorsRoot)
|
||||
service := &Service{
|
||||
cfg: &config{p2p: p, initialSync: &mockSync.Sync{}, clock: clock, chain: chainService},
|
||||
cfg: &config{p2p: p, initialSync: &mockSync.Sync{}, clock: clock, chain: chainService, batchVerifierLimit: 10},
|
||||
ctx: ctx,
|
||||
newColumnsVerifier: newDataColumnsVerifier,
|
||||
seenDataColumnCache: newSlotAwareCache(seenDataColumnSize),
|
||||
kzgChan: make(chan *kzgVerifier, 100),
|
||||
}
|
||||
// Start the KZG verifier routine for batch verification
|
||||
go service.kzgVerifierRoutine()
|
||||
|
||||
// Encode a `beaconBlock` message instead of expected.
|
||||
buf := new(bytes.Buffer)
|
||||
@@ -177,12 +185,6 @@ func TestValidateDataColumn(t *testing.T) {
|
||||
expectedResult: pubsub.ValidationReject,
|
||||
expectedError: genericError,
|
||||
},
|
||||
{
|
||||
name: "sidecar kzg proof verified",
|
||||
verifier: testNewDataColumnSidecarsVerifier(verification.MockDataColumnsVerifier{ErrSidecarKzgProofVerified: genericError}),
|
||||
expectedResult: pubsub.ValidationReject,
|
||||
expectedError: genericError,
|
||||
},
|
||||
{
|
||||
name: "sidecar proposer expected",
|
||||
verifier: testNewDataColumnSidecarsVerifier(verification.MockDataColumnsVerifier{ErrSidecarProposerExpected: genericError}),
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
### Added
|
||||
|
||||
- Populate sszInfo of variable-length fields in AnalyzeObjects
|
||||
3
changelog/james-prysm_deprecate-publish-blos.md
Normal file
3
changelog/james-prysm_deprecate-publish-blos.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Changed
|
||||
|
||||
- Deprecated and added error to /prysm/v1/beacon/blobs endpoint for post Fulu fork.
|
||||
3
changelog/james-prysm_post-block-ssz.md
Normal file
3
changelog/james-prysm_post-block-ssz.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Changed
|
||||
|
||||
- Switching default of validator client rest call for submit block from JSON to SSZ. Fallback json will be attempted.
|
||||
2
changelog/kasey_fix-15607.md
Normal file
2
changelog/kasey_fix-15607.md
Normal file
@@ -0,0 +1,2 @@
|
||||
### Fixed
|
||||
- mitigate potential supernode clustering due to libp2p ConnManager pruning of non-supernodes, see https://github.com/OffchainLabs/prysm/issues/15607.
|
||||
2
changelog/kasey_unwedge-ethspecify.md
Normal file
2
changelog/kasey_unwedge-ethspecify.md
Normal file
@@ -0,0 +1,2 @@
|
||||
### Ignored
|
||||
- Unwedge ethspecify.
|
||||
2
changelog/kasey_update-gossipsub.md
Normal file
2
changelog/kasey_update-gossipsub.md
Normal file
@@ -0,0 +1,2 @@
|
||||
### Changed
|
||||
- Upgraded gossipsub to v0.14.2 and libp2p to v0.39.1.
|
||||
2
changelog/manu-find-peers-subnets.md
Normal file
2
changelog/manu-find-peers-subnets.md
Normal file
@@ -0,0 +1,2 @@
|
||||
### Fixed
|
||||
- Lock the subnet mutex only when trying to find peers, so the mutex is not locked when dialing peers.
|
||||
3
changelog/potuz_fix_forkchoice_startup.md
Normal file
3
changelog/potuz_fix_forkchoice_startup.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Fixed
|
||||
|
||||
- Fixed an off-by-one in forkchoice startup.
|
||||
3
changelog/pvl-downscore-init-sync.md
Normal file
3
changelog/pvl-downscore-init-sync.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Changed
|
||||
|
||||
- Prysm will now downscore peers that return invalid block_by_range responses.
|
||||
3
changelog/pvl-p2p-colocation-whitelist.md
Normal file
3
changelog/pvl-p2p-colocation-whitelist.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Added
|
||||
|
||||
- Added flag `--p2p-colocation-whitelist` to accept CIDRs which will bypass the p2p colocation restrictions.
|
||||
3
changelog/ttsao_implement-kzg-batch-verification.md
Normal file
3
changelog/ttsao_implement-kzg-batch-verification.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Added
|
||||
|
||||
- KZG proof batch verification for data column gossip validation
|
||||
@@ -105,6 +105,7 @@ var appFlags = []cli.Flag{
|
||||
cmd.P2PStaticID,
|
||||
cmd.P2PAllowList,
|
||||
cmd.P2PDenyList,
|
||||
cmd.P2PColocationWhitelist,
|
||||
cmd.PubsubQueueSize,
|
||||
cmd.DataDirFlag,
|
||||
cmd.VerbosityFlag,
|
||||
|
||||
@@ -84,6 +84,7 @@ var appHelpFlagGroups = []flagGroup{
|
||||
cmd.NoDiscovery,
|
||||
cmd.P2PAllowList,
|
||||
cmd.P2PDenyList,
|
||||
cmd.P2PColocationWhitelist,
|
||||
cmd.P2PHost,
|
||||
cmd.P2PHostDNS,
|
||||
cmd.P2PIP,
|
||||
|
||||
@@ -180,6 +180,13 @@ var (
|
||||
"192.168.0.0/16 would deny connections from peers on your local network only. The " +
|
||||
"default is to accept all connections.",
|
||||
}
|
||||
// P2PColocationWhitelist defines a list of CIDR addresses to exempt from IP colocation restrictions.
|
||||
P2PColocationWhitelist = &cli.StringSliceFlag{
|
||||
Name: "p2p-colocation-whitelist",
|
||||
Usage: "CIDR addresses to exempt from gossip sub IP colocation restrictions. " +
|
||||
"Can be specified multiple times. Example: " +
|
||||
"192.168.1.1/32 would exempt that specific IP from colocation restrictions.",
|
||||
}
|
||||
PubsubQueueSize = &cli.IntFlag{
|
||||
Name: "pubsub-queue-size",
|
||||
Usage: "The size of the pubsub validation and outbound queue for the node.",
|
||||
|
||||
176
deps.bzl
176
deps.bzl
@@ -1009,17 +1009,11 @@ def prysm_deps():
|
||||
sum = "h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo=",
|
||||
version = "v0.10.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_go_kit_log",
|
||||
importpath = "github.com/go-kit/log",
|
||||
sum = "h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=",
|
||||
version = "v0.2.1",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_go_logfmt_logfmt",
|
||||
importpath = "github.com/go-logfmt/logfmt",
|
||||
sum = "h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=",
|
||||
version = "v0.5.1",
|
||||
sum = "h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=",
|
||||
version = "v0.5.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_go_logr_logr",
|
||||
@@ -1272,8 +1266,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_google_pprof",
|
||||
importpath = "github.com/google/pprof",
|
||||
sum = "h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=",
|
||||
version = "v0.0.0-20240727154555-813a5fbdbec8",
|
||||
sum = "h1:wlQI2cYY0BsWmmPPAnxfQ8SDW0S3Jasn+4B8kXFxprg=",
|
||||
version = "v0.0.0-20250202011525-fc3143867406",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_google_renameio",
|
||||
@@ -1644,8 +1638,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_ipfs_go_cid",
|
||||
importpath = "github.com/ipfs/go-cid",
|
||||
sum = "h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=",
|
||||
version = "v0.4.1",
|
||||
sum = "h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg=",
|
||||
version = "v0.5.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_ipfs_go_datastore",
|
||||
@@ -1856,8 +1850,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_klauspost_compress",
|
||||
importpath = "github.com/klauspost/compress",
|
||||
sum = "h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=",
|
||||
version = "v1.17.9",
|
||||
sum = "h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=",
|
||||
version = "v1.17.11",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_klauspost_cpuid",
|
||||
@@ -1868,8 +1862,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_klauspost_cpuid_v2",
|
||||
importpath = "github.com/klauspost/cpuid/v2",
|
||||
sum = "h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=",
|
||||
version = "v2.2.8",
|
||||
sum = "h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=",
|
||||
version = "v2.2.9",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_klauspost_reedsolomon",
|
||||
@@ -1892,8 +1886,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_koron_go_ssdp",
|
||||
importpath = "github.com/koron/go-ssdp",
|
||||
sum = "h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0=",
|
||||
version = "v0.0.4",
|
||||
sum = "h1:E1iSMxIs4WqxTbIBLtmNBeOOC+1sCIXQeqTWVnpmwhk=",
|
||||
version = "v0.0.5",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_korovkin_limiter",
|
||||
@@ -1970,8 +1964,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_libp2p_go_flow_metrics",
|
||||
importpath = "github.com/libp2p/go-flow-metrics",
|
||||
sum = "h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM=",
|
||||
version = "v0.1.0",
|
||||
sum = "h1:EIZzjmeOE6c8Dav0sNv35vhZxATIXWZg6j/C08XmmDw=",
|
||||
version = "v0.2.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_libp2p_go_libp2p",
|
||||
@@ -1980,8 +1974,8 @@ def prysm_deps():
|
||||
],
|
||||
build_file_proto_mode = "disable_global",
|
||||
importpath = "github.com/libp2p/go-libp2p",
|
||||
sum = "h1:DoABsaHO0VXwH6pwCs2F6XKAXWYjFMO4HFBoVxTnF9g=",
|
||||
version = "v0.36.5",
|
||||
sum = "h1:1Ur6rPCf3GR+g8jkrnaQaM0ha2IGespsnNlCqJLLALE=",
|
||||
version = "v0.39.1",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_libp2p_go_libp2p_asn_util",
|
||||
@@ -1999,8 +1993,8 @@ def prysm_deps():
|
||||
name = "com_github_libp2p_go_libp2p_pubsub",
|
||||
build_file_proto_mode = "disable_global",
|
||||
importpath = "github.com/libp2p/go-libp2p-pubsub",
|
||||
sum = "h1:RmFQ2XAy3zQtbt2iNPy7Tt0/3fwTnHpCQSSnmGnt1Ps=",
|
||||
version = "v0.13.0",
|
||||
sum = "h1:nT5lFHPQOFJcp9CW8hpKtvbpQNdl2udJuzLQWbgRum8=",
|
||||
version = "v0.14.2",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_libp2p_go_libp2p_testing",
|
||||
@@ -2029,8 +2023,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_libp2p_go_netroute",
|
||||
importpath = "github.com/libp2p/go-netroute",
|
||||
sum = "h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU=",
|
||||
version = "v0.2.1",
|
||||
sum = "h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8=",
|
||||
version = "v0.2.2",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_libp2p_go_reuseport",
|
||||
@@ -2041,8 +2035,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_libp2p_go_yamux_v4",
|
||||
importpath = "github.com/libp2p/go-yamux/v4",
|
||||
sum = "h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ=",
|
||||
version = "v4.0.1",
|
||||
sum = "h1:nrLh89LN/LEiqcFiqdKDRHjGstN300C1269K/EX0CPU=",
|
||||
version = "v4.0.2",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_libp2p_zeroconf_v2",
|
||||
@@ -2185,8 +2179,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_miekg_dns",
|
||||
importpath = "github.com/miekg/dns",
|
||||
sum = "h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=",
|
||||
version = "v1.1.62",
|
||||
sum = "h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=",
|
||||
version = "v1.1.63",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_mikioh_tcp",
|
||||
@@ -2329,14 +2323,14 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_multiformats_go_multiaddr",
|
||||
importpath = "github.com/multiformats/go-multiaddr",
|
||||
sum = "h1:BCBzs61E3AGHcYYTv8dqRH43ZfyrqM8RXVPT8t13tLQ=",
|
||||
version = "v0.13.0",
|
||||
sum = "h1:bfrHrJhrRuh/NXH5mCnemjpbGjzRw/b+tJFOD41g2tU=",
|
||||
version = "v0.14.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_multiformats_go_multiaddr_dns",
|
||||
importpath = "github.com/multiformats/go-multiaddr-dns",
|
||||
sum = "h1:P76EJ3qzBXpUXZ3twdCDx/kvagMsNo0LMFXpyms/zgU=",
|
||||
version = "v0.4.0",
|
||||
sum = "h1:whi/uCLbDS3mSEUMb1MsoT4uzUeZB0N32yzufqS0i5M=",
|
||||
version = "v0.4.1",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_multiformats_go_multiaddr_fmt",
|
||||
@@ -2368,8 +2362,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_multiformats_go_multistream",
|
||||
importpath = "github.com/multiformats/go-multistream",
|
||||
sum = "h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE=",
|
||||
version = "v0.5.0",
|
||||
sum = "h1:ZaHKbsL404720283o4c/IHQXiS6gb8qAN5EIJ4PN5EA=",
|
||||
version = "v0.6.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_multiformats_go_varint",
|
||||
@@ -2482,14 +2476,14 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_onsi_ginkgo_v2",
|
||||
importpath = "github.com/onsi/ginkgo/v2",
|
||||
sum = "h1:PE84V2mHqoT1sglvHc8ZdQtPcwmvvt29WLEEO3xmdZw=",
|
||||
version = "v2.20.0",
|
||||
sum = "h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=",
|
||||
version = "v2.22.2",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_onsi_gomega",
|
||||
importpath = "github.com/onsi/gomega",
|
||||
sum = "h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=",
|
||||
version = "v1.34.1",
|
||||
sum = "h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=",
|
||||
version = "v1.36.2",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_op_go_logging",
|
||||
@@ -2644,8 +2638,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_pion_datachannel",
|
||||
importpath = "github.com/pion/datachannel",
|
||||
sum = "h1:ph1P1NsGkazkjrvyMfhRBUAWMxugJjq2HfQifaOoSNo=",
|
||||
version = "v1.5.8",
|
||||
sum = "h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o=",
|
||||
version = "v1.5.10",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_dtls_v2",
|
||||
@@ -2653,23 +2647,35 @@ def prysm_deps():
|
||||
sum = "h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk=",
|
||||
version = "v2.2.12",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_dtls_v3",
|
||||
importpath = "github.com/pion/dtls/v3",
|
||||
sum = "h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U=",
|
||||
version = "v3.0.4",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_ice_v2",
|
||||
importpath = "github.com/pion/ice/v2",
|
||||
sum = "h1:Ic1ppYCj4tUOcPAp76U6F3fVrlSw8A9JtRXLqw6BbUM=",
|
||||
version = "v2.3.34",
|
||||
sum = "h1:ObIdaNDu1rCo7hObhs34YSBcO7fjslJMZV0ux+uZWh0=",
|
||||
version = "v2.3.37",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_ice_v4",
|
||||
importpath = "github.com/pion/ice/v4",
|
||||
sum = "h1:jmM9HwI9lfetQV/39uD0nY4y++XZNPhvzIPCb8EwxUM=",
|
||||
version = "v4.0.6",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_interceptor",
|
||||
importpath = "github.com/pion/interceptor",
|
||||
sum = "h1:au5rlVHsgmxNi+v/mjOPazbW1SHzfx7/hYOEYQnUcxA=",
|
||||
version = "v0.1.30",
|
||||
sum = "h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI=",
|
||||
version = "v0.1.37",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_logging",
|
||||
importpath = "github.com/pion/logging",
|
||||
sum = "h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=",
|
||||
version = "v0.2.2",
|
||||
sum = "h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI=",
|
||||
version = "v0.2.3",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_mdns",
|
||||
@@ -2677,6 +2683,12 @@ def prysm_deps():
|
||||
sum = "h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8=",
|
||||
version = "v0.0.12",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_mdns_v2",
|
||||
importpath = "github.com/pion/mdns/v2",
|
||||
sum = "h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM=",
|
||||
version = "v2.0.7",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_randutil",
|
||||
importpath = "github.com/pion/randutil",
|
||||
@@ -2686,32 +2698,32 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_pion_rtcp",
|
||||
importpath = "github.com/pion/rtcp",
|
||||
sum = "h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE=",
|
||||
version = "v1.2.14",
|
||||
sum = "h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo=",
|
||||
version = "v1.2.15",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_rtp",
|
||||
importpath = "github.com/pion/rtp",
|
||||
sum = "h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk=",
|
||||
version = "v1.8.9",
|
||||
sum = "h1:17xjnY5WO5hgO6SD3/NTIUPvSFw/PbLsIJyz1r1yNIk=",
|
||||
version = "v1.8.11",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_sctp",
|
||||
importpath = "github.com/pion/sctp",
|
||||
sum = "h1:dSE4wX6uTJBcNm8+YlMg7lw1wqyKHggsP5uKbdj+NZw=",
|
||||
version = "v1.8.33",
|
||||
sum = "h1:qwtKvNK1Wc5tHMIYgTDJhfZk7vATGVHhXbUDfHbYwzA=",
|
||||
version = "v1.8.35",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_sdp_v3",
|
||||
importpath = "github.com/pion/sdp/v3",
|
||||
sum = "h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY=",
|
||||
version = "v3.0.9",
|
||||
sum = "h1:6MChLE/1xYB+CjumMw+gZ9ufp2DPApuVSnDT8t5MIgA=",
|
||||
version = "v3.0.10",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_srtp_v2",
|
||||
importpath = "github.com/pion/srtp/v2",
|
||||
sum = "h1:HNNny4s+OUmG280ETrCdgFndp4ufx3/uy85EawYEhTk=",
|
||||
version = "v2.0.20",
|
||||
name = "com_github_pion_srtp_v3",
|
||||
importpath = "github.com/pion/srtp/v3",
|
||||
sum = "h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M=",
|
||||
version = "v3.0.4",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_stun",
|
||||
@@ -2725,6 +2737,12 @@ def prysm_deps():
|
||||
sum = "h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0=",
|
||||
version = "v2.0.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_stun_v3",
|
||||
importpath = "github.com/pion/stun/v3",
|
||||
sum = "h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw=",
|
||||
version = "v3.0.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_transport_v2",
|
||||
importpath = "github.com/pion/transport/v2",
|
||||
@@ -2744,10 +2762,16 @@ def prysm_deps():
|
||||
version = "v2.1.6",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_webrtc_v3",
|
||||
importpath = "github.com/pion/webrtc/v3",
|
||||
sum = "h1:Rf4u6n6U5t5sUxhYPQk/samzU/oDv7jk6BA5hyO2F9I=",
|
||||
version = "v3.3.0",
|
||||
name = "com_github_pion_turn_v4",
|
||||
importpath = "github.com/pion/turn/v4",
|
||||
sum = "h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM=",
|
||||
version = "v4.0.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pion_webrtc_v4",
|
||||
importpath = "github.com/pion/webrtc/v4",
|
||||
sum = "h1:T1ZmnT9qxIJIt4d8XoiMOBrTClGHDDXNg9e/fh018Qc=",
|
||||
version = "v4.0.8",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_pkg_diff",
|
||||
@@ -2800,8 +2824,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_prometheus_client_golang",
|
||||
importpath = "github.com/prometheus/client_golang",
|
||||
sum = "h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI=",
|
||||
version = "v1.20.0",
|
||||
sum = "h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=",
|
||||
version = "v1.20.5",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_prometheus_client_model",
|
||||
@@ -2812,8 +2836,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_prometheus_common",
|
||||
importpath = "github.com/prometheus/common",
|
||||
sum = "h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=",
|
||||
version = "v0.55.0",
|
||||
sum = "h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=",
|
||||
version = "v0.62.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_prometheus_procfs",
|
||||
@@ -2891,8 +2915,8 @@ def prysm_deps():
|
||||
"gazelle:exclude tools.go",
|
||||
],
|
||||
importpath = "github.com/quic-go/quic-go",
|
||||
sum = "h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=",
|
||||
version = "v0.48.2",
|
||||
sum = "h1:w5iJHXwHxs1QxyBv1EHKuC50GX5to8mJAxvtnttJp94=",
|
||||
version = "v0.49.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_quic_go_webtransport_go",
|
||||
@@ -3504,8 +3528,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_wlynxg_anet",
|
||||
importpath = "github.com/wlynxg/anet",
|
||||
sum = "h1:0de1OFQxnNqAu+x2FAKKCVIrnfGKQbs7FQz++tB0+Uw=",
|
||||
version = "v0.0.4",
|
||||
sum = "h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=",
|
||||
version = "v0.0.5",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_x448_float16",
|
||||
@@ -4757,8 +4781,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "org_golang_x_exp",
|
||||
importpath = "golang.org/x/exp",
|
||||
sum = "h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=",
|
||||
version = "v0.0.0-20240808152545-0cdaa3abc0fa",
|
||||
sum = "h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc=",
|
||||
version = "v0.0.0-20250128182459-e0ece0dbea4c",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_exp_typeparams",
|
||||
@@ -4882,8 +4906,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "org_uber_go_fx",
|
||||
importpath = "go.uber.org/fx",
|
||||
sum = "h1:iPW+OPxv0G8w75OemJ1RAnTUrF55zOJlXlo1TbJ0Buw=",
|
||||
version = "v1.22.2",
|
||||
sum = "h1:lIr/gYWQGfTwGcSXWXu4vP5Ws6iqnNEIY+F/aFzCKTg=",
|
||||
version = "v1.23.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_uber_go_goleak",
|
||||
|
||||
@@ -18,6 +18,12 @@ func AnalyzeObject(obj any) (*sszInfo, error) {
|
||||
return nil, fmt.Errorf("could not analyze type %s: %w", value.Type().Name(), err)
|
||||
}
|
||||
|
||||
// Populate variable-length information using the actual value.
|
||||
err = PopulateVariableLengthInfo(info, value.Interface())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not populate variable length info: %w", err)
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -171,11 +171,9 @@ func TestCalculateOffsetAndLength(t *testing.T) {
|
||||
path, err := query.ParsePath(tt.path)
|
||||
require.NoError(t, err)
|
||||
|
||||
info, err := query.AnalyzeObject(&sszquerypb.VariableTestContainer{})
|
||||
require.NoError(t, err)
|
||||
|
||||
testContainer := createVariableTestContainer()
|
||||
err = query.PopulateVariableLengthInfo(info, testContainer)
|
||||
|
||||
info, err := query.AnalyzeObject(testContainer)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, offset, length, err := query.CalculateOffsetAndLength(info, path)
|
||||
|
||||
67
go.mod
67
go.mod
@@ -41,9 +41,9 @@ require (
|
||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213
|
||||
github.com/kisielk/errcheck v1.8.0
|
||||
github.com/kr/pretty v0.3.1
|
||||
github.com/libp2p/go-libp2p v0.36.5
|
||||
github.com/libp2p/go-libp2p v0.39.1
|
||||
github.com/libp2p/go-libp2p-mplex v0.9.0
|
||||
github.com/libp2p/go-libp2p-pubsub v0.13.0
|
||||
github.com/libp2p/go-libp2p-pubsub v0.14.2
|
||||
github.com/libp2p/go-mplex v0.7.0
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/manifoldco/promptui v0.7.0
|
||||
@@ -51,12 +51,12 @@ require (
|
||||
github.com/minio/highwayhash v1.0.2
|
||||
github.com/minio/sha256-simd v1.0.1
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
github.com/multiformats/go-multiaddr v0.13.0
|
||||
github.com/multiformats/go-multiaddr v0.14.0
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/paulbellamy/ratecounter v0.2.0
|
||||
github.com/pborman/uuid v1.2.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.20.0
|
||||
github.com/prometheus/client_golang v1.20.5
|
||||
github.com/prometheus/client_model v0.6.1
|
||||
github.com/prometheus/prom2json v1.3.0
|
||||
github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516
|
||||
@@ -89,7 +89,7 @@ require (
|
||||
go.uber.org/automaxprocs v1.5.2
|
||||
go.uber.org/mock v0.5.2
|
||||
golang.org/x/crypto v0.36.0
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
|
||||
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c
|
||||
golang.org/x/sync v0.12.0
|
||||
golang.org/x/tools v0.30.0
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1
|
||||
@@ -150,7 +150,7 @@ require (
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
|
||||
github.com/google/pprof v0.0.0-20250202011525-fc3143867406 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/graph-gophers/graphql-go v1.3.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
|
||||
@@ -163,30 +163,30 @@ require (
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.4.0 // indirect
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect
|
||||
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
|
||||
github.com/ipfs/go-cid v0.4.1 // indirect
|
||||
github.com/ipfs/go-cid v0.5.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/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/koron/go-ssdp v0.0.4 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
|
||||
github.com/koron/go-ssdp v0.0.5 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/leodido/go-urn v1.2.3 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
||||
github.com/libp2p/go-flow-metrics v0.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-msgio v0.3.0 // indirect
|
||||
github.com/libp2p/go-nat v0.2.0 // indirect
|
||||
github.com/libp2p/go-netroute v0.2.1 // 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/v4 v4.0.2 // indirect
|
||||
github.com/lunixbochs/vtclean v1.0.0 // indirect
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // 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/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
@@ -198,42 +198,47 @@ require (
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/multiformats/go-base32 v0.1.0 // indirect
|
||||
github.com/multiformats/go-base36 v0.2.0 // indirect
|
||||
github.com/multiformats/go-multiaddr-dns v0.4.0 // indirect
|
||||
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-multihash v0.2.3 // indirect
|
||||
github.com/multiformats/go-multistream v0.5.0 // indirect
|
||||
github.com/multiformats/go-multistream v0.6.0 // 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
|
||||
github.com/onsi/ginkgo/v2 v2.20.0 // 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/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/pion/datachannel v1.5.8 // 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.34 // indirect
|
||||
github.com/pion/interceptor v0.1.30 // indirect
|
||||
github.com/pion/logging v0.2.2 // indirect
|
||||
github.com/pion/dtls/v3 v3.0.4 // indirect
|
||||
github.com/pion/ice/v2 v2.3.37 // indirect
|
||||
github.com/pion/ice/v4 v4.0.6 // indirect
|
||||
github.com/pion/interceptor v0.1.37 // indirect
|
||||
github.com/pion/logging v0.2.3 // indirect
|
||||
github.com/pion/mdns v0.0.12 // indirect
|
||||
github.com/pion/mdns/v2 v2.0.7 // indirect
|
||||
github.com/pion/randutil v0.1.0 // indirect
|
||||
github.com/pion/rtcp v1.2.14 // indirect
|
||||
github.com/pion/rtp v1.8.9 // indirect
|
||||
github.com/pion/sctp v1.8.33 // indirect
|
||||
github.com/pion/sdp/v3 v3.0.9 // indirect
|
||||
github.com/pion/srtp/v2 v2.0.20 // indirect
|
||||
github.com/pion/rtcp v1.2.15 // indirect
|
||||
github.com/pion/rtp v1.8.11 // indirect
|
||||
github.com/pion/sctp v1.8.35 // 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/v2 v2.0.0 // 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.0 // indirect
|
||||
github.com/pion/turn/v4 v4.0.0 // indirect
|
||||
github.com/pion/webrtc/v4 v4.0.8 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/common v0.55.0 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // 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.49.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
|
||||
@@ -246,7 +251,7 @@ require (
|
||||
github.com/tklauser/go-sysconf v0.3.13 // indirect
|
||||
github.com/tklauser/numcpus v0.7.0 // indirect
|
||||
github.com/wealdtech/go-eth2-types/v2 v2.8.2 // indirect
|
||||
github.com/wlynxg/anet v0.0.4 // indirect
|
||||
github.com/wlynxg/anet v0.0.5 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
@@ -254,7 +259,7 @@ require (
|
||||
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||
go.uber.org/dig v1.18.0 // indirect
|
||||
go.uber.org/fx v1.22.2 // indirect
|
||||
go.uber.org/fx v1.23.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 // indirect
|
||||
|
||||
141
go.sum
141
go.sum
@@ -413,8 +413,8 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg=
|
||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=
|
||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/google/pprof v0.0.0-20250202011525-fc3143867406 h1:wlQI2cYY0BsWmmPPAnxfQ8SDW0S3Jasn+4B8kXFxprg=
|
||||
github.com/google/pprof v0.0.0-20250202011525-fc3143867406/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=
|
||||
@@ -511,8 +511,8 @@ github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod
|
||||
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
|
||||
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/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-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY=
|
||||
github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
||||
@@ -547,17 +547,17 @@ github.com/kisielk/errcheck v1.8.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.10.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
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 v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
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/klauspost/reedsolomon v1.9.3/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
|
||||
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.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0=
|
||||
github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk=
|
||||
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/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
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=
|
||||
@@ -581,16 +581,16 @@ github.com/leodido/go-urn v1.2.3 h1:6BE2vPT0lqoz3fmOesHZiaiFh7889ssCo2GMvLCfiuA=
|
||||
github.com/leodido/go-urn v1.2.3/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
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-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM=
|
||||
github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro=
|
||||
github.com/libp2p/go-libp2p v0.36.5 h1:DoABsaHO0VXwH6pwCs2F6XKAXWYjFMO4HFBoVxTnF9g=
|
||||
github.com/libp2p/go-libp2p v0.36.5/go.mod h1:CpszAtXxHYOcyvB7K8rSHgnNlh21eKjYbEfLoMerbEI=
|
||||
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.39.1 h1:1Ur6rPCf3GR+g8jkrnaQaM0ha2IGespsnNlCqJLLALE=
|
||||
github.com/libp2p/go-libp2p v0.39.1/go.mod h1:3zicI8Lp7Isun+Afo/JOACUbbJqqR2owK6RQWFsVAbI=
|
||||
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-pubsub v0.14.2 h1:nT5lFHPQOFJcp9CW8hpKtvbpQNdl2udJuzLQWbgRum8=
|
||||
github.com/libp2p/go-libp2p-pubsub v0.14.2/go.mod h1:MKPU5vMI8RRFyTP0HfdsF9cLmL1nHAeJm44AxJGJx44=
|
||||
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-mplex v0.7.0 h1:BDhFZdlk5tbr0oyFq/xv/NPGfjbnrsDam1EvutpBDbY=
|
||||
@@ -599,12 +599,12 @@ 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-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU=
|
||||
github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ=
|
||||
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.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-yamux/v4 v4.0.2 h1:nrLh89LN/LEiqcFiqdKDRHjGstN300C1269K/EX0CPU=
|
||||
github.com/libp2p/go-yamux/v4 v4.0.2/go.mod h1:C808cCRgOs1iBwY4S71T5oxgMxgLmqUw56qh4AeBW2o=
|
||||
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/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
||||
@@ -653,8 +653,8 @@ github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1f
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
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.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=
|
||||
@@ -703,10 +703,10 @@ github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYg
|
||||
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.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
|
||||
github.com/multiformats/go-multiaddr v0.13.0 h1:BCBzs61E3AGHcYYTv8dqRH43ZfyrqM8RXVPT8t13tLQ=
|
||||
github.com/multiformats/go-multiaddr v0.13.0/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII=
|
||||
github.com/multiformats/go-multiaddr-dns v0.4.0 h1:P76EJ3qzBXpUXZ3twdCDx/kvagMsNo0LMFXpyms/zgU=
|
||||
github.com/multiformats/go-multiaddr-dns v0.4.0/go.mod h1:7hfthtB4E4pQwirrz+J0CcDUfbWzTqEzVyYKKIKpgkc=
|
||||
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-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.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=
|
||||
github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
|
||||
@@ -716,8 +716,8 @@ github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI1
|
||||
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
|
||||
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.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE=
|
||||
github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA=
|
||||
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.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=
|
||||
@@ -748,14 +748,14 @@ 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.20.0 h1:PE84V2mHqoT1sglvHc8ZdQtPcwmvvt29WLEEO3xmdZw=
|
||||
github.com/onsi/ginkgo/v2 v2.20.0/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI=
|
||||
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.7.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.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
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/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc=
|
||||
github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw=
|
||||
@@ -798,39 +798,45 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi
|
||||
github.com/pierrec/lz4 v2.4.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
||||
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||
github.com/pion/datachannel v1.5.8 h1:ph1P1NsGkazkjrvyMfhRBUAWMxugJjq2HfQifaOoSNo=
|
||||
github.com/pion/datachannel v1.5.8/go.mod h1:PgmdpoaNBLX9HNzNClmdki4DYW5JtI7Yibu8QzbL3tI=
|
||||
github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o=
|
||||
github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M=
|
||||
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.34 h1:Ic1ppYCj4tUOcPAp76U6F3fVrlSw8A9JtRXLqw6BbUM=
|
||||
github.com/pion/ice/v2 v2.3.34/go.mod h1:mBF7lnigdqgtB+YHkaY/Y6s6tsyRyo4u4rPGRuOjUBQ=
|
||||
github.com/pion/interceptor v0.1.30 h1:au5rlVHsgmxNi+v/mjOPazbW1SHzfx7/hYOEYQnUcxA=
|
||||
github.com/pion/interceptor v0.1.30/go.mod h1:RQuKT5HTdkP2Fi0cuOS5G5WNymTjzXaGF75J4k7z2nc=
|
||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
||||
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/v2 v2.3.37 h1:ObIdaNDu1rCo7hObhs34YSBcO7fjslJMZV0ux+uZWh0=
|
||||
github.com/pion/ice/v2 v2.3.37/go.mod h1:mBF7lnigdqgtB+YHkaY/Y6s6tsyRyo4u4rPGRuOjUBQ=
|
||||
github.com/pion/ice/v4 v4.0.6 h1:jmM9HwI9lfetQV/39uD0nY4y++XZNPhvzIPCb8EwxUM=
|
||||
github.com/pion/ice/v4 v4.0.6/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=
|
||||
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 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/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.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE=
|
||||
github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4=
|
||||
github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
|
||||
github.com/pion/rtp v1.8.9 h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk=
|
||||
github.com/pion/rtp v1.8.9/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
|
||||
github.com/pion/sctp v1.8.33 h1:dSE4wX6uTJBcNm8+YlMg7lw1wqyKHggsP5uKbdj+NZw=
|
||||
github.com/pion/sctp v1.8.33/go.mod h1:beTnqSzewI53KWoG3nqB282oDMGrhNxBdb+JZnkCwRM=
|
||||
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/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.35 h1:qwtKvNK1Wc5tHMIYgTDJhfZk7vATGVHhXbUDfHbYwzA=
|
||||
github.com/pion/sctp v1.8.35/go.mod h1:EcXP8zCYVTRy3W9xtOF7wJm1L1aXfKRQzaM33SjQlzg=
|
||||
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=
|
||||
@@ -840,8 +846,10 @@ github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uP
|
||||
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.0 h1:Rf4u6n6U5t5sUxhYPQk/samzU/oDv7jk6BA5hyO2F9I=
|
||||
github.com/pion/webrtc/v3 v3.3.0/go.mod h1:hVmrDJvwhEertRWObeb1xzulzHGeVUoPlWvxdGzcfU0=
|
||||
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.8 h1:T1ZmnT9qxIJIt4d8XoiMOBrTClGHDDXNg9e/fh018Qc=
|
||||
github.com/pion/webrtc/v4 v4.0.8/go.mod h1:HHBeUVBAC+j4ZFnYhovEFStF02Arb1EyD4G7e7HBTJw=
|
||||
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=
|
||||
@@ -864,8 +872,8 @@ github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeD
|
||||
github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||
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.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI=
|
||||
github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
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_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=
|
||||
@@ -881,8 +889,8 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
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.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
||||
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
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=
|
||||
@@ -908,8 +916,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.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.49.0 h1:w5iJHXwHxs1QxyBv1EHKuC50GX5to8mJAxvtnttJp94=
|
||||
github.com/quic-go/quic-go v0.49.0/go.mod h1:s2wDnmCdooUQBmQfpUSTCYBl1/D4FcqbULMMkASvR6s=
|
||||
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/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0=
|
||||
@@ -1011,7 +1019,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
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=
|
||||
@@ -1061,8 +1068,8 @@ github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3/go.mod h1:qiIima
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.2 h1:264/meVYWt1wFw6Mtn+xwkZkXjID42gNra4rycoiDXI=
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.2/go.mod h1:k6kmiKWSWBTd4OxFifTEkPaBLhZspnO2KFD5XJY9nqg=
|
||||
github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
|
||||
github.com/wlynxg/anet v0.0.4 h1:0de1OFQxnNqAu+x2FAKKCVIrnfGKQbs7FQz++tB0+Uw=
|
||||
github.com/wlynxg/anet v0.0.4/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/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
||||
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
@@ -1122,8 +1129,8 @@ go.uber.org/automaxprocs v1.5.2 h1:2LxUOGiR3O6tw8ui5sZa2LAaHnsviZdVOUZw4fvbnME=
|
||||
go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
|
||||
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.22.2 h1:iPW+OPxv0G8w75OemJ1RAnTUrF55zOJlXlo1TbJ0Buw=
|
||||
go.uber.org/fx v1.22.2/go.mod h1:o/D9n+2mLP6v1EG+qsdT1O8wKopYAsqZasju97SDFCU=
|
||||
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/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
@@ -1179,8 +1186,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc=
|
||||
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
||||
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 h1:1P7xPZEwZMoBoz0Yze5Nx2/4pxj6nw9ZqHWXqP0iRgQ=
|
||||
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
|
||||
@@ -3737,8 +3737,6 @@
|
||||
sources:
|
||||
- file: beacon-chain/core/validators/validator.go
|
||||
search: func InitiateValidatorExit(
|
||||
- file: beacon-chain/core/validators/validator.go
|
||||
search: if s.Version() < version.Electra {
|
||||
spec: |
|
||||
<spec fn="initiate_validator_exit" fork="phase0" hash="0483a058">
|
||||
def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
|
||||
|
||||
@@ -91,18 +91,6 @@ go_test(
|
||||
"index_test.go",
|
||||
"prepare_beacon_proposer_test.go",
|
||||
"propose_attestation_test.go",
|
||||
"propose_beacon_block_altair_test.go",
|
||||
"propose_beacon_block_bellatrix_test.go",
|
||||
"propose_beacon_block_blinded_bellatrix_test.go",
|
||||
"propose_beacon_block_blinded_capella_test.go",
|
||||
"propose_beacon_block_blinded_deneb_test.go",
|
||||
"propose_beacon_block_blinded_electra_test.go",
|
||||
"propose_beacon_block_blinded_fulu_test.go",
|
||||
"propose_beacon_block_capella_test.go",
|
||||
"propose_beacon_block_deneb_test.go",
|
||||
"propose_beacon_block_electra_test.go",
|
||||
"propose_beacon_block_fulu_test.go",
|
||||
"propose_beacon_block_phase0_test.go",
|
||||
"propose_beacon_block_test.go",
|
||||
"propose_exit_test.go",
|
||||
"prysm_beacon_chain_client_test.go",
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||
rpctesting "github.com/OffchainLabs/prysm/v6/beacon-chain/rpc/eth/shared/testing"
|
||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||
"github.com/OffchainLabs/prysm/v6/network/httputil"
|
||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||
@@ -136,15 +140,14 @@ func TestBeaconApiValidatorClient_ProposeBeaconBlockValid(t *testing.T) {
|
||||
ctx := t.Context()
|
||||
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
jsonRestHandler.EXPECT().PostSSZ(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blocks",
|
||||
map[string]string{"Eth-Consensus-Version": "phase0"},
|
||||
gomock.Any(),
|
||||
nil,
|
||||
gomock.Any(),
|
||||
).Return(
|
||||
nil,
|
||||
).Times(2)
|
||||
nil, nil, nil,
|
||||
).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
expectedResp, expectedErr := validatorClient.proposeBeaconBlock(
|
||||
@@ -153,34 +156,38 @@ func TestBeaconApiValidatorClient_ProposeBeaconBlockValid(t *testing.T) {
|
||||
Block: generateSignedPhase0Block(),
|
||||
},
|
||||
)
|
||||
|
||||
resp, err := validatorClient.ProposeBeaconBlock(
|
||||
ctx,
|
||||
ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedPhase0Block(),
|
||||
},
|
||||
)
|
||||
|
||||
assert.DeepEqual(t, expectedErr, err)
|
||||
assert.DeepEqual(t, expectedResp, resp)
|
||||
require.NoError(t, expectedErr)
|
||||
require.NotNil(t, expectedResp)
|
||||
}
|
||||
|
||||
func TestBeaconApiValidatorClient_ProposeBeaconBlockError(t *testing.T) {
|
||||
func TestBeaconApiValidatorClient_ProposeBeaconBlockError_ThenPass(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
ctx := t.Context()
|
||||
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
jsonRestHandler.EXPECT().PostSSZ(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blocks",
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
).Return(
|
||||
nil, nil, &httputil.DefaultJsonError{
|
||||
Code: http.StatusNotAcceptable,
|
||||
Message: "SSZ not supported",
|
||||
},
|
||||
).Times(1)
|
||||
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blocks",
|
||||
map[string]string{"Eth-Consensus-Version": "phase0"},
|
||||
gomock.Any(),
|
||||
nil,
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
).Return(
|
||||
errors.New("foo error"),
|
||||
).Times(2)
|
||||
nil,
|
||||
).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
expectedResp, expectedErr := validatorClient.proposeBeaconBlock(
|
||||
@@ -189,16 +196,351 @@ func TestBeaconApiValidatorClient_ProposeBeaconBlockError(t *testing.T) {
|
||||
Block: generateSignedPhase0Block(),
|
||||
},
|
||||
)
|
||||
require.NoError(t, expectedErr)
|
||||
require.NotNil(t, expectedResp)
|
||||
}
|
||||
|
||||
resp, err := validatorClient.ProposeBeaconBlock(
|
||||
ctx,
|
||||
ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedPhase0Block(),
|
||||
func TestBeaconApiValidatorClient_ProposeBeaconBlockAllTypes(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
block *ethpb.GenericSignedBeaconBlock
|
||||
expectedPath string
|
||||
wantErr bool
|
||||
errorMessage string
|
||||
}{
|
||||
{
|
||||
name: "Phase0 block",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedPhase0Block(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blocks",
|
||||
},
|
||||
)
|
||||
{
|
||||
name: "Altair block",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedAltairBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blocks",
|
||||
},
|
||||
{
|
||||
name: "Bellatrix block",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedBellatrixBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blocks",
|
||||
},
|
||||
{
|
||||
name: "Capella block",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedCapellaBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blocks",
|
||||
},
|
||||
{
|
||||
name: "Blinded Bellatrix block",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedBlindedBellatrixBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blinded_blocks",
|
||||
},
|
||||
{
|
||||
name: "Blinded Capella block",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedBlindedCapellaBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blinded_blocks",
|
||||
},
|
||||
{
|
||||
name: "Deneb block",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedDenebBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blocks",
|
||||
},
|
||||
{
|
||||
name: "Blinded Deneb block",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedBlindedDenebBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blinded_blocks",
|
||||
},
|
||||
{
|
||||
name: "Electra block",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedElectraBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blocks",
|
||||
},
|
||||
{
|
||||
name: "Blinded Electra block",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedBlindedElectraBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blinded_blocks",
|
||||
},
|
||||
{
|
||||
name: "Fulu block",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedFuluBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blocks",
|
||||
},
|
||||
{
|
||||
name: "Blinded Fulu block",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedBlindedFuluBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blinded_blocks",
|
||||
},
|
||||
{
|
||||
name: "Unsupported block type",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: nil,
|
||||
},
|
||||
wantErr: true,
|
||||
errorMessage: "unsupported block type",
|
||||
},
|
||||
}
|
||||
|
||||
assert.ErrorContains(t, expectedErr.Error(), err)
|
||||
assert.DeepEqual(t, expectedResp, resp)
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
ctx := t.Context()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
if !tt.wantErr {
|
||||
jsonRestHandler.EXPECT().PostSSZ(
|
||||
gomock.Any(),
|
||||
tt.expectedPath,
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
).Return(nil, nil, nil).Times(1)
|
||||
}
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
resp, err := validatorClient.proposeBeaconBlock(ctx, tt.block)
|
||||
|
||||
if tt.wantErr {
|
||||
require.ErrorContains(t, tt.errorMessage, err)
|
||||
assert.Equal(t, (*ethpb.ProposeResponse)(nil), resp)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBeaconApiValidatorClient_ProposeBeaconBlockHTTPErrors(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
sszError error
|
||||
expectJSON bool
|
||||
errorMessage string
|
||||
}{
|
||||
{
|
||||
name: "HTTP 202 Accepted - block broadcast but failed validation",
|
||||
sszError: &httputil.DefaultJsonError{
|
||||
Code: http.StatusAccepted,
|
||||
Message: "block broadcast but failed validation",
|
||||
},
|
||||
expectJSON: false, // No fallback for non-406 errors
|
||||
errorMessage: "failed to submit block ssz",
|
||||
},
|
||||
{
|
||||
name: "Other HTTP error",
|
||||
sszError: &httputil.DefaultJsonError{
|
||||
Code: http.StatusBadRequest,
|
||||
Message: "bad request",
|
||||
},
|
||||
expectJSON: false, // No fallback for non-406 errors
|
||||
errorMessage: "failed to submit block ssz",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
ctx := t.Context()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
jsonRestHandler.EXPECT().PostSSZ(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blocks",
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
).Return(nil, nil, tt.sszError).Times(1)
|
||||
|
||||
if tt.expectJSON {
|
||||
// When SSZ fails, it falls back to JSON
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blocks",
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
).Return(tt.sszError).Times(1)
|
||||
}
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
_, err := validatorClient.proposeBeaconBlock(
|
||||
ctx,
|
||||
ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedPhase0Block(),
|
||||
},
|
||||
)
|
||||
require.ErrorContains(t, tt.errorMessage, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBeaconApiValidatorClient_ProposeBeaconBlockJSONFallback(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
block *ethpb.GenericSignedBeaconBlock
|
||||
expectedPath string
|
||||
jsonError error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Phase0 block JSON fallback success",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedPhase0Block(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blocks",
|
||||
},
|
||||
{
|
||||
name: "Altair block JSON fallback success",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedAltairBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blocks",
|
||||
},
|
||||
{
|
||||
name: "Bellatrix block JSON fallback success",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedBellatrixBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blocks",
|
||||
},
|
||||
{
|
||||
name: "Capella block JSON fallback success",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedCapellaBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blocks",
|
||||
},
|
||||
{
|
||||
name: "Blinded Bellatrix block JSON fallback success",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedBlindedBellatrixBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blinded_blocks",
|
||||
},
|
||||
{
|
||||
name: "Blinded Capella block JSON fallback success",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedBlindedCapellaBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blinded_blocks",
|
||||
},
|
||||
{
|
||||
name: "Deneb block JSON fallback success",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedDenebBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blocks",
|
||||
},
|
||||
{
|
||||
name: "Blinded Deneb block JSON fallback success",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedBlindedDenebBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blinded_blocks",
|
||||
},
|
||||
{
|
||||
name: "Electra block JSON fallback success",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedElectraBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blocks",
|
||||
},
|
||||
{
|
||||
name: "Blinded Electra block JSON fallback success",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedBlindedElectraBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blinded_blocks",
|
||||
},
|
||||
{
|
||||
name: "Fulu block JSON fallback success",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedFuluBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blocks",
|
||||
},
|
||||
{
|
||||
name: "Blinded Fulu block JSON fallback success",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedBlindedFuluBlock(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blinded_blocks",
|
||||
},
|
||||
{
|
||||
name: "JSON fallback fails",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedPhase0Block(),
|
||||
},
|
||||
expectedPath: "/eth/v2/beacon/blocks",
|
||||
jsonError: errors.New("json post failed"),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
ctx := t.Context()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
// SSZ call fails with 406 to trigger JSON fallback
|
||||
jsonRestHandler.EXPECT().PostSSZ(
|
||||
gomock.Any(),
|
||||
tt.expectedPath,
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
).Return(nil, nil, &httputil.DefaultJsonError{
|
||||
Code: http.StatusNotAcceptable,
|
||||
Message: "SSZ not supported",
|
||||
}).Times(1)
|
||||
|
||||
// JSON fallback
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
tt.expectedPath,
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
).Return(tt.jsonError).Times(1)
|
||||
|
||||
validatorClient := beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
resp, err := validatorClient.proposeBeaconBlock(ctx, tt.block)
|
||||
|
||||
if tt.wantErr {
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, (*ethpb.ProposeResponse)(nil), resp)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBeaconApiValidatorClient_Host(t *testing.T) {
|
||||
@@ -229,3 +571,88 @@ func TestBeaconApiValidatorClient_Host(t *testing.T) {
|
||||
host = validatorClient.Host()
|
||||
require.Equal(t, hosts[1], host)
|
||||
}
|
||||
|
||||
// Helper functions for generating test blocks for newer consensus versions
|
||||
func generateSignedDenebBlock() *ethpb.GenericSignedBeaconBlock_Deneb {
|
||||
var blockContents structs.SignedBeaconBlockContentsDeneb
|
||||
if err := json.Unmarshal([]byte(rpctesting.DenebBlockContents), &blockContents); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
genericBlock, err := blockContents.ToGeneric()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ðpb.GenericSignedBeaconBlock_Deneb{
|
||||
Deneb: genericBlock.GetDeneb(),
|
||||
}
|
||||
}
|
||||
|
||||
func generateSignedBlindedDenebBlock() *ethpb.GenericSignedBeaconBlock_BlindedDeneb {
|
||||
var blindedBlock structs.SignedBlindedBeaconBlockDeneb
|
||||
if err := json.Unmarshal([]byte(rpctesting.BlindedDenebBlock), &blindedBlock); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
genericBlock, err := blindedBlock.ToGeneric()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ðpb.GenericSignedBeaconBlock_BlindedDeneb{
|
||||
BlindedDeneb: genericBlock.GetBlindedDeneb(),
|
||||
}
|
||||
}
|
||||
|
||||
func generateSignedElectraBlock() *ethpb.GenericSignedBeaconBlock_Electra {
|
||||
var blockContents structs.SignedBeaconBlockContentsElectra
|
||||
if err := json.Unmarshal([]byte(rpctesting.ElectraBlockContents), &blockContents); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
genericBlock, err := blockContents.ToGeneric()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ðpb.GenericSignedBeaconBlock_Electra{
|
||||
Electra: genericBlock.GetElectra(),
|
||||
}
|
||||
}
|
||||
|
||||
func generateSignedBlindedElectraBlock() *ethpb.GenericSignedBeaconBlock_BlindedElectra {
|
||||
var blindedBlock structs.SignedBlindedBeaconBlockElectra
|
||||
if err := json.Unmarshal([]byte(rpctesting.BlindedElectraBlock), &blindedBlock); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
genericBlock, err := blindedBlock.ToGeneric()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ðpb.GenericSignedBeaconBlock_BlindedElectra{
|
||||
BlindedElectra: genericBlock.GetBlindedElectra(),
|
||||
}
|
||||
}
|
||||
|
||||
func generateSignedFuluBlock() *ethpb.GenericSignedBeaconBlock_Fulu {
|
||||
var blockContents structs.SignedBeaconBlockContentsFulu
|
||||
if err := json.Unmarshal([]byte(rpctesting.FuluBlockContents), &blockContents); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
genericBlock, err := blockContents.ToGeneric()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ðpb.GenericSignedBeaconBlock_Fulu{
|
||||
Fulu: genericBlock.GetFulu(),
|
||||
}
|
||||
}
|
||||
|
||||
func generateSignedBlindedFuluBlock() *ethpb.GenericSignedBeaconBlock_BlindedFulu {
|
||||
var blindedBlock structs.SignedBlindedBeaconBlockFulu
|
||||
if err := json.Unmarshal([]byte(rpctesting.BlindedFuluBlock), &blindedBlock); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
genericBlock, err := blindedBlock.ToGeneric()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ðpb.GenericSignedBeaconBlock_BlindedFulu{
|
||||
BlindedFulu: genericBlock.GetBlindedFulu(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,22 @@ func (mr *MockJsonRestHandlerMockRecorder) Post(ctx, endpoint, headers, data, re
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Post", reflect.TypeOf((*MockJsonRestHandler)(nil).Post), ctx, endpoint, headers, data, resp)
|
||||
}
|
||||
|
||||
// Post mocks base method.
|
||||
func (m *MockJsonRestHandler) PostSSZ(ctx context.Context, endpoint string, headers map[string]string, data *bytes.Buffer) ([]byte, http.Header, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PostSSZ", ctx, endpoint, headers, data)
|
||||
ret0, _ := ret[0].([]byte)
|
||||
ret1, _ := ret[1].(http.Header)
|
||||
ret2, _ := ret[2].(error)
|
||||
return ret0,ret1,ret2
|
||||
}
|
||||
|
||||
// Post indicates an expected call of Post.
|
||||
func (mr *MockJsonRestHandlerMockRecorder) PostSSZ(ctx, endpoint, headers, data any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostSSZ", reflect.TypeOf((*MockJsonRestHandler)(nil).PostSSZ), ctx, endpoint, headers, data)
|
||||
}
|
||||
|
||||
// SetHost mocks base method.
|
||||
func (m *MockJsonRestHandler) SetHost(host string) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@@ -15,8 +15,10 @@ import (
|
||||
type blockProcessingResult struct {
|
||||
consensusVersion string
|
||||
beaconBlockRoot [32]byte
|
||||
marshalledJSON []byte
|
||||
marshalledSSZ []byte
|
||||
blinded bool
|
||||
// Function to marshal JSON on demand
|
||||
marshalJSON func() ([]byte, error)
|
||||
}
|
||||
|
||||
func (c *beaconApiValidatorClient) proposeBeaconBlock(ctx context.Context, in *ethpb.GenericSignedBeaconBlock) (*ethpb.ProposeResponse, error) {
|
||||
@@ -62,17 +64,54 @@ func (c *beaconApiValidatorClient) proposeBeaconBlock(ctx context.Context, in *e
|
||||
}
|
||||
|
||||
headers := map[string]string{"Eth-Consensus-Version": res.consensusVersion}
|
||||
err = c.jsonRestHandler.Post(ctx, endpoint, headers, bytes.NewBuffer(res.marshalledJSON), nil)
|
||||
errJson := &httputil.DefaultJsonError{}
|
||||
if err != nil {
|
||||
if !errors.As(err, &errJson) {
|
||||
return nil, err
|
||||
|
||||
// Try PostSSZ first with SSZ data
|
||||
if res.marshalledSSZ != nil {
|
||||
_, _, err = c.jsonRestHandler.PostSSZ(ctx, endpoint, headers, bytes.NewBuffer(res.marshalledSSZ))
|
||||
if err != nil {
|
||||
errJson := &httputil.DefaultJsonError{}
|
||||
// If PostSSZ fails with 406 (Not Acceptable), fall back to JSON
|
||||
if !errors.As(err, &errJson) {
|
||||
return nil, err
|
||||
}
|
||||
if errJson.Code == http.StatusNotAcceptable && res.marshalJSON != nil {
|
||||
log.WithError(err).Warn("Failed to submit block ssz, falling back to JSON")
|
||||
jsonData, jsonErr := res.marshalJSON()
|
||||
if jsonErr != nil {
|
||||
return nil, errors.Wrap(jsonErr, "failed to marshal JSON")
|
||||
}
|
||||
// Reset headers for JSON
|
||||
err = c.jsonRestHandler.Post(ctx, endpoint, headers, bytes.NewBuffer(jsonData), nil)
|
||||
// If JSON also fails, return that error
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to submit block via JSON fallback")
|
||||
}
|
||||
} else {
|
||||
// For non-406 errors or when no JSON fallback is available, return the SSZ error
|
||||
return nil, errors.Wrap(errJson, "failed to submit block ssz")
|
||||
}
|
||||
}
|
||||
// Error 202 means that the block was successfully broadcast, but validation failed
|
||||
if errJson.Code == http.StatusAccepted {
|
||||
return nil, errors.New("block was successfully broadcast but failed validation")
|
||||
} else if res.marshalJSON == nil {
|
||||
return nil, errors.New("no marshalling functions available")
|
||||
} else {
|
||||
// No SSZ data available, marshal and use JSON
|
||||
jsonData, jsonErr := res.marshalJSON()
|
||||
if jsonErr != nil {
|
||||
return nil, errors.Wrap(jsonErr, "failed to marshal JSON")
|
||||
}
|
||||
// Reset headers for JSON
|
||||
err = c.jsonRestHandler.Post(ctx, endpoint, headers, bytes.NewBuffer(jsonData), nil)
|
||||
errJson := &httputil.DefaultJsonError{}
|
||||
if err != nil {
|
||||
if !errors.As(err, &errJson) {
|
||||
return nil, err
|
||||
}
|
||||
// Error 202 means that the block was successfully broadcast, but validation failed
|
||||
if errJson.Code == http.StatusAccepted {
|
||||
return nil, errors.New("block was successfully broadcast but failed validation")
|
||||
}
|
||||
return nil, errJson
|
||||
}
|
||||
return nil, errJson
|
||||
}
|
||||
|
||||
return ðpb.ProposeResponse{BlockRoot: res.beaconBlockRoot[:]}, nil
|
||||
@@ -89,11 +128,19 @@ func handlePhase0Block(block *ethpb.GenericSignedBeaconBlock_Phase0) (*blockProc
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
signedBlock := structs.SignedBeaconBlockPhase0FromConsensus(block.Phase0)
|
||||
res.marshalledJSON, err = json.Marshal(signedBlock)
|
||||
// Marshal SSZ
|
||||
ssz, err := block.Phase0.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall phase0 beacon block to json")
|
||||
return nil, errors.Wrap(err, "failed to serialize block for phase0 beacon block")
|
||||
}
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock := structs.SignedBeaconBlockPhase0FromConsensus(block.Phase0)
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
@@ -108,11 +155,19 @@ func handleAltairBlock(block *ethpb.GenericSignedBeaconBlock_Altair) (*blockProc
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
signedBlock := structs.SignedBeaconBlockAltairFromConsensus(block.Altair)
|
||||
res.marshalledJSON, err = json.Marshal(signedBlock)
|
||||
// Marshal SSZ
|
||||
ssz, err := block.Altair.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall altair beacon block to json")
|
||||
return nil, errors.Wrap(err, "failed to serialize block for altair beacon block")
|
||||
}
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock := structs.SignedBeaconBlockAltairFromConsensus(block.Altair)
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
@@ -127,13 +182,20 @@ func handleBellatrixBlock(block *ethpb.GenericSignedBeaconBlock_Bellatrix) (*blo
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
signedBlock, err := structs.SignedBeaconBlockBellatrixFromConsensus(block.Bellatrix)
|
||||
// Marshal SSZ
|
||||
ssz, err := block.Bellatrix.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall bellatrix beacon block")
|
||||
return nil, errors.Wrap(err, "failed to serialize block for bellatrix beacon block")
|
||||
}
|
||||
res.marshalledJSON, err = json.Marshal(signedBlock)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall bellatrix beacon block to json")
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBeaconBlockBellatrixFromConsensus(block.Bellatrix)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert bellatrix beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
@@ -150,13 +212,20 @@ func handleBlindedBellatrixBlock(block *ethpb.GenericSignedBeaconBlock_BlindedBe
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockBellatrixFromConsensus(block.BlindedBellatrix)
|
||||
// Marshal SSZ
|
||||
ssz, err := block.BlindedBellatrix.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall blinded bellatrix beacon block")
|
||||
return nil, errors.Wrap(err, "failed to serialize block for bellatrix beacon block")
|
||||
}
|
||||
res.marshalledJSON, err = json.Marshal(signedBlock)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall blinded bellatrix beacon block to json")
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockBellatrixFromConsensus(block.BlindedBellatrix)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert blinded bellatrix beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
@@ -173,13 +242,20 @@ func handleCapellaBlock(block *ethpb.GenericSignedBeaconBlock_Capella) (*blockPr
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
signedBlock, err := structs.SignedBeaconBlockCapellaFromConsensus(block.Capella)
|
||||
// Marshal SSZ
|
||||
ssz, err := block.Capella.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall capella beacon block")
|
||||
return nil, errors.Wrap(err, "failed to serialize capella beacon block")
|
||||
}
|
||||
res.marshalledJSON, err = json.Marshal(signedBlock)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall capella beacon block to json")
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBeaconBlockCapellaFromConsensus(block.Capella)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert capella beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
@@ -196,13 +272,20 @@ func handleBlindedCapellaBlock(block *ethpb.GenericSignedBeaconBlock_BlindedCape
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockCapellaFromConsensus(block.BlindedCapella)
|
||||
// Marshal SSZ
|
||||
ssz, err := block.BlindedCapella.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall blinded capella beacon block")
|
||||
return nil, errors.Wrap(err, "failed to serialize blinded capella beacon block")
|
||||
}
|
||||
res.marshalledJSON, err = json.Marshal(signedBlock)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall blinded capella beacon block to json")
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockCapellaFromConsensus(block.BlindedCapella)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert blinded capella beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
@@ -219,13 +302,20 @@ func handleDenebBlockContents(block *ethpb.GenericSignedBeaconBlock_Deneb) (*blo
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
signedBlock, err := structs.SignedBeaconBlockContentsDenebFromConsensus(block.Deneb)
|
||||
// Marshal SSZ
|
||||
ssz, err := block.Deneb.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall deneb beacon block contents")
|
||||
return nil, errors.Wrap(err, "failed to serialize deneb beacon block")
|
||||
}
|
||||
res.marshalledJSON, err = json.Marshal(signedBlock)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall deneb beacon block contents to json")
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBeaconBlockContentsDenebFromConsensus(block.Deneb)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert deneb beacon block contents")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
@@ -242,13 +332,20 @@ func handleBlindedDenebBlock(block *ethpb.GenericSignedBeaconBlock_BlindedDeneb)
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockDenebFromConsensus(block.BlindedDeneb)
|
||||
// Marshal SSZ
|
||||
ssz, err := block.BlindedDeneb.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall deneb blinded beacon block ")
|
||||
return nil, errors.Wrap(err, "failed to serialize blinded deneb beacon block")
|
||||
}
|
||||
res.marshalledJSON, err = json.Marshal(signedBlock)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall deneb blinded beacon block to json")
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockDenebFromConsensus(block.BlindedDeneb)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert deneb blinded beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
@@ -265,13 +362,20 @@ func handleElectraBlockContents(block *ethpb.GenericSignedBeaconBlock_Electra) (
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
signedBlock, err := structs.SignedBeaconBlockContentsElectraFromConsensus(block.Electra)
|
||||
// Marshal SSZ
|
||||
ssz, err := block.Electra.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall electra beacon block contents")
|
||||
return nil, errors.Wrap(err, "failed to serialize electra beacon block")
|
||||
}
|
||||
res.marshalledJSON, err = json.Marshal(signedBlock)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall electra beacon block contents to json")
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBeaconBlockContentsElectraFromConsensus(block.Electra)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert electra beacon block contents")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
@@ -288,13 +392,20 @@ func handleBlindedElectraBlock(block *ethpb.GenericSignedBeaconBlock_BlindedElec
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockElectraFromConsensus(block.BlindedElectra)
|
||||
// Marshal SSZ
|
||||
ssz, err := block.BlindedElectra.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall electra blinded beacon block")
|
||||
return nil, errors.Wrap(err, "failed to serialize blinded electra beacon block")
|
||||
}
|
||||
res.marshalledJSON, err = json.Marshal(signedBlock)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall electra blinded beacon block to json")
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockElectraFromConsensus(block.BlindedElectra)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert electra blinded beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
@@ -311,13 +422,20 @@ func handleFuluBlockContents(block *ethpb.GenericSignedBeaconBlock_Fulu) (*block
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
signedBlock, err := structs.SignedBeaconBlockContentsFuluFromConsensus(block.Fulu)
|
||||
// Marshal SSZ
|
||||
ssz, err := block.Fulu.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall fulu beacon block contents")
|
||||
return nil, errors.Wrap(err, "failed to serialize fulu beacon block")
|
||||
}
|
||||
res.marshalledJSON, err = json.Marshal(signedBlock)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall fulu beacon block contents to json")
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBeaconBlockContentsFuluFromConsensus(block.Fulu)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert fulu beacon block contents")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
@@ -334,13 +452,20 @@ func handleBlindedFuluBlock(block *ethpb.GenericSignedBeaconBlock_BlindedFulu) (
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockFuluFromConsensus(block.BlindedFulu)
|
||||
// Marshal SSZ
|
||||
ssz, err := block.BlindedFulu.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall fulu blinded beacon block")
|
||||
return nil, errors.Wrap(err, "failed to serialize blinded fulu beacon block")
|
||||
}
|
||||
res.marshalledJSON, err = json.Marshal(signedBlock)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to marshall fulu blinded beacon block to json")
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockFuluFromConsensus(block.BlindedFulu)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert fulu blinded beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/mock"
|
||||
testhelpers "github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/test-helpers"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestProposeBeaconBlock_Altair(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
altairBlock := generateSignedAltairBlock()
|
||||
|
||||
genericSignedBlock := ðpb.GenericSignedBeaconBlock{}
|
||||
genericSignedBlock.Block = altairBlock
|
||||
|
||||
jsonAltairBlock := structs.SignedBeaconBlockAltairFromConsensus(altairBlock.Altair)
|
||||
|
||||
marshalledBlock, err := json.Marshal(jsonAltairBlock)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := t.Context()
|
||||
|
||||
// Make sure that what we send in the POST body is the marshalled version of the protobuf block
|
||||
headers := map[string]string{"Eth-Consensus-Version": "altair"}
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blocks",
|
||||
headers,
|
||||
bytes.NewBuffer(marshalledBlock),
|
||||
nil,
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(ctx, genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := altairBlock.Altair.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure that the block root is set
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
}
|
||||
|
||||
func generateSignedAltairBlock() *ethpb.GenericSignedBeaconBlock_Altair {
|
||||
return ðpb.GenericSignedBeaconBlock_Altair{
|
||||
Altair: ðpb.SignedBeaconBlockAltair{
|
||||
Block: testhelpers.GenerateProtoAltairBeaconBlock(),
|
||||
Signature: testhelpers.FillByteSlice(96, 112),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/mock"
|
||||
testhelpers "github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/test-helpers"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestProposeBeaconBlock_Bellatrix(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
bellatrixBlock := generateSignedBellatrixBlock()
|
||||
|
||||
genericSignedBlock := ðpb.GenericSignedBeaconBlock{}
|
||||
genericSignedBlock.Block = bellatrixBlock
|
||||
|
||||
jsonBellatrixBlock, err := structs.SignedBeaconBlockBellatrixFromConsensus(bellatrixBlock.Bellatrix)
|
||||
require.NoError(t, err)
|
||||
|
||||
marshalledBlock, err := json.Marshal(jsonBellatrixBlock)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := t.Context()
|
||||
|
||||
// Make sure that what we send in the POST body is the marshalled version of the protobuf block
|
||||
headers := map[string]string{"Eth-Consensus-Version": "bellatrix"}
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blocks",
|
||||
headers,
|
||||
bytes.NewBuffer(marshalledBlock),
|
||||
nil,
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(ctx, genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := bellatrixBlock.Bellatrix.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure that the block root is set
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
}
|
||||
|
||||
func generateSignedBellatrixBlock() *ethpb.GenericSignedBeaconBlock_Bellatrix {
|
||||
return ðpb.GenericSignedBeaconBlock_Bellatrix{
|
||||
Bellatrix: ðpb.SignedBeaconBlockBellatrix{
|
||||
Block: testhelpers.GenerateProtoBellatrixBeaconBlock(),
|
||||
Signature: testhelpers.FillByteSlice(96, 127),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,291 +0,0 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/mock"
|
||||
testhelpers "github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/test-helpers"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestProposeBeaconBlock_BlindedBellatrix(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
blindedBellatrixBlock := generateSignedBlindedBellatrixBlock()
|
||||
|
||||
genericSignedBlock := ðpb.GenericSignedBeaconBlock{}
|
||||
genericSignedBlock.Block = blindedBellatrixBlock
|
||||
|
||||
jsonBlindedBellatrixBlock, err := structs.SignedBlindedBeaconBlockBellatrixFromConsensus(blindedBellatrixBlock.BlindedBellatrix)
|
||||
require.NoError(t, err)
|
||||
|
||||
marshalledBlock, err := json.Marshal(jsonBlindedBellatrixBlock)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := t.Context()
|
||||
|
||||
// Make sure that what we send in the POST body is the marshalled version of the protobuf block
|
||||
headers := map[string]string{"Eth-Consensus-Version": "bellatrix"}
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blinded_blocks",
|
||||
headers,
|
||||
bytes.NewBuffer(marshalledBlock),
|
||||
nil,
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(ctx, genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := blindedBellatrixBlock.BlindedBellatrix.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure that the block root is set
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
}
|
||||
|
||||
func generateSignedBlindedBellatrixBlock() *ethpb.GenericSignedBeaconBlock_BlindedBellatrix {
|
||||
return ðpb.GenericSignedBeaconBlock_BlindedBellatrix{
|
||||
BlindedBellatrix: ðpb.SignedBlindedBeaconBlockBellatrix{
|
||||
Block: ðpb.BlindedBeaconBlockBellatrix{
|
||||
Slot: 1,
|
||||
ProposerIndex: 2,
|
||||
ParentRoot: testhelpers.FillByteSlice(32, 3),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 4),
|
||||
Body: ðpb.BlindedBeaconBlockBodyBellatrix{
|
||||
RandaoReveal: testhelpers.FillByteSlice(96, 5),
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: testhelpers.FillByteSlice(32, 6),
|
||||
DepositCount: 7,
|
||||
BlockHash: testhelpers.FillByteSlice(32, 8),
|
||||
},
|
||||
Graffiti: testhelpers.FillByteSlice(32, 9),
|
||||
ProposerSlashings: []*ethpb.ProposerSlashing{
|
||||
{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 10,
|
||||
ProposerIndex: 11,
|
||||
ParentRoot: testhelpers.FillByteSlice(32, 12),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 13),
|
||||
BodyRoot: testhelpers.FillByteSlice(32, 14),
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 15),
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 16,
|
||||
ProposerIndex: 17,
|
||||
ParentRoot: testhelpers.FillByteSlice(32, 18),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 19),
|
||||
BodyRoot: testhelpers.FillByteSlice(32, 20),
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 21),
|
||||
},
|
||||
},
|
||||
{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 22,
|
||||
ProposerIndex: 23,
|
||||
ParentRoot: testhelpers.FillByteSlice(32, 24),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 25),
|
||||
BodyRoot: testhelpers.FillByteSlice(32, 26),
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 27),
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 28,
|
||||
ProposerIndex: 29,
|
||||
ParentRoot: testhelpers.FillByteSlice(32, 30),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 31),
|
||||
BodyRoot: testhelpers.FillByteSlice(32, 32),
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 33),
|
||||
},
|
||||
},
|
||||
},
|
||||
AttesterSlashings: []*ethpb.AttesterSlashing{
|
||||
{
|
||||
Attestation_1: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{34, 35},
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 36,
|
||||
CommitteeIndex: 37,
|
||||
BeaconBlockRoot: testhelpers.FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 39,
|
||||
Root: testhelpers.FillByteSlice(32, 40),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 41,
|
||||
Root: testhelpers.FillByteSlice(32, 42),
|
||||
},
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 43),
|
||||
},
|
||||
Attestation_2: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{44, 45},
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 46,
|
||||
CommitteeIndex: 47,
|
||||
BeaconBlockRoot: testhelpers.FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 49,
|
||||
Root: testhelpers.FillByteSlice(32, 50),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 51,
|
||||
Root: testhelpers.FillByteSlice(32, 52),
|
||||
},
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 53),
|
||||
},
|
||||
},
|
||||
{
|
||||
Attestation_1: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{54, 55},
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 56,
|
||||
CommitteeIndex: 57,
|
||||
BeaconBlockRoot: testhelpers.FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 59,
|
||||
Root: testhelpers.FillByteSlice(32, 60),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 61,
|
||||
Root: testhelpers.FillByteSlice(32, 62),
|
||||
},
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 63),
|
||||
},
|
||||
Attestation_2: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{64, 65},
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 66,
|
||||
CommitteeIndex: 67,
|
||||
BeaconBlockRoot: testhelpers.FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 69,
|
||||
Root: testhelpers.FillByteSlice(32, 70),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 71,
|
||||
Root: testhelpers.FillByteSlice(32, 72),
|
||||
},
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 73),
|
||||
},
|
||||
},
|
||||
},
|
||||
Attestations: []*ethpb.Attestation{
|
||||
{
|
||||
AggregationBits: testhelpers.FillByteSlice(4, 74),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 75,
|
||||
CommitteeIndex: 76,
|
||||
BeaconBlockRoot: testhelpers.FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 78,
|
||||
Root: testhelpers.FillByteSlice(32, 79),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 80,
|
||||
Root: testhelpers.FillByteSlice(32, 81),
|
||||
},
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 82),
|
||||
},
|
||||
{
|
||||
AggregationBits: testhelpers.FillByteSlice(4, 83),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 84,
|
||||
CommitteeIndex: 85,
|
||||
BeaconBlockRoot: testhelpers.FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 87,
|
||||
Root: testhelpers.FillByteSlice(32, 88),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 89,
|
||||
Root: testhelpers.FillByteSlice(32, 90),
|
||||
},
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 91),
|
||||
},
|
||||
},
|
||||
Deposits: []*ethpb.Deposit{
|
||||
{
|
||||
Proof: testhelpers.FillByteArraySlice(33, testhelpers.FillByteSlice(32, 92)),
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: testhelpers.FillByteSlice(48, 94),
|
||||
WithdrawalCredentials: testhelpers.FillByteSlice(32, 95),
|
||||
Amount: 96,
|
||||
Signature: testhelpers.FillByteSlice(96, 97),
|
||||
},
|
||||
},
|
||||
{
|
||||
Proof: testhelpers.FillByteArraySlice(33, testhelpers.FillByteSlice(32, 98)),
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: testhelpers.FillByteSlice(48, 100),
|
||||
WithdrawalCredentials: testhelpers.FillByteSlice(32, 101),
|
||||
Amount: 102,
|
||||
Signature: testhelpers.FillByteSlice(96, 103),
|
||||
},
|
||||
},
|
||||
},
|
||||
VoluntaryExits: []*ethpb.SignedVoluntaryExit{
|
||||
{
|
||||
Exit: ðpb.VoluntaryExit{
|
||||
Epoch: 104,
|
||||
ValidatorIndex: 105,
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 106),
|
||||
},
|
||||
{
|
||||
Exit: ðpb.VoluntaryExit{
|
||||
Epoch: 107,
|
||||
ValidatorIndex: 108,
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 109),
|
||||
},
|
||||
},
|
||||
SyncAggregate: ðpb.SyncAggregate{
|
||||
SyncCommitteeBits: testhelpers.FillByteSlice(64, 110),
|
||||
SyncCommitteeSignature: testhelpers.FillByteSlice(96, 111),
|
||||
},
|
||||
ExecutionPayloadHeader: &enginev1.ExecutionPayloadHeader{
|
||||
ParentHash: testhelpers.FillByteSlice(32, 112),
|
||||
FeeRecipient: testhelpers.FillByteSlice(20, 113),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 114),
|
||||
ReceiptsRoot: testhelpers.FillByteSlice(32, 115),
|
||||
LogsBloom: testhelpers.FillByteSlice(256, 116),
|
||||
PrevRandao: testhelpers.FillByteSlice(32, 117),
|
||||
BlockNumber: 118,
|
||||
GasLimit: 119,
|
||||
GasUsed: 120,
|
||||
Timestamp: 121,
|
||||
ExtraData: testhelpers.FillByteSlice(32, 122),
|
||||
BaseFeePerGas: testhelpers.FillByteSlice(32, 123),
|
||||
BlockHash: testhelpers.FillByteSlice(32, 124),
|
||||
TransactionsRoot: testhelpers.FillByteSlice(32, 125),
|
||||
},
|
||||
},
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 126),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,310 +0,0 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/mock"
|
||||
testhelpers "github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/test-helpers"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestProposeBeaconBlock_BlindedCapella(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
blindedCapellaBlock := generateSignedBlindedCapellaBlock()
|
||||
|
||||
genericSignedBlock := ðpb.GenericSignedBeaconBlock{}
|
||||
genericSignedBlock.Block = blindedCapellaBlock
|
||||
|
||||
jsonBlindedCapellaBlock, err := structs.SignedBlindedBeaconBlockCapellaFromConsensus(blindedCapellaBlock.BlindedCapella)
|
||||
require.NoError(t, err)
|
||||
|
||||
marshalledBlock, err := json.Marshal(jsonBlindedCapellaBlock)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := t.Context()
|
||||
|
||||
// Make sure that what we send in the POST body is the marshalled version of the protobuf block
|
||||
headers := map[string]string{"Eth-Consensus-Version": "capella"}
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blinded_blocks",
|
||||
headers,
|
||||
bytes.NewBuffer(marshalledBlock),
|
||||
nil,
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(ctx, genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := blindedCapellaBlock.BlindedCapella.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure that the block root is set
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
}
|
||||
|
||||
func generateSignedBlindedCapellaBlock() *ethpb.GenericSignedBeaconBlock_BlindedCapella {
|
||||
return ðpb.GenericSignedBeaconBlock_BlindedCapella{
|
||||
BlindedCapella: ðpb.SignedBlindedBeaconBlockCapella{
|
||||
Block: ðpb.BlindedBeaconBlockCapella{
|
||||
Slot: 1,
|
||||
ProposerIndex: 2,
|
||||
ParentRoot: testhelpers.FillByteSlice(32, 3),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 4),
|
||||
Body: ðpb.BlindedBeaconBlockBodyCapella{
|
||||
RandaoReveal: testhelpers.FillByteSlice(96, 5),
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: testhelpers.FillByteSlice(32, 6),
|
||||
DepositCount: 7,
|
||||
BlockHash: testhelpers.FillByteSlice(32, 8),
|
||||
},
|
||||
Graffiti: testhelpers.FillByteSlice(32, 9),
|
||||
ProposerSlashings: []*ethpb.ProposerSlashing{
|
||||
{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 10,
|
||||
ProposerIndex: 11,
|
||||
ParentRoot: testhelpers.FillByteSlice(32, 12),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 13),
|
||||
BodyRoot: testhelpers.FillByteSlice(32, 14),
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 15),
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 16,
|
||||
ProposerIndex: 17,
|
||||
ParentRoot: testhelpers.FillByteSlice(32, 18),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 19),
|
||||
BodyRoot: testhelpers.FillByteSlice(32, 20),
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 21),
|
||||
},
|
||||
},
|
||||
{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 22,
|
||||
ProposerIndex: 23,
|
||||
ParentRoot: testhelpers.FillByteSlice(32, 24),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 25),
|
||||
BodyRoot: testhelpers.FillByteSlice(32, 26),
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 27),
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 28,
|
||||
ProposerIndex: 29,
|
||||
ParentRoot: testhelpers.FillByteSlice(32, 30),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 31),
|
||||
BodyRoot: testhelpers.FillByteSlice(32, 32),
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 33),
|
||||
},
|
||||
},
|
||||
},
|
||||
AttesterSlashings: []*ethpb.AttesterSlashing{
|
||||
{
|
||||
Attestation_1: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{34, 35},
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 36,
|
||||
CommitteeIndex: 37,
|
||||
BeaconBlockRoot: testhelpers.FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 39,
|
||||
Root: testhelpers.FillByteSlice(32, 40),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 41,
|
||||
Root: testhelpers.FillByteSlice(32, 42),
|
||||
},
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 43),
|
||||
},
|
||||
Attestation_2: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{44, 45},
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 46,
|
||||
CommitteeIndex: 47,
|
||||
BeaconBlockRoot: testhelpers.FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 49,
|
||||
Root: testhelpers.FillByteSlice(32, 50),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 51,
|
||||
Root: testhelpers.FillByteSlice(32, 52),
|
||||
},
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 53),
|
||||
},
|
||||
},
|
||||
{
|
||||
Attestation_1: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{54, 55},
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 56,
|
||||
CommitteeIndex: 57,
|
||||
BeaconBlockRoot: testhelpers.FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 59,
|
||||
Root: testhelpers.FillByteSlice(32, 60),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 61,
|
||||
Root: testhelpers.FillByteSlice(32, 62),
|
||||
},
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 63),
|
||||
},
|
||||
Attestation_2: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{64, 65},
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 66,
|
||||
CommitteeIndex: 67,
|
||||
BeaconBlockRoot: testhelpers.FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 69,
|
||||
Root: testhelpers.FillByteSlice(32, 70),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 71,
|
||||
Root: testhelpers.FillByteSlice(32, 72),
|
||||
},
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 73),
|
||||
},
|
||||
},
|
||||
},
|
||||
Attestations: []*ethpb.Attestation{
|
||||
{
|
||||
AggregationBits: testhelpers.FillByteSlice(4, 74),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 75,
|
||||
CommitteeIndex: 76,
|
||||
BeaconBlockRoot: testhelpers.FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 78,
|
||||
Root: testhelpers.FillByteSlice(32, 79),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 80,
|
||||
Root: testhelpers.FillByteSlice(32, 81),
|
||||
},
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 82),
|
||||
},
|
||||
{
|
||||
AggregationBits: testhelpers.FillByteSlice(4, 83),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 84,
|
||||
CommitteeIndex: 85,
|
||||
BeaconBlockRoot: testhelpers.FillByteSlice(32, 38),
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 87,
|
||||
Root: testhelpers.FillByteSlice(32, 88),
|
||||
},
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: 89,
|
||||
Root: testhelpers.FillByteSlice(32, 90),
|
||||
},
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 91),
|
||||
},
|
||||
},
|
||||
Deposits: []*ethpb.Deposit{
|
||||
{
|
||||
Proof: testhelpers.FillByteArraySlice(33, testhelpers.FillByteSlice(32, 92)),
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: testhelpers.FillByteSlice(48, 94),
|
||||
WithdrawalCredentials: testhelpers.FillByteSlice(32, 95),
|
||||
Amount: 96,
|
||||
Signature: testhelpers.FillByteSlice(96, 97),
|
||||
},
|
||||
},
|
||||
{
|
||||
Proof: testhelpers.FillByteArraySlice(33, testhelpers.FillByteSlice(32, 98)),
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: testhelpers.FillByteSlice(48, 100),
|
||||
WithdrawalCredentials: testhelpers.FillByteSlice(32, 101),
|
||||
Amount: 102,
|
||||
Signature: testhelpers.FillByteSlice(96, 103),
|
||||
},
|
||||
},
|
||||
},
|
||||
VoluntaryExits: []*ethpb.SignedVoluntaryExit{
|
||||
{
|
||||
Exit: ðpb.VoluntaryExit{
|
||||
Epoch: 104,
|
||||
ValidatorIndex: 105,
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 106),
|
||||
},
|
||||
{
|
||||
Exit: ðpb.VoluntaryExit{
|
||||
Epoch: 107,
|
||||
ValidatorIndex: 108,
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 109),
|
||||
},
|
||||
},
|
||||
SyncAggregate: ðpb.SyncAggregate{
|
||||
SyncCommitteeBits: testhelpers.FillByteSlice(64, 110),
|
||||
SyncCommitteeSignature: testhelpers.FillByteSlice(96, 111),
|
||||
},
|
||||
ExecutionPayloadHeader: &enginev1.ExecutionPayloadHeaderCapella{
|
||||
ParentHash: testhelpers.FillByteSlice(32, 112),
|
||||
FeeRecipient: testhelpers.FillByteSlice(20, 113),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 114),
|
||||
ReceiptsRoot: testhelpers.FillByteSlice(32, 115),
|
||||
LogsBloom: testhelpers.FillByteSlice(256, 116),
|
||||
PrevRandao: testhelpers.FillByteSlice(32, 117),
|
||||
BlockNumber: 118,
|
||||
GasLimit: 119,
|
||||
GasUsed: 120,
|
||||
Timestamp: 121,
|
||||
ExtraData: testhelpers.FillByteSlice(32, 122),
|
||||
BaseFeePerGas: testhelpers.FillByteSlice(32, 123),
|
||||
BlockHash: testhelpers.FillByteSlice(32, 124),
|
||||
TransactionsRoot: testhelpers.FillByteSlice(32, 125),
|
||||
WithdrawalsRoot: testhelpers.FillByteSlice(32, 126),
|
||||
},
|
||||
BlsToExecutionChanges: []*ethpb.SignedBLSToExecutionChange{
|
||||
{
|
||||
Message: ðpb.BLSToExecutionChange{
|
||||
ValidatorIndex: 127,
|
||||
FromBlsPubkey: testhelpers.FillByteSlice(48, 128),
|
||||
ToExecutionAddress: testhelpers.FillByteSlice(20, 129),
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 130),
|
||||
},
|
||||
{
|
||||
Message: ðpb.BLSToExecutionChange{
|
||||
ValidatorIndex: 131,
|
||||
FromBlsPubkey: testhelpers.FillByteSlice(48, 132),
|
||||
ToExecutionAddress: testhelpers.FillByteSlice(20, 133),
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 134),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 135),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||
rpctesting "github.com/OffchainLabs/prysm/v6/beacon-chain/rpc/eth/shared/testing"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/mock"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestProposeBeaconBlock_BlindedDeneb(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
var block structs.SignedBlindedBeaconBlockDeneb
|
||||
err := json.Unmarshal([]byte(rpctesting.BlindedDenebBlock), &block)
|
||||
require.NoError(t, err)
|
||||
genericSignedBlock, err := block.ToGeneric()
|
||||
require.NoError(t, err)
|
||||
|
||||
denebBytes, err := json.Marshal(block)
|
||||
require.NoError(t, err)
|
||||
// Make sure that what we send in the POST body is the marshalled version of the protobuf block
|
||||
headers := map[string]string{"Eth-Consensus-Version": "deneb"}
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blinded_blocks",
|
||||
headers,
|
||||
bytes.NewBuffer(denebBytes),
|
||||
nil,
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(t.Context(), genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := genericSignedBlock.GetBlindedDeneb().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure that the block root is set
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||
rpctesting "github.com/OffchainLabs/prysm/v6/beacon-chain/rpc/eth/shared/testing"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/mock"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestProposeBeaconBlock_BlindedElectra(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
var block structs.SignedBlindedBeaconBlockElectra
|
||||
err := json.Unmarshal([]byte(rpctesting.BlindedElectraBlock), &block)
|
||||
require.NoError(t, err)
|
||||
genericSignedBlock, err := block.ToGeneric()
|
||||
require.NoError(t, err)
|
||||
|
||||
electraBytes, err := json.Marshal(block)
|
||||
require.NoError(t, err)
|
||||
// Make sure that what we send in the POST body is the marshalled version of the protobuf block
|
||||
headers := map[string]string{"Eth-Consensus-Version": "electra"}
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blinded_blocks",
|
||||
headers,
|
||||
bytes.NewBuffer(electraBytes),
|
||||
nil,
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(t.Context(), genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := genericSignedBlock.GetBlindedElectra().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure that the block root is set
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||
rpctesting "github.com/OffchainLabs/prysm/v6/beacon-chain/rpc/eth/shared/testing"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/mock"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestProposeBeaconBlock_BlindedFulu(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
var block structs.SignedBlindedBeaconBlockFulu
|
||||
err := json.Unmarshal([]byte(rpctesting.BlindedFuluBlock), &block)
|
||||
require.NoError(t, err)
|
||||
genericSignedBlock, err := block.ToGeneric()
|
||||
require.NoError(t, err)
|
||||
|
||||
fuluBytes, err := json.Marshal(block)
|
||||
require.NoError(t, err)
|
||||
// Make sure that what we send in the POST body is the marshalled version of the protobuf block
|
||||
headers := map[string]string{"Eth-Consensus-Version": "fulu"}
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blinded_blocks",
|
||||
headers,
|
||||
bytes.NewBuffer(fuluBytes),
|
||||
nil,
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(t.Context(), genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := genericSignedBlock.GetBlindedFulu().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure that the block root is set
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/mock"
|
||||
testhelpers "github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/test-helpers"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestProposeBeaconBlock_Capella(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
capellaBlock := generateSignedCapellaBlock()
|
||||
|
||||
genericSignedBlock := ðpb.GenericSignedBeaconBlock{}
|
||||
genericSignedBlock.Block = capellaBlock
|
||||
|
||||
jsonCapellaBlock, err := structs.SignedBeaconBlockCapellaFromConsensus(capellaBlock.Capella)
|
||||
require.NoError(t, err)
|
||||
|
||||
marshalledBlock, err := json.Marshal(jsonCapellaBlock)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure that what we send in the POST body is the marshalled version of the protobuf block
|
||||
headers := map[string]string{"Eth-Consensus-Version": "capella"}
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blocks",
|
||||
headers,
|
||||
bytes.NewBuffer(marshalledBlock),
|
||||
nil,
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(t.Context(), genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := capellaBlock.Capella.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure that the block root is set
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
}
|
||||
|
||||
func generateSignedCapellaBlock() *ethpb.GenericSignedBeaconBlock_Capella {
|
||||
return ðpb.GenericSignedBeaconBlock_Capella{
|
||||
Capella: ðpb.SignedBeaconBlockCapella{
|
||||
Block: testhelpers.GenerateProtoCapellaBeaconBlock(),
|
||||
Signature: testhelpers.FillByteSlice(96, 127),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||
rpctesting "github.com/OffchainLabs/prysm/v6/beacon-chain/rpc/eth/shared/testing"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/mock"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestProposeBeaconBlock_Deneb(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
var blockContents structs.SignedBeaconBlockContentsDeneb
|
||||
err := json.Unmarshal([]byte(rpctesting.DenebBlockContents), &blockContents)
|
||||
require.NoError(t, err)
|
||||
genericSignedBlock, err := blockContents.ToGeneric()
|
||||
require.NoError(t, err)
|
||||
|
||||
denebBytes, err := json.Marshal(blockContents)
|
||||
require.NoError(t, err)
|
||||
// Make sure that what we send in the POST body is the marshalled version of the protobuf block
|
||||
headers := map[string]string{"Eth-Consensus-Version": "deneb"}
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blocks",
|
||||
headers,
|
||||
bytes.NewBuffer(denebBytes),
|
||||
nil,
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(t.Context(), genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := genericSignedBlock.GetDeneb().Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure that the block root is set
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||
rpctesting "github.com/OffchainLabs/prysm/v6/beacon-chain/rpc/eth/shared/testing"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/mock"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestProposeBeaconBlock_Electra(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
var blockContents structs.SignedBeaconBlockContentsElectra
|
||||
err := json.Unmarshal([]byte(rpctesting.ElectraBlockContents), &blockContents)
|
||||
require.NoError(t, err)
|
||||
genericSignedBlock, err := blockContents.ToGeneric()
|
||||
require.NoError(t, err)
|
||||
|
||||
electraBytes, err := json.Marshal(blockContents)
|
||||
require.NoError(t, err)
|
||||
// Make sure that what we send in the POST body is the marshalled version of the protobuf block
|
||||
headers := map[string]string{"Eth-Consensus-Version": "electra"}
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blocks",
|
||||
headers,
|
||||
bytes.NewBuffer(electraBytes),
|
||||
nil,
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(t.Context(), genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := genericSignedBlock.GetElectra().Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure that the block root is set
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||
rpctesting "github.com/OffchainLabs/prysm/v6/beacon-chain/rpc/eth/shared/testing"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/mock"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestProposeBeaconBlock_Fulu(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
var blockContents structs.SignedBeaconBlockContentsFulu
|
||||
err := json.Unmarshal([]byte(rpctesting.FuluBlockContents), &blockContents)
|
||||
require.NoError(t, err)
|
||||
genericSignedBlock, err := blockContents.ToGeneric()
|
||||
require.NoError(t, err)
|
||||
|
||||
fuluBytes, err := json.Marshal(blockContents)
|
||||
require.NoError(t, err)
|
||||
// Make sure that what we send in the POST body is the marshalled version of the protobuf block
|
||||
headers := map[string]string{"Eth-Consensus-Version": "fulu"}
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blocks",
|
||||
headers,
|
||||
bytes.NewBuffer(fuluBytes),
|
||||
nil,
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(t.Context(), genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := genericSignedBlock.GetFulu().Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure that the block root is set
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/mock"
|
||||
testhelpers "github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/test-helpers"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestProposeBeaconBlock_Phase0(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
phase0Block := generateSignedPhase0Block()
|
||||
|
||||
genericSignedBlock := ðpb.GenericSignedBeaconBlock{}
|
||||
genericSignedBlock.Block = phase0Block
|
||||
|
||||
jsonPhase0Block := structs.SignedBeaconBlockPhase0FromConsensus(phase0Block.Phase0)
|
||||
|
||||
marshalledBlock, err := json.Marshal(jsonPhase0Block)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := t.Context()
|
||||
|
||||
// Make sure that what we send in the POST body is the marshalled version of the protobuf block
|
||||
headers := map[string]string{"Eth-Consensus-Version": "phase0"}
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blocks",
|
||||
headers,
|
||||
bytes.NewBuffer(marshalledBlock),
|
||||
nil,
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(ctx, genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := phase0Block.Phase0.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure that the block root is set
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
}
|
||||
|
||||
func generateSignedPhase0Block() *ethpb.GenericSignedBeaconBlock_Phase0 {
|
||||
return ðpb.GenericSignedBeaconBlock_Phase0{
|
||||
Phase0: ðpb.SignedBeaconBlock{
|
||||
Block: testhelpers.GenerateProtoPhase0BeaconBlock(),
|
||||
Signature: testhelpers.FillByteSlice(96, 110),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,43 +1,42 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||
rpctesting "github.com/OffchainLabs/prysm/v6/beacon-chain/rpc/eth/shared/testing"
|
||||
"github.com/OffchainLabs/prysm/v6/network/httputil"
|
||||
engine "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/mock"
|
||||
testhelpers "github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/test-helpers"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestProposeBeaconBlock_Error(t *testing.T) {
|
||||
func TestProposeBeaconBlock_SSZ_Error(t *testing.T) {
|
||||
testSuites := []struct {
|
||||
name string
|
||||
returnedError error
|
||||
expectedErrorMessage string
|
||||
}{
|
||||
{
|
||||
name: "error 202",
|
||||
expectedErrorMessage: "block was successfully broadcast but failed validation",
|
||||
returnedError: &httputil.DefaultJsonError{
|
||||
Code: http.StatusAccepted,
|
||||
Message: "202 error",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "error 500",
|
||||
expectedErrorMessage: "HTTP request unsuccessful (500: foo error)",
|
||||
expectedErrorMessage: "failed to submit block ssz",
|
||||
returnedError: &httputil.DefaultJsonError{
|
||||
Code: http.StatusInternalServerError,
|
||||
Message: "foo error",
|
||||
Message: "failed to submit block ssz",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "other error",
|
||||
expectedErrorMessage: "foo error",
|
||||
returnedError: errors.New("foo error"),
|
||||
expectedErrorMessage: "failed to submit block ssz",
|
||||
returnedError: errors.New("failed to submit block ssz"),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -106,17 +105,21 @@ func TestProposeBeaconBlock_Error(t *testing.T) {
|
||||
ctx := t.Context()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
headers := map[string]string{"Eth-Consensus-Version": testCase.consensusVersion}
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
// Expect PostSSZ to be called first with SSZ data
|
||||
headers := map[string]string{
|
||||
"Eth-Consensus-Version": testCase.consensusVersion,
|
||||
}
|
||||
jsonRestHandler.EXPECT().PostSSZ(
|
||||
gomock.Any(),
|
||||
testCase.endpoint,
|
||||
headers,
|
||||
gomock.Any(),
|
||||
nil,
|
||||
).Return(
|
||||
testSuite.returnedError,
|
||||
nil, nil, testSuite.returnedError,
|
||||
).Times(1)
|
||||
|
||||
// No JSON fallback expected for non-406 errors
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
_, err := validatorClient.proposeBeaconBlock(ctx, testCase.block)
|
||||
assert.ErrorContains(t, testSuite.expectedErrorMessage, err)
|
||||
@@ -130,3 +133,546 @@ func TestProposeBeaconBlock_UnsupportedBlockType(t *testing.T) {
|
||||
_, err := validatorClient.proposeBeaconBlock(t.Context(), ðpb.GenericSignedBeaconBlock{})
|
||||
assert.ErrorContains(t, "unsupported block type", err)
|
||||
}
|
||||
|
||||
func TestProposeBeaconBlock_SSZSuccess_NoFallback(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
consensusVersion string
|
||||
endpoint string
|
||||
block *ethpb.GenericSignedBeaconBlock
|
||||
}{
|
||||
{
|
||||
name: "phase0",
|
||||
consensusVersion: "phase0",
|
||||
endpoint: "/eth/v2/beacon/blocks",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedPhase0Block(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "altair",
|
||||
consensusVersion: "altair",
|
||||
endpoint: "/eth/v2/beacon/blocks",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedAltairBlock(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
ctx := t.Context()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
// Expect PostSSZ to be called and succeed
|
||||
headers := map[string]string{
|
||||
"Eth-Consensus-Version": testCase.consensusVersion,
|
||||
}
|
||||
jsonRestHandler.EXPECT().PostSSZ(
|
||||
gomock.Any(),
|
||||
testCase.endpoint,
|
||||
headers,
|
||||
gomock.Any(),
|
||||
).Return(
|
||||
nil, nil, nil,
|
||||
).Times(1)
|
||||
|
||||
// Post should NOT be called when PostSSZ succeeds
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
).Times(0)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
_, err := validatorClient.proposeBeaconBlock(ctx, testCase.block)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProposeBeaconBlock_NewerTypes_SSZMarshal(t *testing.T) {
|
||||
t.Run("deneb", func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
var blockContents structs.SignedBeaconBlockContentsDeneb
|
||||
err := json.Unmarshal([]byte(rpctesting.DenebBlockContents), &blockContents)
|
||||
require.NoError(t, err)
|
||||
genericSignedBlock, err := blockContents.ToGeneric()
|
||||
require.NoError(t, err)
|
||||
|
||||
denebBytes, err := genericSignedBlock.GetDeneb().MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
jsonRestHandler.EXPECT().PostSSZ(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blocks",
|
||||
gomock.Any(),
|
||||
bytes.NewBuffer(denebBytes),
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(t.Context(), genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := genericSignedBlock.GetDeneb().Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
})
|
||||
|
||||
t.Run("blinded_deneb", func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
var blindedBlock structs.SignedBlindedBeaconBlockDeneb
|
||||
err := json.Unmarshal([]byte(rpctesting.BlindedDenebBlock), &blindedBlock)
|
||||
require.NoError(t, err)
|
||||
genericSignedBlock, err := blindedBlock.ToGeneric()
|
||||
require.NoError(t, err)
|
||||
|
||||
blindedDenebBytes, err := genericSignedBlock.GetBlindedDeneb().MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
jsonRestHandler.EXPECT().PostSSZ(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blinded_blocks",
|
||||
gomock.Any(),
|
||||
bytes.NewBuffer(blindedDenebBytes),
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(t.Context(), genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := genericSignedBlock.GetBlindedDeneb().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
})
|
||||
|
||||
t.Run("electra", func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
var blockContents structs.SignedBeaconBlockContentsElectra
|
||||
err := json.Unmarshal([]byte(rpctesting.ElectraBlockContents), &blockContents)
|
||||
require.NoError(t, err)
|
||||
genericSignedBlock, err := blockContents.ToGeneric()
|
||||
require.NoError(t, err)
|
||||
|
||||
electraBytes, err := genericSignedBlock.GetElectra().MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
jsonRestHandler.EXPECT().PostSSZ(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blocks",
|
||||
gomock.Any(),
|
||||
bytes.NewBuffer(electraBytes),
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(t.Context(), genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := genericSignedBlock.GetElectra().Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
})
|
||||
|
||||
t.Run("blinded_electra", func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
var blindedBlock structs.SignedBlindedBeaconBlockElectra
|
||||
err := json.Unmarshal([]byte(rpctesting.BlindedElectraBlock), &blindedBlock)
|
||||
require.NoError(t, err)
|
||||
genericSignedBlock, err := blindedBlock.ToGeneric()
|
||||
require.NoError(t, err)
|
||||
|
||||
blindedElectraBytes, err := genericSignedBlock.GetBlindedElectra().MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
jsonRestHandler.EXPECT().PostSSZ(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blinded_blocks",
|
||||
gomock.Any(),
|
||||
bytes.NewBuffer(blindedElectraBytes),
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(t.Context(), genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := genericSignedBlock.GetBlindedElectra().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
})
|
||||
|
||||
t.Run("fulu", func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
var blockContents structs.SignedBeaconBlockContentsFulu
|
||||
err := json.Unmarshal([]byte(rpctesting.FuluBlockContents), &blockContents)
|
||||
require.NoError(t, err)
|
||||
genericSignedBlock, err := blockContents.ToGeneric()
|
||||
require.NoError(t, err)
|
||||
|
||||
fuluBytes, err := genericSignedBlock.GetFulu().MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
jsonRestHandler.EXPECT().PostSSZ(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blocks",
|
||||
gomock.Any(),
|
||||
bytes.NewBuffer(fuluBytes),
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(t.Context(), genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := genericSignedBlock.GetFulu().Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
})
|
||||
|
||||
t.Run("blinded_fulu", func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
var blindedBlock structs.SignedBlindedBeaconBlockFulu
|
||||
err := json.Unmarshal([]byte(rpctesting.BlindedFuluBlock), &blindedBlock)
|
||||
require.NoError(t, err)
|
||||
genericSignedBlock, err := blindedBlock.ToGeneric()
|
||||
require.NoError(t, err)
|
||||
|
||||
blindedFuluBytes, err := genericSignedBlock.GetBlindedFulu().MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
jsonRestHandler.EXPECT().PostSSZ(
|
||||
gomock.Any(),
|
||||
"/eth/v2/beacon/blinded_blocks",
|
||||
gomock.Any(),
|
||||
bytes.NewBuffer(blindedFuluBytes),
|
||||
)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
proposeResponse, err := validatorClient.proposeBeaconBlock(t.Context(), genericSignedBlock)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, proposeResponse)
|
||||
|
||||
expectedBlockRoot, err := genericSignedBlock.GetBlindedFulu().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
|
||||
})
|
||||
}
|
||||
|
||||
// Generator functions for test blocks
|
||||
func generateSignedPhase0Block() *ethpb.GenericSignedBeaconBlock_Phase0 {
|
||||
return ðpb.GenericSignedBeaconBlock_Phase0{
|
||||
Phase0: ðpb.SignedBeaconBlock{
|
||||
Block: testhelpers.GenerateProtoPhase0BeaconBlock(),
|
||||
Signature: testhelpers.FillByteSlice(96, 110),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func generateSignedAltairBlock() *ethpb.GenericSignedBeaconBlock_Altair {
|
||||
return ðpb.GenericSignedBeaconBlock_Altair{
|
||||
Altair: ðpb.SignedBeaconBlockAltair{
|
||||
Block: testhelpers.GenerateProtoAltairBeaconBlock(),
|
||||
Signature: testhelpers.FillByteSlice(96, 112),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func generateSignedBellatrixBlock() *ethpb.GenericSignedBeaconBlock_Bellatrix {
|
||||
return ðpb.GenericSignedBeaconBlock_Bellatrix{
|
||||
Bellatrix: ðpb.SignedBeaconBlockBellatrix{
|
||||
Block: testhelpers.GenerateProtoBellatrixBeaconBlock(),
|
||||
Signature: testhelpers.FillByteSlice(96, 127),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func generateSignedBlindedBellatrixBlock() *ethpb.GenericSignedBeaconBlock_BlindedBellatrix {
|
||||
return ðpb.GenericSignedBeaconBlock_BlindedBellatrix{
|
||||
BlindedBellatrix: ðpb.SignedBlindedBeaconBlockBellatrix{
|
||||
Block: ðpb.BlindedBeaconBlockBellatrix{
|
||||
Slot: 1,
|
||||
ProposerIndex: 2,
|
||||
ParentRoot: testhelpers.FillByteSlice(32, 3),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 4),
|
||||
Body: ðpb.BlindedBeaconBlockBodyBellatrix{
|
||||
RandaoReveal: testhelpers.FillByteSlice(96, 5),
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: testhelpers.FillByteSlice(32, 6),
|
||||
DepositCount: 7,
|
||||
BlockHash: testhelpers.FillByteSlice(32, 8),
|
||||
},
|
||||
Graffiti: testhelpers.FillByteSlice(32, 9),
|
||||
ProposerSlashings: []*ethpb.ProposerSlashing{
|
||||
{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 10,
|
||||
ProposerIndex: 11,
|
||||
ParentRoot: testhelpers.FillByteSlice(32, 12),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 13),
|
||||
BodyRoot: testhelpers.FillByteSlice(32, 14),
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 15),
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 16,
|
||||
ProposerIndex: 17,
|
||||
ParentRoot: testhelpers.FillByteSlice(32, 18),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 19),
|
||||
BodyRoot: testhelpers.FillByteSlice(32, 20),
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 21),
|
||||
},
|
||||
},
|
||||
},
|
||||
AttesterSlashings: []*ethpb.AttesterSlashing{},
|
||||
Attestations: []*ethpb.Attestation{},
|
||||
Deposits: []*ethpb.Deposit{},
|
||||
VoluntaryExits: []*ethpb.SignedVoluntaryExit{},
|
||||
SyncAggregate: ðpb.SyncAggregate{
|
||||
SyncCommitteeBits: testhelpers.FillByteSlice(64, 100),
|
||||
SyncCommitteeSignature: testhelpers.FillByteSlice(96, 101),
|
||||
},
|
||||
ExecutionPayloadHeader: &engine.ExecutionPayloadHeader{
|
||||
ParentHash: testhelpers.FillByteSlice(32, 102),
|
||||
FeeRecipient: testhelpers.FillByteSlice(20, 103),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 104),
|
||||
ReceiptsRoot: testhelpers.FillByteSlice(32, 105),
|
||||
LogsBloom: testhelpers.FillByteSlice(256, 106),
|
||||
PrevRandao: testhelpers.FillByteSlice(32, 107),
|
||||
BlockNumber: 108,
|
||||
GasLimit: 109,
|
||||
GasUsed: 110,
|
||||
Timestamp: 111,
|
||||
ExtraData: testhelpers.FillByteSlice(32, 112),
|
||||
BaseFeePerGas: testhelpers.FillByteSlice(32, 113),
|
||||
BlockHash: testhelpers.FillByteSlice(32, 114),
|
||||
TransactionsRoot: testhelpers.FillByteSlice(32, 115),
|
||||
},
|
||||
},
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 116),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func generateSignedCapellaBlock() *ethpb.GenericSignedBeaconBlock_Capella {
|
||||
return ðpb.GenericSignedBeaconBlock_Capella{
|
||||
Capella: ðpb.SignedBeaconBlockCapella{
|
||||
Block: testhelpers.GenerateProtoCapellaBeaconBlock(),
|
||||
Signature: testhelpers.FillByteSlice(96, 127),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func generateSignedBlindedCapellaBlock() *ethpb.GenericSignedBeaconBlock_BlindedCapella {
|
||||
return ðpb.GenericSignedBeaconBlock_BlindedCapella{
|
||||
BlindedCapella: ðpb.SignedBlindedBeaconBlockCapella{
|
||||
Block: ðpb.BlindedBeaconBlockCapella{
|
||||
Slot: 1,
|
||||
ProposerIndex: 2,
|
||||
ParentRoot: testhelpers.FillByteSlice(32, 3),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 4),
|
||||
Body: ðpb.BlindedBeaconBlockBodyCapella{
|
||||
RandaoReveal: testhelpers.FillByteSlice(96, 5),
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: testhelpers.FillByteSlice(32, 6),
|
||||
DepositCount: 7,
|
||||
BlockHash: testhelpers.FillByteSlice(32, 8),
|
||||
},
|
||||
Graffiti: testhelpers.FillByteSlice(32, 9),
|
||||
ProposerSlashings: []*ethpb.ProposerSlashing{
|
||||
{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 10,
|
||||
ProposerIndex: 11,
|
||||
ParentRoot: testhelpers.FillByteSlice(32, 12),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 13),
|
||||
BodyRoot: testhelpers.FillByteSlice(32, 14),
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 15),
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 16,
|
||||
ProposerIndex: 17,
|
||||
ParentRoot: testhelpers.FillByteSlice(32, 18),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 19),
|
||||
BodyRoot: testhelpers.FillByteSlice(32, 20),
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 21),
|
||||
},
|
||||
},
|
||||
},
|
||||
AttesterSlashings: []*ethpb.AttesterSlashing{},
|
||||
Attestations: []*ethpb.Attestation{},
|
||||
Deposits: []*ethpb.Deposit{},
|
||||
VoluntaryExits: []*ethpb.SignedVoluntaryExit{},
|
||||
SyncAggregate: ðpb.SyncAggregate{
|
||||
SyncCommitteeBits: testhelpers.FillByteSlice(64, 37),
|
||||
SyncCommitteeSignature: testhelpers.FillByteSlice(96, 38),
|
||||
},
|
||||
ExecutionPayloadHeader: &engine.ExecutionPayloadHeaderCapella{
|
||||
ParentHash: testhelpers.FillByteSlice(32, 39),
|
||||
FeeRecipient: testhelpers.FillByteSlice(20, 40),
|
||||
StateRoot: testhelpers.FillByteSlice(32, 41),
|
||||
ReceiptsRoot: testhelpers.FillByteSlice(32, 42),
|
||||
LogsBloom: testhelpers.FillByteSlice(256, 43),
|
||||
PrevRandao: testhelpers.FillByteSlice(32, 44),
|
||||
BlockNumber: 45,
|
||||
GasLimit: 46,
|
||||
GasUsed: 47,
|
||||
Timestamp: 48,
|
||||
ExtraData: testhelpers.FillByteSlice(32, 49),
|
||||
BaseFeePerGas: testhelpers.FillByteSlice(32, 50),
|
||||
BlockHash: testhelpers.FillByteSlice(32, 51),
|
||||
TransactionsRoot: testhelpers.FillByteSlice(32, 52),
|
||||
WithdrawalsRoot: testhelpers.FillByteSlice(32, 53),
|
||||
},
|
||||
BlsToExecutionChanges: []*ethpb.SignedBLSToExecutionChange{},
|
||||
},
|
||||
},
|
||||
Signature: testhelpers.FillByteSlice(96, 54),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestProposeBeaconBlock_SSZFails_406_FallbackToJSON(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
consensusVersion string
|
||||
endpoint string
|
||||
block *ethpb.GenericSignedBeaconBlock
|
||||
}{
|
||||
{
|
||||
name: "phase0",
|
||||
consensusVersion: "phase0",
|
||||
endpoint: "/eth/v2/beacon/blocks",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedPhase0Block(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
ctx := t.Context()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
// Expect PostSSZ to be called first and fail
|
||||
jsonRestHandler.EXPECT().PostSSZ(
|
||||
gomock.Any(),
|
||||
testCase.endpoint,
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
).Return(
|
||||
nil, nil, &httputil.DefaultJsonError{
|
||||
Code: http.StatusNotAcceptable,
|
||||
Message: "SSZ not supported",
|
||||
},
|
||||
).Times(1)
|
||||
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
testCase.endpoint,
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
nil,
|
||||
).Return(
|
||||
nil,
|
||||
).Times(1)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
_, err := validatorClient.proposeBeaconBlock(ctx, testCase.block)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProposeBeaconBlock_SSZFails_Non406_NoFallback(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
consensusVersion string
|
||||
endpoint string
|
||||
block *ethpb.GenericSignedBeaconBlock
|
||||
}{
|
||||
{
|
||||
name: "phase0",
|
||||
consensusVersion: "phase0",
|
||||
endpoint: "/eth/v2/beacon/blocks",
|
||||
block: ðpb.GenericSignedBeaconBlock{
|
||||
Block: generateSignedPhase0Block(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
ctx := t.Context()
|
||||
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
|
||||
|
||||
// Expect PostSSZ to be called first and fail with non-406 error
|
||||
sszHeaders := map[string]string{
|
||||
"Eth-Consensus-Version": testCase.consensusVersion,
|
||||
}
|
||||
jsonRestHandler.EXPECT().PostSSZ(
|
||||
gomock.Any(),
|
||||
testCase.endpoint,
|
||||
sszHeaders,
|
||||
gomock.Any(),
|
||||
).Return(
|
||||
nil, nil, &httputil.DefaultJsonError{
|
||||
Code: http.StatusInternalServerError,
|
||||
Message: "Internal server error",
|
||||
},
|
||||
).Times(1)
|
||||
|
||||
// Post should NOT be called for non-406 errors
|
||||
jsonRestHandler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
).Times(0)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
|
||||
_, err := validatorClient.proposeBeaconBlock(ctx, testCase.block)
|
||||
require.ErrorContains(t, "Internal server error", err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ type RestHandler interface {
|
||||
Get(ctx context.Context, endpoint string, resp interface{}) error
|
||||
GetSSZ(ctx context.Context, endpoint string) ([]byte, http.Header, error)
|
||||
Post(ctx context.Context, endpoint string, headers map[string]string, data *bytes.Buffer, resp interface{}) error
|
||||
PostSSZ(ctx context.Context, endpoint string, headers map[string]string, data *bytes.Buffer) ([]byte, http.Header, error)
|
||||
HttpClient() *http.Client
|
||||
Host() string
|
||||
SetHost(host string)
|
||||
@@ -179,6 +180,75 @@ func (c *BeaconApiRestHandler) Post(
|
||||
return decodeResp(httpResp, resp)
|
||||
}
|
||||
|
||||
// PostSSZ sends a POST request and prefers an SSZ (application/octet-stream) response body.
|
||||
func (c *BeaconApiRestHandler) PostSSZ(
|
||||
ctx context.Context,
|
||||
apiEndpoint string,
|
||||
headers map[string]string,
|
||||
data *bytes.Buffer,
|
||||
) ([]byte, http.Header, error) {
|
||||
if data == nil {
|
||||
return nil, nil, errors.New("data is nil")
|
||||
}
|
||||
url := c.host + apiEndpoint
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, data)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "failed to create request for endpoint %s", url)
|
||||
}
|
||||
|
||||
// Accept header: prefer octet-stream (SSZ), fall back to JSON
|
||||
primaryAcceptType := fmt.Sprintf("%s;q=%s", api.OctetStreamMediaType, "0.95")
|
||||
secondaryAcceptType := fmt.Sprintf("%s;q=%s", api.JsonMediaType, "0.9")
|
||||
acceptHeaderString := fmt.Sprintf("%s,%s", primaryAcceptType, secondaryAcceptType)
|
||||
req.Header.Set("Accept", acceptHeaderString)
|
||||
|
||||
// User-supplied headers
|
||||
for headerKey, headerValue := range headers {
|
||||
req.Header.Set(headerKey, headerValue)
|
||||
}
|
||||
|
||||
for _, o := range c.reqOverrides {
|
||||
o(req)
|
||||
}
|
||||
req.Header.Set("Content-Type", api.OctetStreamMediaType)
|
||||
req.Header.Set("User-Agent", version.BuildData())
|
||||
httpResp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "failed to perform request for endpoint %s", url)
|
||||
}
|
||||
defer func() {
|
||||
if err := httpResp.Body.Close(); err != nil {
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
accept := req.Header.Get("Accept")
|
||||
contentType := httpResp.Header.Get("Content-Type")
|
||||
body, err := io.ReadAll(httpResp.Body)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "failed to read response body for %s", httpResp.Request.URL)
|
||||
}
|
||||
|
||||
if !apiutil.PrimaryAcceptMatches(accept, contentType) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"Accept": accept,
|
||||
"Content-Type": contentType,
|
||||
}).Debug("Server responded with non primary accept type")
|
||||
}
|
||||
|
||||
// non-2XX codes are a failure
|
||||
if !strings.HasPrefix(httpResp.Status, "2") {
|
||||
decoder := json.NewDecoder(bytes.NewBuffer(body))
|
||||
errorJson := &httputil.DefaultJsonError{}
|
||||
if err = decoder.Decode(errorJson); err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "failed to decode response body into error json for %s", httpResp.Request.URL)
|
||||
}
|
||||
return nil, nil, errorJson
|
||||
}
|
||||
|
||||
return body, httpResp.Header, nil
|
||||
}
|
||||
|
||||
func decodeResp(httpResp *http.Response, resp interface{}) error {
|
||||
body, err := io.ReadAll(httpResp.Body)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user