mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 05:47:59 -05:00
Compare commits
6 Commits
v5.1.1-rc.
...
use_hashtr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a289071ddd | ||
|
|
24a6025426 | ||
|
|
57cc4950c0 | ||
|
|
2c981d5564 | ||
|
|
492c8af83f | ||
|
|
e40d2cbd2c |
12
CHANGELOG.md
12
CHANGELOG.md
@@ -16,13 +16,16 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
|
||||
- Light client support: Implement `BlockToLightClientHeader` function.
|
||||
- Light client support: Consensus types.
|
||||
- GetBeaconStateV2: add Electra case.
|
||||
- Implement [consensus-specs/3875](https://github.com/ethereum/consensus-specs/pull/3875)
|
||||
- Tests to ensure sepolia config matches the official upstream yaml
|
||||
- HTTP endpoint for PublishBlobs
|
||||
- Implement [consensus-specs/3875](https://github.com/ethereum/consensus-specs/pull/3875).
|
||||
- Tests to ensure sepolia config matches the official upstream yaml.
|
||||
- HTTP endpoint for PublishBlobs.
|
||||
- GetBlockV2, GetBlindedBlock, ProduceBlockV2, ProduceBlockV3: add Electra case.
|
||||
- Add Electra support and tests for light client functions
|
||||
- Add Electra support and tests for light client functions.
|
||||
- fastssz version bump (better error messages).
|
||||
- SSE implementation that sheds stuck clients. [pr](https://github.com/prysmaticlabs/prysm/pull/14413)
|
||||
- Add Bellatrix tests for light client functions.
|
||||
- Add Discovery Rebooter Feature.
|
||||
- Added GetBlockAttestationsV2 endpoint.
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -80,6 +83,7 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
|
||||
- Light client support: fix light client attested header execution fields' wrong version bug.
|
||||
- Testing: added custom matcher for better push settings testing.
|
||||
- Registered `GetDepositSnapshot` Beacon API endpoint.
|
||||
- Fixed mesh size by appending `gParams.Dhi = gossipSubDhi`
|
||||
|
||||
### Security
|
||||
|
||||
|
||||
@@ -133,6 +133,13 @@ type GetBlockAttestationsResponse struct {
|
||||
Data []*Attestation `json:"data"`
|
||||
}
|
||||
|
||||
type GetBlockAttestationsV2Response struct {
|
||||
Version string `json:"version"`
|
||||
ExecutionOptimistic bool `json:"execution_optimistic"`
|
||||
Finalized bool `json:"finalized"`
|
||||
Data json.RawMessage `json:"data"` // Accepts both `Attestation` and `AttestationElectra` types
|
||||
}
|
||||
|
||||
type GetStateRootResponse struct {
|
||||
ExecutionOptimistic bool `json:"execution_optimistic"`
|
||||
Finalized bool `json:"finalized"`
|
||||
|
||||
@@ -364,6 +364,26 @@ func TestLightClient_BlockToLightClientHeader(t *testing.T) {
|
||||
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon.BodyRoot, "Body root is not equal")
|
||||
})
|
||||
|
||||
t.Run("Bellatrix", func(t *testing.T) {
|
||||
l := util.NewTestLightClient(t).SetupTestBellatrix()
|
||||
|
||||
container, err := lightClient.BlockToLightClientHeader(l.Block)
|
||||
require.NoError(t, err)
|
||||
header := container.GetHeaderAltair()
|
||||
require.NotNil(t, header, "header is nil")
|
||||
|
||||
parentRoot := l.Block.Block().ParentRoot()
|
||||
stateRoot := l.Block.Block().StateRoot()
|
||||
bodyRoot, err := l.Block.Block().Body().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, l.Block.Block().Slot(), header.Beacon.Slot, "Slot is not equal")
|
||||
require.Equal(t, l.Block.Block().ProposerIndex(), header.Beacon.ProposerIndex, "Proposer index is not equal")
|
||||
require.DeepSSZEqual(t, parentRoot[:], header.Beacon.ParentRoot, "Parent root is not equal")
|
||||
require.DeepSSZEqual(t, stateRoot[:], header.Beacon.StateRoot, "State root is not equal")
|
||||
require.DeepSSZEqual(t, bodyRoot[:], header.Beacon.BodyRoot, "Body root is not equal")
|
||||
})
|
||||
|
||||
t.Run("Capella", func(t *testing.T) {
|
||||
t.Run("Non-Blinded Beacon Block", func(t *testing.T) {
|
||||
l := util.NewTestLightClient(t).SetupTestCapella(false)
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
@@ -236,7 +235,7 @@ func TestService_BroadcastAttestationWithDiscoveryAttempts(t *testing.T) {
|
||||
bootNode := bootListener.Self()
|
||||
subnet := uint64(5)
|
||||
|
||||
var listeners []*discover.UDPv5
|
||||
var listeners []*listenerWrapper
|
||||
var hosts []host.Host
|
||||
// setup other nodes.
|
||||
cfg = &Config{
|
||||
|
||||
@@ -50,7 +50,7 @@ func TestPeer_AtMaxLimit(t *testing.T) {
|
||||
}()
|
||||
|
||||
for i := 0; i < highWatermarkBuffer; i++ {
|
||||
addPeer(t, s.peers, peers.PeerConnected)
|
||||
addPeer(t, s.peers, peers.PeerConnected, false)
|
||||
}
|
||||
|
||||
// create alternate host
|
||||
@@ -159,7 +159,7 @@ func TestService_RejectInboundPeersBeyondLimit(t *testing.T) {
|
||||
inboundLimit += 1
|
||||
// Add in up to inbound peer limit.
|
||||
for i := 0; i < int(inboundLimit); i++ {
|
||||
addPeer(t, s.peers, peerdata.PeerConnectionState(ethpb.ConnectionState_CONNECTED))
|
||||
addPeer(t, s.peers, peerdata.PeerConnectionState(ethpb.ConnectionState_CONNECTED), false)
|
||||
}
|
||||
valid = s.InterceptAccept(&maEndpoints{raddr: multiAddress})
|
||||
if valid {
|
||||
|
||||
@@ -24,6 +24,11 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||
)
|
||||
|
||||
type ListenerRebooter interface {
|
||||
Listener
|
||||
RebootListener() error
|
||||
}
|
||||
|
||||
// Listener defines the discovery V5 network interface that is used
|
||||
// to communicate with other peers.
|
||||
type Listener interface {
|
||||
@@ -47,6 +52,87 @@ type quicProtocol uint16
|
||||
// quicProtocol is the "quic" key, which holds the QUIC port of the node.
|
||||
func (quicProtocol) ENRKey() string { return "quic" }
|
||||
|
||||
type listenerWrapper struct {
|
||||
mu sync.RWMutex
|
||||
listener *discover.UDPv5
|
||||
listenerCreator func() (*discover.UDPv5, error)
|
||||
}
|
||||
|
||||
func newListener(listenerCreator func() (*discover.UDPv5, error)) (*listenerWrapper, error) {
|
||||
rawListener, err := listenerCreator()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create new listener")
|
||||
}
|
||||
return &listenerWrapper{
|
||||
listener: rawListener,
|
||||
listenerCreator: listenerCreator,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (l *listenerWrapper) Self() *enode.Node {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
return l.listener.Self()
|
||||
}
|
||||
|
||||
func (l *listenerWrapper) Close() {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
l.listener.Close()
|
||||
}
|
||||
|
||||
func (l *listenerWrapper) Lookup(id enode.ID) []*enode.Node {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
return l.listener.Lookup(id)
|
||||
}
|
||||
|
||||
func (l *listenerWrapper) Resolve(node *enode.Node) *enode.Node {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
return l.listener.Resolve(node)
|
||||
}
|
||||
|
||||
func (l *listenerWrapper) RandomNodes() enode.Iterator {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
return l.listener.RandomNodes()
|
||||
}
|
||||
|
||||
func (l *listenerWrapper) Ping(node *enode.Node) error {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
return l.listener.Ping(node)
|
||||
}
|
||||
|
||||
func (l *listenerWrapper) RequestENR(node *enode.Node) (*enode.Node, error) {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
return l.listener.RequestENR(node)
|
||||
}
|
||||
|
||||
func (l *listenerWrapper) LocalNode() *enode.LocalNode {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
return l.listener.LocalNode()
|
||||
}
|
||||
|
||||
func (l *listenerWrapper) RebootListener() error {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
// Close current listener
|
||||
l.listener.Close()
|
||||
|
||||
newListener, err := l.listenerCreator()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.listener = newListener
|
||||
return nil
|
||||
}
|
||||
|
||||
// RefreshENR uses an epoch to refresh the enr entry for our node
|
||||
// with the tracked committee ids for the epoch, allowing our node
|
||||
// to be dynamically discoverable by others given our tracked committee ids.
|
||||
@@ -110,55 +196,78 @@ func (s *Service) RefreshENR() {
|
||||
func (s *Service) listenForNewNodes() {
|
||||
iterator := filterNodes(s.ctx, s.dv5Listener.RandomNodes(), s.filterPeer)
|
||||
defer iterator.Close()
|
||||
connectivityTicker := time.NewTicker(1 * time.Minute)
|
||||
thresholdCount := 0
|
||||
|
||||
for {
|
||||
// Exit if service's context is canceled.
|
||||
if s.ctx.Err() != nil {
|
||||
break
|
||||
}
|
||||
|
||||
if s.isPeerAtLimit(false /* inbound */) {
|
||||
// Pause the main loop for a period to stop looking
|
||||
// for new peers.
|
||||
log.Trace("Not looking for peers, at peer limit")
|
||||
time.Sleep(pollingPeriod)
|
||||
continue
|
||||
}
|
||||
wantedCount := s.wantedPeerDials()
|
||||
if wantedCount == 0 {
|
||||
log.Trace("Not looking for peers, at peer limit")
|
||||
time.Sleep(pollingPeriod)
|
||||
continue
|
||||
}
|
||||
// Restrict dials if limit is applied.
|
||||
if flags.MaxDialIsActive() {
|
||||
wantedCount = min(wantedCount, flags.Get().MaxConcurrentDials)
|
||||
}
|
||||
wantedNodes := enode.ReadNodes(iterator, wantedCount)
|
||||
wg := new(sync.WaitGroup)
|
||||
for i := 0; i < len(wantedNodes); i++ {
|
||||
node := wantedNodes[i]
|
||||
peerInfo, _, err := convertToAddrInfo(node)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not convert to peer info")
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
return
|
||||
case <-connectivityTicker.C:
|
||||
// Skip the connectivity check if not enabled.
|
||||
if !features.Get().EnableDiscoveryReboot {
|
||||
continue
|
||||
}
|
||||
|
||||
if peerInfo == nil {
|
||||
if !s.isBelowOutboundPeerThreshold() {
|
||||
// Reset counter if we are beyond the threshold
|
||||
thresholdCount = 0
|
||||
continue
|
||||
}
|
||||
|
||||
// Make sure that peer is not dialed too often, for each connection attempt there's a backoff period.
|
||||
s.Peers().RandomizeBackOff(peerInfo.ID)
|
||||
wg.Add(1)
|
||||
go func(info *peer.AddrInfo) {
|
||||
if err := s.connectWithPeer(s.ctx, *info); err != nil {
|
||||
log.WithError(err).Tracef("Could not connect with peer %s", info.String())
|
||||
thresholdCount++
|
||||
// Reboot listener if connectivity drops
|
||||
if thresholdCount > 5 {
|
||||
log.WithField("outboundConnectionCount", len(s.peers.OutboundConnected())).Warn("Rebooting discovery listener, reached threshold.")
|
||||
if err := s.dv5Listener.RebootListener(); err != nil {
|
||||
log.WithError(err).Error("Could not reboot listener")
|
||||
continue
|
||||
}
|
||||
wg.Done()
|
||||
}(peerInfo)
|
||||
iterator = filterNodes(s.ctx, s.dv5Listener.RandomNodes(), s.filterPeer)
|
||||
thresholdCount = 0
|
||||
}
|
||||
default:
|
||||
if s.isPeerAtLimit(false /* inbound */) {
|
||||
// Pause the main loop for a period to stop looking
|
||||
// for new peers.
|
||||
log.Trace("Not looking for peers, at peer limit")
|
||||
time.Sleep(pollingPeriod)
|
||||
continue
|
||||
}
|
||||
wantedCount := s.wantedPeerDials()
|
||||
if wantedCount == 0 {
|
||||
log.Trace("Not looking for peers, at peer limit")
|
||||
time.Sleep(pollingPeriod)
|
||||
continue
|
||||
}
|
||||
// Restrict dials if limit is applied.
|
||||
if flags.MaxDialIsActive() {
|
||||
wantedCount = min(wantedCount, flags.Get().MaxConcurrentDials)
|
||||
}
|
||||
wantedNodes := enode.ReadNodes(iterator, wantedCount)
|
||||
wg := new(sync.WaitGroup)
|
||||
for i := 0; i < len(wantedNodes); i++ {
|
||||
node := wantedNodes[i]
|
||||
peerInfo, _, err := convertToAddrInfo(node)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not convert to peer info")
|
||||
continue
|
||||
}
|
||||
|
||||
if peerInfo == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Make sure that peer is not dialed too often, for each connection attempt there's a backoff period.
|
||||
s.Peers().RandomizeBackOff(peerInfo.ID)
|
||||
wg.Add(1)
|
||||
go func(info *peer.AddrInfo) {
|
||||
if err := s.connectWithPeer(s.ctx, *info); err != nil {
|
||||
log.WithError(err).Tracef("Could not connect with peer %s", info.String())
|
||||
}
|
||||
wg.Done()
|
||||
}(peerInfo)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,14 +408,17 @@ func (s *Service) createLocalNode(
|
||||
func (s *Service) startDiscoveryV5(
|
||||
addr net.IP,
|
||||
privKey *ecdsa.PrivateKey,
|
||||
) (*discover.UDPv5, error) {
|
||||
listener, err := s.createListener(addr, privKey)
|
||||
) (*listenerWrapper, error) {
|
||||
createListener := func() (*discover.UDPv5, error) {
|
||||
return s.createListener(addr, privKey)
|
||||
}
|
||||
wrappedListener, err := newListener(createListener)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create listener")
|
||||
}
|
||||
record := listener.Self()
|
||||
record := wrappedListener.Self()
|
||||
log.WithField("ENR", record.String()).Info("Started discovery v5")
|
||||
return listener, nil
|
||||
return wrappedListener, nil
|
||||
}
|
||||
|
||||
// filterPeer validates each node that we retrieve from our dht. We
|
||||
@@ -398,6 +510,22 @@ func (s *Service) isPeerAtLimit(inbound bool) bool {
|
||||
return activePeers >= maxPeers || numOfConns >= maxPeers
|
||||
}
|
||||
|
||||
// isBelowOutboundPeerThreshold checks if the number of outbound peers that
|
||||
// we are connected to satisfies the minimum expected outbound peer count
|
||||
// according to our peer limit.
|
||||
func (s *Service) isBelowOutboundPeerThreshold() bool {
|
||||
maxPeers := int(s.cfg.MaxPeers)
|
||||
inBoundLimit := s.Peers().InboundLimit()
|
||||
// Impossible Condition
|
||||
if maxPeers < inBoundLimit {
|
||||
return false
|
||||
}
|
||||
outboundFloor := maxPeers - inBoundLimit
|
||||
outBoundThreshold := outboundFloor / 2
|
||||
outBoundCount := len(s.Peers().OutboundConnected())
|
||||
return outBoundCount < outBoundThreshold
|
||||
}
|
||||
|
||||
func (s *Service) wantedPeerDials() int {
|
||||
maxPeers := int(s.cfg.MaxPeers)
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ func TestStartDiscV5_DiscoverAllPeers(t *testing.T) {
|
||||
|
||||
bootNode := bootListener.Self()
|
||||
|
||||
var listeners []*discover.UDPv5
|
||||
var listeners []*listenerWrapper
|
||||
for i := 1; i <= 5; i++ {
|
||||
port = 3000 + i
|
||||
cfg := &Config{
|
||||
@@ -231,6 +231,37 @@ func TestCreateLocalNode(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRebootDiscoveryListener(t *testing.T) {
|
||||
port := 1024
|
||||
ipAddr, pkey := createAddrAndPrivKey(t)
|
||||
s := &Service{
|
||||
genesisTime: time.Now(),
|
||||
genesisValidatorsRoot: bytesutil.PadTo([]byte{'A'}, 32),
|
||||
cfg: &Config{UDPPort: uint(port)},
|
||||
}
|
||||
createListener := func() (*discover.UDPv5, error) {
|
||||
return s.createListener(ipAddr, pkey)
|
||||
}
|
||||
listener, err := newListener(createListener)
|
||||
require.NoError(t, err)
|
||||
currentPubkey := listener.Self().Pubkey()
|
||||
currentID := listener.Self().ID()
|
||||
currentPort := listener.Self().UDP()
|
||||
currentAddr := listener.Self().IP()
|
||||
|
||||
assert.NoError(t, listener.RebootListener())
|
||||
|
||||
newPubkey := listener.Self().Pubkey()
|
||||
newID := listener.Self().ID()
|
||||
newPort := listener.Self().UDP()
|
||||
newAddr := listener.Self().IP()
|
||||
|
||||
assert.Equal(t, true, currentPubkey.Equal(newPubkey))
|
||||
assert.Equal(t, currentID, newID)
|
||||
assert.Equal(t, currentPort, newPort)
|
||||
assert.Equal(t, currentAddr.String(), newAddr.String())
|
||||
}
|
||||
|
||||
func TestMultiAddrsConversion_InvalidIPAddr(t *testing.T) {
|
||||
addr := net.ParseIP("invalidIP")
|
||||
_, pkey := createAddrAndPrivKey(t)
|
||||
@@ -347,19 +378,44 @@ func TestInboundPeerLimit(t *testing.T) {
|
||||
}
|
||||
|
||||
for i := 0; i < 30; i++ {
|
||||
_ = addPeer(t, s.peers, peerdata.PeerConnectionState(ethpb.ConnectionState_CONNECTED))
|
||||
_ = addPeer(t, s.peers, peerdata.PeerConnectionState(ethpb.ConnectionState_CONNECTED), false)
|
||||
}
|
||||
|
||||
require.Equal(t, true, s.isPeerAtLimit(false), "not at limit for outbound peers")
|
||||
require.Equal(t, false, s.isPeerAtLimit(true), "at limit for inbound peers")
|
||||
|
||||
for i := 0; i < highWatermarkBuffer; i++ {
|
||||
_ = addPeer(t, s.peers, peerdata.PeerConnectionState(ethpb.ConnectionState_CONNECTED))
|
||||
_ = addPeer(t, s.peers, peerdata.PeerConnectionState(ethpb.ConnectionState_CONNECTED), false)
|
||||
}
|
||||
|
||||
require.Equal(t, true, s.isPeerAtLimit(true), "not at limit for inbound peers")
|
||||
}
|
||||
|
||||
func TestOutboundPeerThreshold(t *testing.T) {
|
||||
fakePeer := testp2p.NewTestP2P(t)
|
||||
s := &Service{
|
||||
cfg: &Config{MaxPeers: 30},
|
||||
ipLimiter: leakybucket.NewCollector(ipLimit, ipBurst, 1*time.Second, false),
|
||||
peers: peers.NewStatus(context.Background(), &peers.StatusConfig{
|
||||
PeerLimit: 30,
|
||||
ScorerParams: &scorers.Config{},
|
||||
}),
|
||||
host: fakePeer.BHost,
|
||||
}
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
_ = addPeer(t, s.peers, peerdata.PeerConnectionState(ethpb.ConnectionState_CONNECTED), true)
|
||||
}
|
||||
|
||||
require.Equal(t, true, s.isBelowOutboundPeerThreshold(), "not at outbound peer threshold")
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
_ = addPeer(t, s.peers, peerdata.PeerConnectionState(ethpb.ConnectionState_CONNECTED), true)
|
||||
}
|
||||
|
||||
require.Equal(t, false, s.isBelowOutboundPeerThreshold(), "still at outbound peer threshold")
|
||||
}
|
||||
|
||||
func TestUDPMultiAddress(t *testing.T) {
|
||||
port := 6500
|
||||
ipAddr, pkey := createAddrAndPrivKey(t)
|
||||
@@ -370,7 +426,11 @@ func TestUDPMultiAddress(t *testing.T) {
|
||||
genesisTime: genesisTime,
|
||||
genesisValidatorsRoot: genesisValidatorsRoot,
|
||||
}
|
||||
listener, err := s.createListener(ipAddr, pkey)
|
||||
|
||||
createListener := func() (*discover.UDPv5, error) {
|
||||
return s.createListener(ipAddr, pkey)
|
||||
}
|
||||
listener, err := newListener(createListener)
|
||||
require.NoError(t, err)
|
||||
defer listener.Close()
|
||||
s.dv5Listener = listener
|
||||
@@ -417,7 +477,7 @@ func TestCorrectUDPVersion(t *testing.T) {
|
||||
}
|
||||
|
||||
// addPeer is a helper to add a peer with a given connection state)
|
||||
func addPeer(t *testing.T, p *peers.Status, state peerdata.PeerConnectionState) peer.ID {
|
||||
func addPeer(t *testing.T, p *peers.Status, state peerdata.PeerConnectionState, outbound bool) peer.ID {
|
||||
// Set up some peers with different states
|
||||
mhBytes := []byte{0x11, 0x04}
|
||||
idBytes := make([]byte, 4)
|
||||
@@ -426,7 +486,11 @@ func addPeer(t *testing.T, p *peers.Status, state peerdata.PeerConnectionState)
|
||||
mhBytes = append(mhBytes, idBytes...)
|
||||
id, err := peer.IDFromBytes(mhBytes)
|
||||
require.NoError(t, err)
|
||||
p.Add(new(enr.Record), id, nil, network.DirInbound)
|
||||
dir := network.DirInbound
|
||||
if outbound {
|
||||
dir = network.DirOutbound
|
||||
}
|
||||
p.Add(new(enr.Record), id, nil, dir)
|
||||
p.SetConnectionState(id, state)
|
||||
p.SetMetadata(id, wrapper.WrappedMetadataV0(ðpb.MetaDataV0{
|
||||
SeqNumber: 0,
|
||||
@@ -455,7 +519,10 @@ func TestRefreshENR_ForkBoundaries(t *testing.T) {
|
||||
genesisValidatorsRoot: bytesutil.PadTo([]byte{'A'}, 32),
|
||||
cfg: &Config{UDPPort: uint(port)},
|
||||
}
|
||||
listener, err := s.createListener(ipAddr, pkey)
|
||||
createListener := func() (*discover.UDPv5, error) {
|
||||
return s.createListener(ipAddr, pkey)
|
||||
}
|
||||
listener, err := newListener(createListener)
|
||||
assert.NoError(t, err)
|
||||
s.dv5Listener = listener
|
||||
s.metaData = wrapper.WrappedMetadataV0(new(ethpb.MetaDataV0))
|
||||
@@ -484,7 +551,10 @@ func TestRefreshENR_ForkBoundaries(t *testing.T) {
|
||||
genesisValidatorsRoot: bytesutil.PadTo([]byte{'A'}, 32),
|
||||
cfg: &Config{UDPPort: uint(port)},
|
||||
}
|
||||
listener, err := s.createListener(ipAddr, pkey)
|
||||
createListener := func() (*discover.UDPv5, error) {
|
||||
return s.createListener(ipAddr, pkey)
|
||||
}
|
||||
listener, err := newListener(createListener)
|
||||
assert.NoError(t, err)
|
||||
s.dv5Listener = listener
|
||||
s.metaData = wrapper.WrappedMetadataV0(new(ethpb.MetaDataV0))
|
||||
@@ -506,7 +576,10 @@ func TestRefreshENR_ForkBoundaries(t *testing.T) {
|
||||
genesisValidatorsRoot: bytesutil.PadTo([]byte{'A'}, 32),
|
||||
cfg: &Config{UDPPort: uint(port)},
|
||||
}
|
||||
listener, err := s.createListener(ipAddr, pkey)
|
||||
createListener := func() (*discover.UDPv5, error) {
|
||||
return s.createListener(ipAddr, pkey)
|
||||
}
|
||||
listener, err := newListener(createListener)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Update params
|
||||
@@ -537,7 +610,10 @@ func TestRefreshENR_ForkBoundaries(t *testing.T) {
|
||||
genesisValidatorsRoot: bytesutil.PadTo([]byte{'A'}, 32),
|
||||
cfg: &Config{UDPPort: uint(port)},
|
||||
}
|
||||
listener, err := s.createListener(ipAddr, pkey)
|
||||
createListener := func() (*discover.UDPv5, error) {
|
||||
return s.createListener(ipAddr, pkey)
|
||||
}
|
||||
listener, err := newListener(createListener)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Update params
|
||||
@@ -575,7 +651,10 @@ func TestRefreshENR_ForkBoundaries(t *testing.T) {
|
||||
genesisValidatorsRoot: bytesutil.PadTo([]byte{'A'}, 32),
|
||||
cfg: &Config{UDPPort: uint(port)},
|
||||
}
|
||||
listener, err := s.createListener(ipAddr, pkey)
|
||||
createListener := func() (*discover.UDPv5, error) {
|
||||
return s.createListener(ipAddr, pkey)
|
||||
}
|
||||
listener, err := newListener(createListener)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Update params
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
@@ -52,7 +51,7 @@ func TestStartDiscv5_DifferentForkDigests(t *testing.T) {
|
||||
StateNotifier: &mock.MockStateNotifier{},
|
||||
}
|
||||
|
||||
var listeners []*discover.UDPv5
|
||||
var listeners []*listenerWrapper
|
||||
for i := 1; i <= 5; i++ {
|
||||
port := 3000 + i
|
||||
cfg.UDPPort = uint(port)
|
||||
@@ -139,7 +138,7 @@ func TestStartDiscv5_SameForkDigests_DifferentNextForkData(t *testing.T) {
|
||||
UDPPort: uint(port),
|
||||
}
|
||||
|
||||
var listeners []*discover.UDPv5
|
||||
var listeners []*listenerWrapper
|
||||
for i := 1; i <= 5; i++ {
|
||||
port := 3000 + i
|
||||
cfg.UDPPort = uint(port)
|
||||
|
||||
@@ -182,6 +182,7 @@ func pubsubGossipParam() pubsub.GossipSubParams {
|
||||
gParams := pubsub.DefaultGossipSubParams()
|
||||
gParams.Dlo = gossipSubDlo
|
||||
gParams.D = gossipSubD
|
||||
gParams.Dhi = gossipSubDhi
|
||||
gParams.HeartbeatInterval = gossipSubHeartbeatInterval
|
||||
gParams.HistoryLength = gossipSubMcacheLen
|
||||
gParams.HistoryGossip = gossipSubMcacheGossip
|
||||
|
||||
@@ -71,7 +71,7 @@ type Service struct {
|
||||
subnetsLock map[uint64]*sync.RWMutex
|
||||
subnetsLockLock sync.Mutex // Lock access to subnetsLock
|
||||
initializationLock sync.Mutex
|
||||
dv5Listener Listener
|
||||
dv5Listener ListenerRebooter
|
||||
startupErr error
|
||||
ctx context.Context
|
||||
host host.Host
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/libp2p/go-libp2p"
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
@@ -69,6 +68,8 @@ func (mockListener) RandomNodes() enode.Iterator {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (mockListener) RebootListener() error { panic("implement me") }
|
||||
|
||||
func createHost(t *testing.T, port int) (host.Host, *ecdsa.PrivateKey, net.IP) {
|
||||
_, pkey := createAddrAndPrivKey(t)
|
||||
ipAddr := net.ParseIP("127.0.0.1")
|
||||
@@ -210,7 +211,7 @@ func TestListenForNewNodes(t *testing.T) {
|
||||
|
||||
bootNode := bootListener.Self()
|
||||
|
||||
var listeners []*discover.UDPv5
|
||||
var listeners []*listenerWrapper
|
||||
var hosts []host.Host
|
||||
// setup other nodes.
|
||||
cs := startup.NewClockSynchronizer()
|
||||
|
||||
@@ -585,6 +585,15 @@ func (s *Service) beaconEndpoints(
|
||||
handler: server.GetBlockAttestations,
|
||||
methods: []string{http.MethodGet},
|
||||
},
|
||||
{
|
||||
template: "/eth/v2/beacon/blocks/{block_id}/attestations",
|
||||
name: namespace + ".GetBlockAttestationsV2",
|
||||
middleware: []middleware.Middleware{
|
||||
middleware.AcceptHeaderHandler([]string{api.JsonMediaType}),
|
||||
},
|
||||
handler: server.GetBlockAttestations,
|
||||
methods: []string{http.MethodGet},
|
||||
},
|
||||
{
|
||||
template: "/eth/v1/beacon/blinded_blocks/{block_id}",
|
||||
name: namespace + ".GetBlindedBlock",
|
||||
|
||||
@@ -36,6 +36,7 @@ func Test_endpoints(t *testing.T) {
|
||||
"/eth/v2/beacon/blocks/{block_id}": {http.MethodGet},
|
||||
"/eth/v1/beacon/blocks/{block_id}/root": {http.MethodGet},
|
||||
"/eth/v1/beacon/blocks/{block_id}/attestations": {http.MethodGet},
|
||||
"/eth/v2/beacon/blocks/{block_id}/attestations": {http.MethodGet},
|
||||
"/eth/v1/beacon/blob_sidecars/{block_id}": {http.MethodGet},
|
||||
"/eth/v1/beacon/deposit_snapshot": {http.MethodGet},
|
||||
"/eth/v1/beacon/blinded_blocks/{block_id}": {http.MethodGet},
|
||||
|
||||
@@ -200,16 +200,10 @@ func (s *Server) GetBlockAttestations(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "beacon.GetBlockAttestations")
|
||||
defer span.End()
|
||||
|
||||
blockId := r.PathValue("block_id")
|
||||
if blockId == "" {
|
||||
httputil.HandleError(w, "block_id is required in URL params", http.StatusBadRequest)
|
||||
blk, isOptimistic, root := s.blockData(ctx, w, r)
|
||||
if blk == nil {
|
||||
return
|
||||
}
|
||||
blk, err := s.Blocker.Block(ctx, []byte(blockId))
|
||||
if !shared.WriteBlockFetchError(w, blk, err) {
|
||||
return
|
||||
}
|
||||
|
||||
consensusAtts := blk.Block().Body().Attestations()
|
||||
atts := make([]*structs.Attestation, len(consensusAtts))
|
||||
for i, att := range consensusAtts {
|
||||
@@ -221,17 +215,6 @@ func (s *Server) GetBlockAttestations(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
}
|
||||
root, err := blk.Block().HashTreeRoot()
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not get block root: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
isOptimistic, err := s.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not check if block is optimistic: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
resp := &structs.GetBlockAttestationsResponse{
|
||||
Data: atts,
|
||||
ExecutionOptimistic: isOptimistic,
|
||||
@@ -240,6 +223,79 @@ func (s *Server) GetBlockAttestations(w http.ResponseWriter, r *http.Request) {
|
||||
httputil.WriteJson(w, resp)
|
||||
}
|
||||
|
||||
// GetBlockAttestationsV2 retrieves attestation included in requested block.
|
||||
func (s *Server) GetBlockAttestationsV2(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "beacon.GetBlockAttestationsV2")
|
||||
defer span.End()
|
||||
|
||||
blk, isOptimistic, root := s.blockData(ctx, w, r)
|
||||
if blk == nil {
|
||||
return
|
||||
}
|
||||
consensusAtts := blk.Block().Body().Attestations()
|
||||
|
||||
v := blk.Block().Version()
|
||||
var attStructs []interface{}
|
||||
if v >= version.Electra {
|
||||
for _, att := range consensusAtts {
|
||||
a, ok := att.(*eth.AttestationElectra)
|
||||
if !ok {
|
||||
httputil.HandleError(w, fmt.Sprintf("unable to convert consensus attestations electra of type %T", att), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
attStruct := structs.AttElectraFromConsensus(a)
|
||||
attStructs = append(attStructs, attStruct)
|
||||
}
|
||||
} else {
|
||||
for _, att := range consensusAtts {
|
||||
a, ok := att.(*eth.Attestation)
|
||||
if !ok {
|
||||
httputil.HandleError(w, fmt.Sprintf("unable to convert consensus attestation of type %T", att), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
attStruct := structs.AttFromConsensus(a)
|
||||
attStructs = append(attStructs, attStruct)
|
||||
}
|
||||
}
|
||||
|
||||
attBytes, err := json.Marshal(attStructs)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, fmt.Sprintf("failed to marshal attestations: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
resp := &structs.GetBlockAttestationsV2Response{
|
||||
Version: version.String(v),
|
||||
ExecutionOptimistic: isOptimistic,
|
||||
Finalized: s.FinalizationFetcher.IsFinalized(ctx, root),
|
||||
Data: attBytes,
|
||||
}
|
||||
httputil.WriteJson(w, resp)
|
||||
}
|
||||
|
||||
func (s *Server) blockData(ctx context.Context, w http.ResponseWriter, r *http.Request) (interfaces.ReadOnlySignedBeaconBlock, bool, [32]byte) {
|
||||
blockId := r.PathValue("block_id")
|
||||
if blockId == "" {
|
||||
httputil.HandleError(w, "block_id is required in URL params", http.StatusBadRequest)
|
||||
return nil, false, [32]byte{}
|
||||
}
|
||||
blk, err := s.Blocker.Block(ctx, []byte(blockId))
|
||||
if !shared.WriteBlockFetchError(w, blk, err) {
|
||||
return nil, false, [32]byte{}
|
||||
}
|
||||
|
||||
root, err := blk.Block().HashTreeRoot()
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not get block root: "+err.Error(), http.StatusInternalServerError)
|
||||
return nil, false, [32]byte{}
|
||||
}
|
||||
isOptimistic, err := s.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not check if block is optimistic: "+err.Error(), http.StatusInternalServerError)
|
||||
return nil, false, [32]byte{}
|
||||
}
|
||||
return blk, isOptimistic, root
|
||||
}
|
||||
|
||||
// PublishBlindedBlock instructs the beacon node to use the components of the `SignedBlindedBeaconBlock` to construct
|
||||
// and publish a SignedBeaconBlock by swapping out the transactions_root for the corresponding full list of `transactions`.
|
||||
// The beacon node should broadcast a newly constructed SignedBeaconBlock to the beacon network, to be included in the
|
||||
|
||||
@@ -519,137 +519,141 @@ func TestGetBlockSSZV2(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetBlockAttestations(t *testing.T) {
|
||||
t.Run("ok", func(t *testing.T) {
|
||||
b := util.NewBeaconBlock()
|
||||
b.Block.Body.Attestations = []*eth.Attestation{
|
||||
{
|
||||
AggregationBits: bitfield.Bitlist{0x00},
|
||||
Data: ð.AttestationData{
|
||||
Slot: 123,
|
||||
CommitteeIndex: 123,
|
||||
BeaconBlockRoot: bytesutil.PadTo([]byte("root1"), 32),
|
||||
Source: ð.Checkpoint{
|
||||
Epoch: 123,
|
||||
Root: bytesutil.PadTo([]byte("root1"), 32),
|
||||
},
|
||||
Target: ð.Checkpoint{
|
||||
Epoch: 123,
|
||||
Root: bytesutil.PadTo([]byte("root1"), 32),
|
||||
},
|
||||
preElectraAtts := []*eth.Attestation{
|
||||
{
|
||||
AggregationBits: bitfield.Bitlist{0x00},
|
||||
Data: ð.AttestationData{
|
||||
Slot: 123,
|
||||
CommitteeIndex: 123,
|
||||
BeaconBlockRoot: bytesutil.PadTo([]byte("root1"), 32),
|
||||
Source: ð.Checkpoint{
|
||||
Epoch: 123,
|
||||
Root: bytesutil.PadTo([]byte("root1"), 32),
|
||||
},
|
||||
Signature: bytesutil.PadTo([]byte("sig1"), 96),
|
||||
},
|
||||
{
|
||||
AggregationBits: bitfield.Bitlist{0x01},
|
||||
Data: ð.AttestationData{
|
||||
Slot: 456,
|
||||
CommitteeIndex: 456,
|
||||
BeaconBlockRoot: bytesutil.PadTo([]byte("root2"), 32),
|
||||
Source: ð.Checkpoint{
|
||||
Epoch: 456,
|
||||
Root: bytesutil.PadTo([]byte("root2"), 32),
|
||||
},
|
||||
Target: ð.Checkpoint{
|
||||
Epoch: 456,
|
||||
Root: bytesutil.PadTo([]byte("root2"), 32),
|
||||
},
|
||||
Target: ð.Checkpoint{
|
||||
Epoch: 123,
|
||||
Root: bytesutil.PadTo([]byte("root1"), 32),
|
||||
},
|
||||
Signature: bytesutil.PadTo([]byte("sig2"), 96),
|
||||
},
|
||||
}
|
||||
sb, err := blocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb}
|
||||
mockChainService := &chainMock.ChainService{
|
||||
FinalizedRoots: map[[32]byte]bool{},
|
||||
}
|
||||
s := &Server{
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
Blocker: mockBlockFetcher,
|
||||
}
|
||||
Signature: bytesutil.PadTo([]byte("sig1"), 96),
|
||||
},
|
||||
{
|
||||
AggregationBits: bitfield.Bitlist{0x01},
|
||||
Data: ð.AttestationData{
|
||||
Slot: 456,
|
||||
CommitteeIndex: 456,
|
||||
BeaconBlockRoot: bytesutil.PadTo([]byte("root2"), 32),
|
||||
Source: ð.Checkpoint{
|
||||
Epoch: 456,
|
||||
Root: bytesutil.PadTo([]byte("root2"), 32),
|
||||
},
|
||||
Target: ð.Checkpoint{
|
||||
Epoch: 456,
|
||||
Root: bytesutil.PadTo([]byte("root2"), 32),
|
||||
},
|
||||
},
|
||||
Signature: bytesutil.PadTo([]byte("sig2"), 96),
|
||||
},
|
||||
}
|
||||
electraAtts := []*eth.AttestationElectra{
|
||||
{
|
||||
AggregationBits: bitfield.Bitlist{0x00},
|
||||
Data: ð.AttestationData{
|
||||
Slot: 123,
|
||||
CommitteeIndex: 123,
|
||||
BeaconBlockRoot: bytesutil.PadTo([]byte("root1"), 32),
|
||||
Source: ð.Checkpoint{
|
||||
Epoch: 123,
|
||||
Root: bytesutil.PadTo([]byte("root1"), 32),
|
||||
},
|
||||
Target: ð.Checkpoint{
|
||||
Epoch: 123,
|
||||
Root: bytesutil.PadTo([]byte("root1"), 32),
|
||||
},
|
||||
},
|
||||
Signature: bytesutil.PadTo([]byte("sig1"), 96),
|
||||
CommitteeBits: primitives.NewAttestationCommitteeBits(),
|
||||
},
|
||||
{
|
||||
AggregationBits: bitfield.Bitlist{0x01},
|
||||
Data: ð.AttestationData{
|
||||
Slot: 456,
|
||||
CommitteeIndex: 456,
|
||||
BeaconBlockRoot: bytesutil.PadTo([]byte("root2"), 32),
|
||||
Source: ð.Checkpoint{
|
||||
Epoch: 456,
|
||||
Root: bytesutil.PadTo([]byte("root2"), 32),
|
||||
},
|
||||
Target: ð.Checkpoint{
|
||||
Epoch: 456,
|
||||
Root: bytesutil.PadTo([]byte("root2"), 32),
|
||||
},
|
||||
},
|
||||
Signature: bytesutil.PadTo([]byte("sig2"), 96),
|
||||
CommitteeBits: primitives.NewAttestationCommitteeBits(),
|
||||
},
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v2/beacon/blocks/{block_id}/attestations", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
b := util.NewBeaconBlock()
|
||||
b.Block.Body.Attestations = preElectraAtts
|
||||
sb, err := blocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
|
||||
s.GetBlockAttestations(writer, request)
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
resp := &structs.GetBlockAttestationsResponse{}
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
||||
require.Equal(t, len(b.Block.Body.Attestations), len(resp.Data))
|
||||
atts := make([]*eth.Attestation, len(b.Block.Body.Attestations))
|
||||
for i, a := range resp.Data {
|
||||
atts[i], err = a.ToConsensus()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
assert.DeepEqual(t, b.Block.Body.Attestations, atts)
|
||||
})
|
||||
t.Run("execution optimistic", func(t *testing.T) {
|
||||
b := util.NewBeaconBlockBellatrix()
|
||||
sb, err := blocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
r, err := sb.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb}
|
||||
mockChainService := &chainMock.ChainService{
|
||||
OptimisticRoots: map[[32]byte]bool{r: true},
|
||||
FinalizedRoots: map[[32]byte]bool{},
|
||||
}
|
||||
s := &Server{
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
Blocker: mockBlockFetcher,
|
||||
}
|
||||
bb := util.NewBeaconBlockBellatrix()
|
||||
bb.Block.Body.Attestations = preElectraAtts
|
||||
bsb, err := blocks.NewSignedBeaconBlock(bb)
|
||||
require.NoError(t, err)
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v2/beacon/blocks/{block_id}/attestations", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
eb := util.NewBeaconBlockElectra()
|
||||
eb.Block.Body.Attestations = electraAtts
|
||||
esb, err := blocks.NewSignedBeaconBlock(eb)
|
||||
require.NoError(t, err)
|
||||
|
||||
s.GetBlockAttestations(writer, request)
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
resp := &structs.GetBlockAttestationsResponse{}
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
||||
assert.Equal(t, true, resp.ExecutionOptimistic)
|
||||
})
|
||||
t.Run("finalized", func(t *testing.T) {
|
||||
b := util.NewBeaconBlock()
|
||||
sb, err := blocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
r, err := sb.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb}
|
||||
t.Run("v1", func(t *testing.T) {
|
||||
t.Run("ok", func(t *testing.T) {
|
||||
mockChainService := &chainMock.ChainService{
|
||||
FinalizedRoots: map[[32]byte]bool{},
|
||||
}
|
||||
|
||||
t.Run("true", func(t *testing.T) {
|
||||
mockChainService := &chainMock.ChainService{FinalizedRoots: map[[32]byte]bool{r: true}}
|
||||
s := &Server{
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
Blocker: mockBlockFetcher,
|
||||
Blocker: &testutil.MockBlocker{BlockToReturn: sb},
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v2/beacon/blocks/{block_id}/attestations", nil)
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v1/beacon/blocks/{block_id}/attestations", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetBlockAttestations(writer, request)
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
|
||||
resp := &structs.GetBlockAttestationsResponse{}
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
||||
assert.Equal(t, true, resp.Finalized)
|
||||
require.Equal(t, len(b.Block.Body.Attestations), len(resp.Data))
|
||||
|
||||
atts := make([]*eth.Attestation, len(b.Block.Body.Attestations))
|
||||
for i, a := range resp.Data {
|
||||
atts[i], err = a.ToConsensus()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
assert.DeepEqual(t, b.Block.Body.Attestations, atts)
|
||||
})
|
||||
t.Run("false", func(t *testing.T) {
|
||||
mockChainService := &chainMock.ChainService{FinalizedRoots: map[[32]byte]bool{r: false}}
|
||||
t.Run("execution-optimistic", func(t *testing.T) {
|
||||
r, err := bsb.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
mockChainService := &chainMock.ChainService{
|
||||
OptimisticRoots: map[[32]byte]bool{r: true},
|
||||
FinalizedRoots: map[[32]byte]bool{},
|
||||
}
|
||||
s := &Server{
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
Blocker: mockBlockFetcher,
|
||||
Blocker: &testutil.MockBlocker{BlockToReturn: bsb},
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v2/beacon/blocks/{block_id}/attestations", nil)
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v1/beacon/blocks/{block_id}/attestations", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -658,7 +662,194 @@ func TestGetBlockAttestations(t *testing.T) {
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
resp := &structs.GetBlockAttestationsResponse{}
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
||||
assert.Equal(t, false, resp.ExecutionOptimistic)
|
||||
assert.Equal(t, true, resp.ExecutionOptimistic)
|
||||
})
|
||||
t.Run("finalized", func(t *testing.T) {
|
||||
r, err := sb.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("true", func(t *testing.T) {
|
||||
mockChainService := &chainMock.ChainService{FinalizedRoots: map[[32]byte]bool{r: true}}
|
||||
s := &Server{
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
Blocker: &testutil.MockBlocker{BlockToReturn: sb},
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v1/beacon/blocks/{block_id}/attestations", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetBlockAttestations(writer, request)
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
resp := &structs.GetBlockAttestationsResponse{}
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
||||
assert.Equal(t, true, resp.Finalized)
|
||||
})
|
||||
t.Run("false", func(t *testing.T) {
|
||||
mockChainService := &chainMock.ChainService{FinalizedRoots: map[[32]byte]bool{r: false}}
|
||||
s := &Server{
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
Blocker: &testutil.MockBlocker{BlockToReturn: sb},
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v1/beacon/blocks/{block_id}/attestations", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetBlockAttestations(writer, request)
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
resp := &structs.GetBlockAttestationsResponse{}
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
||||
assert.Equal(t, false, resp.ExecutionOptimistic)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("V2", func(t *testing.T) {
|
||||
t.Run("ok-pre-electra", func(t *testing.T) {
|
||||
mockChainService := &chainMock.ChainService{
|
||||
FinalizedRoots: map[[32]byte]bool{},
|
||||
}
|
||||
|
||||
s := &Server{
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
Blocker: &testutil.MockBlocker{BlockToReturn: sb},
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v2/beacon/blocks/{block_id}/attestations", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetBlockAttestationsV2(writer, request)
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
|
||||
resp := &structs.GetBlockAttestationsV2Response{}
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
||||
|
||||
var attStructs []structs.Attestation
|
||||
require.NoError(t, json.Unmarshal(resp.Data, &attStructs))
|
||||
|
||||
atts := make([]*eth.Attestation, len(attStructs))
|
||||
for i, attStruct := range attStructs {
|
||||
atts[i], err = attStruct.ToConsensus()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
assert.DeepEqual(t, b.Block.Body.Attestations, atts)
|
||||
assert.Equal(t, "phase0", resp.Version)
|
||||
})
|
||||
t.Run("ok-post-electra", func(t *testing.T) {
|
||||
mockChainService := &chainMock.ChainService{
|
||||
FinalizedRoots: map[[32]byte]bool{},
|
||||
}
|
||||
|
||||
s := &Server{
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
Blocker: &testutil.MockBlocker{BlockToReturn: esb},
|
||||
}
|
||||
|
||||
mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: esb}
|
||||
s.Blocker = mockBlockFetcher
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v2/beacon/blocks/{block_id}/attestations", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetBlockAttestationsV2(writer, request)
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
|
||||
resp := &structs.GetBlockAttestationsV2Response{}
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
||||
|
||||
var attStructs []structs.AttestationElectra
|
||||
require.NoError(t, json.Unmarshal(resp.Data, &attStructs))
|
||||
|
||||
atts := make([]*eth.AttestationElectra, len(attStructs))
|
||||
for i, attStruct := range attStructs {
|
||||
atts[i], err = attStruct.ToConsensus()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
assert.DeepEqual(t, eb.Block.Body.Attestations, atts)
|
||||
assert.Equal(t, "electra", resp.Version)
|
||||
})
|
||||
t.Run("execution-optimistic", func(t *testing.T) {
|
||||
r, err := bsb.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
mockChainService := &chainMock.ChainService{
|
||||
OptimisticRoots: map[[32]byte]bool{r: true},
|
||||
FinalizedRoots: map[[32]byte]bool{},
|
||||
}
|
||||
s := &Server{
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
Blocker: &testutil.MockBlocker{BlockToReturn: bsb},
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v2/beacon/blocks/{block_id}/attestations", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetBlockAttestationsV2(writer, request)
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
resp := &structs.GetBlockAttestationsV2Response{}
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
||||
assert.Equal(t, true, resp.ExecutionOptimistic)
|
||||
assert.Equal(t, "bellatrix", resp.Version)
|
||||
})
|
||||
t.Run("finalized", func(t *testing.T) {
|
||||
r, err := sb.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("true", func(t *testing.T) {
|
||||
mockChainService := &chainMock.ChainService{FinalizedRoots: map[[32]byte]bool{r: true}}
|
||||
s := &Server{
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
Blocker: &testutil.MockBlocker{BlockToReturn: sb},
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v2/beacon/blocks/{block_id}/attestations", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetBlockAttestationsV2(writer, request)
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
resp := &structs.GetBlockAttestationsV2Response{}
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
||||
assert.Equal(t, true, resp.Finalized)
|
||||
assert.Equal(t, "phase0", resp.Version)
|
||||
})
|
||||
t.Run("false", func(t *testing.T) {
|
||||
mockChainService := &chainMock.ChainService{FinalizedRoots: map[[32]byte]bool{r: false}}
|
||||
s := &Server{
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
Blocker: &testutil.MockBlocker{BlockToReturn: sb},
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v2/beacon/blocks/{block_id}/attestations", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetBlockAttestationsV2(writer, request)
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
resp := &structs.GetBlockAttestationsV2Response{}
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
||||
assert.Equal(t, false, resp.ExecutionOptimistic)
|
||||
assert.Equal(t, "phase0", resp.Version)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -63,7 +63,46 @@ func TestLightClientHandler_GetLightClientBootstrap_Altair(t *testing.T) {
|
||||
|
||||
require.NotNil(t, resp.Data.CurrentSyncCommittee)
|
||||
require.NotNil(t, resp.Data.CurrentSyncCommitteeBranch)
|
||||
}
|
||||
|
||||
func TestLightClientHandler_GetLightClientBootstrap_Bellatrix(t *testing.T) {
|
||||
l := util.NewTestLightClient(t).SetupTestBellatrix()
|
||||
|
||||
slot := l.State.Slot()
|
||||
stateRoot, err := l.State.HashTreeRoot(l.Ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
mockBlocker := &testutil.MockBlocker{BlockToReturn: l.Block}
|
||||
mockChainService := &mock.ChainService{Optimistic: true, Slot: &slot}
|
||||
s := &Server{
|
||||
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{
|
||||
slot: l.State,
|
||||
}},
|
||||
Blocker: mockBlocker,
|
||||
HeadFetcher: mockChainService,
|
||||
}
|
||||
request := httptest.NewRequest("GET", "http://foo.com/", nil)
|
||||
request.SetPathValue("block_root", hexutil.Encode(stateRoot[:]))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetLightClientBootstrap(writer, request)
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
var resp structs.LightClientBootstrapResponse
|
||||
err = json.Unmarshal(writer.Body.Bytes(), &resp)
|
||||
require.NoError(t, err)
|
||||
var respHeader structs.LightClientHeader
|
||||
err = json.Unmarshal(resp.Data.Header, &respHeader)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "bellatrix", resp.Version)
|
||||
|
||||
blockHeader, err := l.Block.Header()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, hexutil.Encode(blockHeader.Header.BodyRoot), respHeader.Beacon.BodyRoot)
|
||||
require.Equal(t, strconv.FormatUint(uint64(blockHeader.Header.Slot), 10), respHeader.Beacon.Slot)
|
||||
|
||||
require.NotNil(t, resp.Data.CurrentSyncCommittee)
|
||||
require.NotNil(t, resp.Data.CurrentSyncCommitteeBranch)
|
||||
}
|
||||
|
||||
func TestLightClientHandler_GetLightClientBootstrap_Capella(t *testing.T) {
|
||||
|
||||
@@ -69,6 +69,7 @@ type Flags struct {
|
||||
DisableResourceManager bool // Disables running the node with libp2p's resource manager.
|
||||
DisableStakinContractCheck bool // Disables check for deposit contract when proposing blocks
|
||||
|
||||
EnableHashtree bool // Enables usage of the hashtree library for hashing
|
||||
EnableVerboseSigVerification bool // EnableVerboseSigVerification specifies whether to verify individual signature if batch verification fails
|
||||
|
||||
PrepareAllPayloads bool // PrepareAllPayloads informs the engine to prepare a block on every slot.
|
||||
@@ -78,6 +79,8 @@ type Flags struct {
|
||||
SaveInvalidBlock bool // SaveInvalidBlock saves invalid block to temp.
|
||||
SaveInvalidBlob bool // SaveInvalidBlob saves invalid blob to temp.
|
||||
|
||||
EnableDiscoveryReboot bool // EnableDiscoveryReboot allows the node to have its local listener to be rebooted in the event of discovery issues.
|
||||
|
||||
// KeystoreImportDebounceInterval specifies the time duration the validator waits to reload new keys if they have
|
||||
// changed on disk. This feature is for advanced use cases only.
|
||||
KeystoreImportDebounceInterval time.Duration
|
||||
@@ -231,6 +234,10 @@ func ConfigureBeaconChain(ctx *cli.Context) error {
|
||||
logEnabled(enableFullSSZDataLogging)
|
||||
cfg.EnableFullSSZDataLogging = true
|
||||
}
|
||||
if ctx.IsSet(enableHashtree.Name) {
|
||||
logEnabled(enableHashtree)
|
||||
cfg.EnableHashtree = true
|
||||
}
|
||||
cfg.EnableVerboseSigVerification = true
|
||||
if ctx.IsSet(disableVerboseSigVerification.Name) {
|
||||
logEnabled(disableVerboseSigVerification)
|
||||
@@ -260,6 +267,10 @@ func ConfigureBeaconChain(ctx *cli.Context) error {
|
||||
logEnabled(DisableCommitteeAwarePacking)
|
||||
cfg.DisableCommitteeAwarePacking = true
|
||||
}
|
||||
if ctx.IsSet(EnableDiscoveryReboot.Name) {
|
||||
logEnabled(EnableDiscoveryReboot)
|
||||
cfg.EnableDiscoveryReboot = true
|
||||
}
|
||||
|
||||
cfg.AggregateIntervals = [3]time.Duration{aggregateFirstInterval.Value, aggregateSecondInterval.Value, aggregateThirdInterval.Value}
|
||||
Init(cfg)
|
||||
|
||||
@@ -135,6 +135,10 @@ var (
|
||||
Name: "enable-beacon-rest-api",
|
||||
Usage: "(Experimental): Enables of the beacon REST API when querying a beacon node.",
|
||||
}
|
||||
enableHashtree = &cli.BoolFlag{
|
||||
Name: "enable-hashtree",
|
||||
Usage: "(Experimental): Enables the hashthree hashing library.",
|
||||
}
|
||||
disableVerboseSigVerification = &cli.BoolFlag{
|
||||
Name: "disable-verbose-sig-verification",
|
||||
Usage: "Disables identifying invalid signatures if batch verification fails when processing block.",
|
||||
@@ -170,6 +174,10 @@ var (
|
||||
Name: "disable-committee-aware-packing",
|
||||
Usage: "Changes the attestation packing algorithm to one that is not aware of attesting committees.",
|
||||
}
|
||||
EnableDiscoveryReboot = &cli.BoolFlag{
|
||||
Name: "enable-discovery-reboot",
|
||||
Usage: "Experimental: Enables the discovery listener to rebooted in the event of connectivity issues.",
|
||||
}
|
||||
)
|
||||
|
||||
// devModeFlags holds list of flags that are set when development mode is on.
|
||||
@@ -211,6 +219,7 @@ var BeaconChainFlags = append(deprecatedBeaconFlags, append(deprecatedFlags, []c
|
||||
disablePeerScorer,
|
||||
disableBroadcastSlashingFlag,
|
||||
enableSlasherFlag,
|
||||
enableHashtree,
|
||||
enableHistoricalSpaceRepresentation,
|
||||
disableStakinContractCheck,
|
||||
SaveFullExecutionPayloads,
|
||||
@@ -227,6 +236,7 @@ var BeaconChainFlags = append(deprecatedBeaconFlags, append(deprecatedFlags, []c
|
||||
BlobSaveFsync,
|
||||
EnableQUIC,
|
||||
DisableCommitteeAwarePacking,
|
||||
EnableDiscoveryReboot,
|
||||
}...)...)
|
||||
|
||||
// E2EBeaconChainFlags contains a list of the beacon chain feature flags to be tested in E2E.
|
||||
|
||||
@@ -19,6 +19,7 @@ go_library(
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types:go_default_library",
|
||||
|
||||
@@ -3,6 +3,7 @@ package blocks
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/gohashtree"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/features"
|
||||
field_params "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
@@ -39,7 +40,11 @@ func VerifyKZGInclusionProof(blob ROBlob) error {
|
||||
return errInvalidBodyRoot
|
||||
}
|
||||
chunks := makeChunk(blob.KzgCommitment)
|
||||
gohashtree.HashChunks(chunks, chunks)
|
||||
if features.Get().EnableHashtree {
|
||||
hashtree.HashChunks(chunks, chunks)
|
||||
} else {
|
||||
gohashtree.HashChunks(chunks, chunks)
|
||||
}
|
||||
verified := trie.VerifyMerkleProof(root, chunks[0][:], blob.Index+KZGOffset, blob.CommitmentInclusionProof)
|
||||
if !verified {
|
||||
return errInvalidInclusionProof
|
||||
|
||||
@@ -5,7 +5,11 @@ go_library(
|
||||
srcs = ["hashtree.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/crypto/hash/htr",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["@com_github_prysmaticlabs_gohashtree//:go_default_library"],
|
||||
deps = [
|
||||
"//config/features:go_default_library",
|
||||
"@com_github_prysmaticlabs_gohashtree//:go_default_library",
|
||||
"@com_github_prysmaticlabs_hashtree//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
|
||||
@@ -5,13 +5,20 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/prysmaticlabs/gohashtree"
|
||||
"github.com/prysmaticlabs/hashtree"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/features"
|
||||
)
|
||||
|
||||
const minSliceSizeToParallelize = 5000
|
||||
|
||||
func hashParallel(inputList [][32]byte, outputList [][32]byte, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
err := gohashtree.Hash(outputList, inputList)
|
||||
var err error
|
||||
if features.Get().EnableHashtree {
|
||||
err = hashtree.Hash(outputList, inputList)
|
||||
} else {
|
||||
err = gohashtree.Hash(outputList, inputList)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -38,7 +45,12 @@ func VectorizedSha256(inputList [][32]byte) [][32]byte {
|
||||
for j := 0; j < n; j++ {
|
||||
go hashParallel(inputList[j*2*groupSize:(j+1)*2*groupSize], outputList[j*groupSize:], &wg)
|
||||
}
|
||||
err := gohashtree.Hash(outputList[n*groupSize:], inputList[n*2*groupSize:])
|
||||
var err error
|
||||
if features.Get().EnableHashtree {
|
||||
err = hashtree.Hash(outputList[n*groupSize:], inputList[n*2*groupSize:])
|
||||
} else {
|
||||
err = gohashtree.Hash(outputList[n*groupSize:], inputList[n*2*groupSize:])
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
10
deps.bzl
10
deps.bzl
@@ -4810,3 +4810,13 @@ def prysm_deps():
|
||||
build_file = "//third_party:blst/blst.BUILD",
|
||||
sha256 = "132124c074e59ead77e1828cc54b587a182ea67b781b72198e802af4696d78fe",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "com_github_prysmaticlabs_hashtree",
|
||||
urls = [
|
||||
"https://github.com/prysmaticlabs/hashtree/archive/refs/tags/v0.2.0.tar.gz",
|
||||
],
|
||||
strip_prefix = "hashtree-0.2.0",
|
||||
build_file = "//third_party:hashtree/hashtree.BUILD",
|
||||
sha256 = "26e6e14712040be81b5c9c08dc0ad2d48e03f2f9032806a76e98e438af10c1e0",
|
||||
)
|
||||
|
||||
@@ -344,6 +344,91 @@ func (l *TestLightClient) SetupTestAltair() *TestLightClient {
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *TestLightClient) SetupTestBellatrix() *TestLightClient {
|
||||
ctx := context.Background()
|
||||
|
||||
slot := primitives.Slot(params.BeaconConfig().BellatrixForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Add(1)
|
||||
|
||||
attestedState, err := NewBeaconStateBellatrix()
|
||||
require.NoError(l.T, err)
|
||||
err = attestedState.SetSlot(slot)
|
||||
require.NoError(l.T, err)
|
||||
|
||||
finalizedBlock, err := blocks.NewSignedBeaconBlock(NewBeaconBlockBellatrix())
|
||||
require.NoError(l.T, err)
|
||||
finalizedBlock.SetSlot(1)
|
||||
finalizedHeader, err := finalizedBlock.Header()
|
||||
require.NoError(l.T, err)
|
||||
finalizedRoot, err := finalizedHeader.Header.HashTreeRoot()
|
||||
require.NoError(l.T, err)
|
||||
|
||||
require.NoError(l.T, attestedState.SetFinalizedCheckpoint(ðpb.Checkpoint{
|
||||
Epoch: params.BeaconConfig().BellatrixForkEpoch - 10,
|
||||
Root: finalizedRoot[:],
|
||||
}))
|
||||
|
||||
parent := NewBeaconBlockBellatrix()
|
||||
parent.Block.Slot = slot
|
||||
|
||||
signedParent, err := blocks.NewSignedBeaconBlock(parent)
|
||||
require.NoError(l.T, err)
|
||||
|
||||
parentHeader, err := signedParent.Header()
|
||||
require.NoError(l.T, err)
|
||||
attestedHeader := parentHeader.Header
|
||||
|
||||
err = attestedState.SetLatestBlockHeader(attestedHeader)
|
||||
require.NoError(l.T, err)
|
||||
attestedStateRoot, err := attestedState.HashTreeRoot(ctx)
|
||||
require.NoError(l.T, err)
|
||||
|
||||
// get a new signed block so the root is updated with the new state root
|
||||
parent.Block.StateRoot = attestedStateRoot[:]
|
||||
signedParent, err = blocks.NewSignedBeaconBlock(parent)
|
||||
require.NoError(l.T, err)
|
||||
|
||||
state, err := NewBeaconStateBellatrix()
|
||||
require.NoError(l.T, err)
|
||||
err = state.SetSlot(slot)
|
||||
require.NoError(l.T, err)
|
||||
|
||||
parentRoot, err := signedParent.Block().HashTreeRoot()
|
||||
require.NoError(l.T, err)
|
||||
|
||||
block := NewBeaconBlockBellatrix()
|
||||
block.Block.Slot = slot
|
||||
block.Block.ParentRoot = parentRoot[:]
|
||||
|
||||
for i := uint64(0); i < params.BeaconConfig().MinSyncCommitteeParticipants; i++ {
|
||||
block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true)
|
||||
}
|
||||
|
||||
signedBlock, err := blocks.NewSignedBeaconBlock(block)
|
||||
require.NoError(l.T, err)
|
||||
|
||||
h, err := signedBlock.Header()
|
||||
require.NoError(l.T, err)
|
||||
|
||||
err = state.SetLatestBlockHeader(h.Header)
|
||||
require.NoError(l.T, err)
|
||||
stateRoot, err := state.HashTreeRoot(ctx)
|
||||
require.NoError(l.T, err)
|
||||
|
||||
// get a new signed block so the root is updated with the new state root
|
||||
block.Block.StateRoot = stateRoot[:]
|
||||
signedBlock, err = blocks.NewSignedBeaconBlock(block)
|
||||
require.NoError(l.T, err)
|
||||
|
||||
l.State = state
|
||||
l.AttestedState = attestedState
|
||||
l.Block = signedBlock
|
||||
l.Ctx = ctx
|
||||
l.FinalizedBlock = finalizedBlock
|
||||
l.AttestedBlock = signedParent
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *TestLightClient) SetupTestDeneb(blinded bool) *TestLightClient {
|
||||
ctx := context.Background()
|
||||
|
||||
|
||||
63
third_party/hashtree/hashtree.BUILD
vendored
Normal file
63
third_party/hashtree/hashtree.BUILD
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"bindings.go",
|
||||
"sha256_1_generic.go",
|
||||
"bindings_amd64.go",
|
||||
"bindings_arm64.go",
|
||||
"wrapper_arm64.s",
|
||||
"wrapper_linux_amd64.s",
|
||||
"wrapper_windows_amd64.s",
|
||||
],
|
||||
deps = select({
|
||||
"@io_bazel_rules_go//go/platform:amd64": ["@com_github_klauspost_cpuid_v2//:cpuid"],
|
||||
"@io_bazel_rules_go//go/platform:arm64": ["@com_github_klauspost_cpuid_v2//:cpuid"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
cgo = True,
|
||||
cdeps = [":hashtree"],
|
||||
importpath = "github.com/prysmaticlabs/hashtree",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"bindings_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
|
||||
# c-archive creates a statically-linked c-archive file instead of
|
||||
# a go test binary. So, it won't run, but it does compile.
|
||||
linkmode = "c-archive",
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "hashtree",
|
||||
srcs = [
|
||||
"src/hashtree.c",
|
||||
"src/sha256_sse_x1.S",
|
||||
"src/sha256_avx_x1.S",
|
||||
"src/sha256_avx_x4.S",
|
||||
"src/sha256_avx_x8.S",
|
||||
"src/sha256_avx_x16.S",
|
||||
"src/sha256_shani.S",
|
||||
"src/sha256_armv8_crypto.S",
|
||||
"src/sha256_armv8_neon_x1.S",
|
||||
"src/sha256_armv8_neon_x4.S",
|
||||
],
|
||||
hdrs = [
|
||||
"src/hashtree.h",
|
||||
],
|
||||
copts = [
|
||||
"-g -Wall -Werror -fpic",
|
||||
"-O2",
|
||||
"-Isrc",
|
||||
"-fno-integrated-as",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
linkstatic = True,
|
||||
)
|
||||
Reference in New Issue
Block a user