mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-22 19:40:37 +00:00
Add Gossip Handler For BLS To Execution Changes (#11690)
This commit is contained in:
parent
f9e0d4b13a
commit
a23a5052bc
@ -67,12 +67,29 @@ func ProcessBLSToExecutionChanges(
|
||||
// + address_change.to_execution_address
|
||||
// )
|
||||
func processBLSToExecutionChange(st state.BeaconState, signed *ethpb.SignedBLSToExecutionChange) (state.BeaconState, error) {
|
||||
// Checks that the message passes the validation conditions.
|
||||
val, err := ValidateBLSToExecutionChange(st, signed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
message := signed.Message
|
||||
newCredentials := make([]byte, executionToBLSPadding)
|
||||
newCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
||||
val.WithdrawalCredentials = append(newCredentials, message.ToExecutionAddress...)
|
||||
err = st.UpdateValidatorAtIndex(message.ValidatorIndex, val)
|
||||
return st, err
|
||||
}
|
||||
|
||||
// ValidateBLSToExecutionChange validates the execution change message against the state and returns the
|
||||
// validator referenced by the message.
|
||||
func ValidateBLSToExecutionChange(st state.ReadOnlyBeaconState, signed *ethpb.SignedBLSToExecutionChange) (*ethpb.Validator, error) {
|
||||
if signed == nil {
|
||||
return st, errNilSignedWithdrawalMessage
|
||||
return nil, errNilSignedWithdrawalMessage
|
||||
}
|
||||
message := signed.Message
|
||||
if message == nil {
|
||||
return st, errNilWithdrawalMessage
|
||||
return nil, errNilWithdrawalMessage
|
||||
}
|
||||
|
||||
val, err := st.ValidatorAtIndex(message.ValidatorIndex)
|
||||
@ -91,12 +108,7 @@ func processBLSToExecutionChange(st state.BeaconState, signed *ethpb.SignedBLSTo
|
||||
if !bytes.Equal(digest[1:], cred[1:]) {
|
||||
return nil, errInvalidWithdrawalCredentials
|
||||
}
|
||||
|
||||
newCredentials := make([]byte, executionToBLSPadding)
|
||||
newCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
||||
val.WithdrawalCredentials = append(newCredentials, message.ToExecutionAddress...)
|
||||
err = st.UpdateValidatorAtIndex(message.ValidatorIndex, val)
|
||||
return st, err
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func ProcessWithdrawals(st state.BeaconState, withdrawals []*enginev1.Withdrawal) (state.BeaconState, error) {
|
||||
|
@ -70,6 +70,47 @@ func TestProcessBLSToExecutionChange(t *testing.T) {
|
||||
|
||||
require.DeepEqual(t, message.ToExecutionAddress, val.WithdrawalCredentials[12:])
|
||||
})
|
||||
t.Run("happy case only validation", func(t *testing.T) {
|
||||
priv, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
pubkey := priv.PublicKey().Marshal()
|
||||
|
||||
message := ðpb.BLSToExecutionChange{
|
||||
ToExecutionAddress: []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13},
|
||||
ValidatorIndex: 0,
|
||||
FromBlsPubkey: pubkey,
|
||||
}
|
||||
|
||||
hashFn := ssz.NewHasherFunc(hash.CustomSHA256Hasher())
|
||||
digest := hashFn.Hash(pubkey)
|
||||
digest[0] = params.BeaconConfig().BLSWithdrawalPrefixByte
|
||||
|
||||
registry := []*ethpb.Validator{
|
||||
{
|
||||
WithdrawalCredentials: digest[:],
|
||||
},
|
||||
}
|
||||
st, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Validators: registry,
|
||||
Fork: ðpb.Fork{
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
},
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch * 5,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
signature, err := signing.ComputeDomainAndSign(st, time.CurrentEpoch(st), message, params.BeaconConfig().DomainBLSToExecutionChange, priv)
|
||||
require.NoError(t, err)
|
||||
|
||||
signed := ðpb.SignedBLSToExecutionChange{
|
||||
Message: message,
|
||||
Signature: signature,
|
||||
}
|
||||
val, err := blocks.ValidateBLSToExecutionChange(st, signed)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, digest[:], val.WithdrawalCredentials)
|
||||
})
|
||||
|
||||
t.Run("non-existent validator", func(t *testing.T) {
|
||||
priv, err := bls.RandKey()
|
||||
|
@ -32,6 +32,7 @@ go_library(
|
||||
"//beacon-chain/monitor:go_default_library",
|
||||
"//beacon-chain/node/registration:go_default_library",
|
||||
"//beacon-chain/operations/attestations:go_default_library",
|
||||
"//beacon-chain/operations/blstoexec:go_default_library",
|
||||
"//beacon-chain/operations/slashings:go_default_library",
|
||||
"//beacon-chain/operations/synccommittee:go_default_library",
|
||||
"//beacon-chain/operations/voluntaryexits:go_default_library",
|
||||
|
@ -34,6 +34,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/monitor"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/node/registration"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/attestations"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/blstoexec"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/slashings"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/synccommittee"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/voluntaryexits"
|
||||
@ -94,6 +95,7 @@ type BeaconNode struct {
|
||||
exitPool voluntaryexits.PoolManager
|
||||
slashingsPool slashings.PoolManager
|
||||
syncCommitteePool synccommittee.Pool
|
||||
blsToExecPool blstoexec.PoolManager
|
||||
depositCache *depositcache.DepositCache
|
||||
proposerIdsCache *cache.ProposerPayloadIDsCache
|
||||
stateFeed *event.Feed
|
||||
@ -171,6 +173,7 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
|
||||
exitPool: voluntaryexits.NewPool(),
|
||||
slashingsPool: slashings.NewPool(),
|
||||
syncCommitteePool: synccommittee.NewPool(),
|
||||
blsToExecPool: blstoexec.NewPool(),
|
||||
slasherBlockHeadersFeed: new(event.Feed),
|
||||
slasherAttestationsFeed: new(event.Feed),
|
||||
serviceFlagOpts: &serviceFlagOpts{},
|
||||
@ -674,6 +677,7 @@ func (b *BeaconNode) registerSyncService() error {
|
||||
regularsync.WithExitPool(b.exitPool),
|
||||
regularsync.WithSlashingPool(b.slashingsPool),
|
||||
regularsync.WithSyncCommsPool(b.syncCommitteePool),
|
||||
regularsync.WithBlsToExecPool(b.blsToExecPool),
|
||||
regularsync.WithStateGen(b.stateGen),
|
||||
regularsync.WithSlasherAttestationsFeed(b.slasherAttestationsFeed),
|
||||
regularsync.WithSlasherBlockHeadersFeed(b.slasherBlockHeadersFeed),
|
||||
|
@ -17,6 +17,7 @@ type PoolManager interface {
|
||||
BLSToExecChangesForInclusion() ([]*ethpb.SignedBLSToExecutionChange, error)
|
||||
InsertBLSToExecChange(change *ethpb.SignedBLSToExecutionChange)
|
||||
MarkIncluded(change *ethpb.SignedBLSToExecutionChange) error
|
||||
ValidatorExists(idx types.ValidatorIndex) bool
|
||||
}
|
||||
|
||||
// Pool is a concrete implementation of PoolManager.
|
||||
@ -107,3 +108,14 @@ func (p *Pool) MarkIncluded(change *ethpb.SignedBLSToExecutionChange) error {
|
||||
p.pending.Remove(node)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidatorExists checks if the bls to execution change object exists
|
||||
// for that particular validator.
|
||||
func (p *Pool) ValidatorExists(idx types.ValidatorIndex) bool {
|
||||
p.lock.RLock()
|
||||
defer p.lock.RUnlock()
|
||||
|
||||
node := p.m[idx]
|
||||
|
||||
return node != nil
|
||||
}
|
||||
|
@ -256,3 +256,76 @@ func TestMarkIncluded(t *testing.T) {
|
||||
assert.NotNil(t, pool.m[1])
|
||||
})
|
||||
}
|
||||
|
||||
func TestValidatorExists(t *testing.T) {
|
||||
t.Run("no validators in pool", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
assert.Equal(t, false, pool.ValidatorExists(0))
|
||||
})
|
||||
t.Run("validator added to pool", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
change := ð.SignedBLSToExecutionChange{
|
||||
Message: ð.BLSToExecutionChange{
|
||||
ValidatorIndex: types.ValidatorIndex(0),
|
||||
}}
|
||||
pool.InsertBLSToExecChange(change)
|
||||
assert.Equal(t, true, pool.ValidatorExists(0))
|
||||
})
|
||||
t.Run("multiple validators added to pool", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
change := ð.SignedBLSToExecutionChange{
|
||||
Message: ð.BLSToExecutionChange{
|
||||
ValidatorIndex: types.ValidatorIndex(0),
|
||||
}}
|
||||
pool.InsertBLSToExecChange(change)
|
||||
change = ð.SignedBLSToExecutionChange{
|
||||
Message: ð.BLSToExecutionChange{
|
||||
ValidatorIndex: types.ValidatorIndex(10),
|
||||
}}
|
||||
pool.InsertBLSToExecChange(change)
|
||||
change = ð.SignedBLSToExecutionChange{
|
||||
Message: ð.BLSToExecutionChange{
|
||||
ValidatorIndex: types.ValidatorIndex(30),
|
||||
}}
|
||||
pool.InsertBLSToExecChange(change)
|
||||
|
||||
assert.Equal(t, true, pool.ValidatorExists(0))
|
||||
assert.Equal(t, true, pool.ValidatorExists(10))
|
||||
assert.Equal(t, true, pool.ValidatorExists(30))
|
||||
})
|
||||
t.Run("validator added and then removed", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
change := ð.SignedBLSToExecutionChange{
|
||||
Message: ð.BLSToExecutionChange{
|
||||
ValidatorIndex: types.ValidatorIndex(0),
|
||||
}}
|
||||
pool.InsertBLSToExecChange(change)
|
||||
require.NoError(t, pool.MarkIncluded(change))
|
||||
assert.Equal(t, false, pool.ValidatorExists(0))
|
||||
})
|
||||
t.Run("multiple validators added to pool and removed", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
firstChange := ð.SignedBLSToExecutionChange{
|
||||
Message: ð.BLSToExecutionChange{
|
||||
ValidatorIndex: types.ValidatorIndex(0),
|
||||
}}
|
||||
pool.InsertBLSToExecChange(firstChange)
|
||||
secondChange := ð.SignedBLSToExecutionChange{
|
||||
Message: ð.BLSToExecutionChange{
|
||||
ValidatorIndex: types.ValidatorIndex(10),
|
||||
}}
|
||||
pool.InsertBLSToExecChange(secondChange)
|
||||
thirdChange := ð.SignedBLSToExecutionChange{
|
||||
Message: ð.BLSToExecutionChange{
|
||||
ValidatorIndex: types.ValidatorIndex(30),
|
||||
}}
|
||||
pool.InsertBLSToExecChange(thirdChange)
|
||||
|
||||
assert.NoError(t, pool.MarkIncluded(firstChange))
|
||||
assert.NoError(t, pool.MarkIncluded(thirdChange))
|
||||
|
||||
assert.Equal(t, false, pool.ValidatorExists(0))
|
||||
assert.Equal(t, true, pool.ValidatorExists(10))
|
||||
assert.Equal(t, false, pool.ValidatorExists(30))
|
||||
})
|
||||
}
|
||||
|
@ -41,6 +41,9 @@ const (
|
||||
// voluntaryExitWeight specifies the scoring weight that we apply to
|
||||
// our voluntary exit topic.
|
||||
voluntaryExitWeight = 0.05
|
||||
// blsToExecutionChangeWeight specifies the scoring weight that we apply to
|
||||
// our bls to execution topic.
|
||||
blsToExecutionChangeWeight = 0.05
|
||||
|
||||
// maxInMeshScore describes the max score a peer can attain from being in the mesh.
|
||||
maxInMeshScore = 10
|
||||
@ -116,6 +119,8 @@ func (s *Service) topicScoreParams(topic string) (*pubsub.TopicScoreParams, erro
|
||||
return defaultProposerSlashingTopicParams(), nil
|
||||
case strings.Contains(topic, GossipAttesterSlashingMessage):
|
||||
return defaultAttesterSlashingTopicParams(), nil
|
||||
case strings.Contains(topic, GossipBlsToExecutionChangeMessage):
|
||||
return defaultBlsToExecutionChangeTopicParams(), nil
|
||||
default:
|
||||
return nil, errors.Errorf("unrecognized topic provided for parameter registration: %s", topic)
|
||||
}
|
||||
@ -473,6 +478,28 @@ func defaultVoluntaryExitTopicParams() *pubsub.TopicScoreParams {
|
||||
}
|
||||
}
|
||||
|
||||
func defaultBlsToExecutionChangeTopicParams() *pubsub.TopicScoreParams {
|
||||
return &pubsub.TopicScoreParams{
|
||||
TopicWeight: blsToExecutionChangeWeight,
|
||||
TimeInMeshWeight: maxInMeshScore / inMeshCap(),
|
||||
TimeInMeshQuantum: inMeshTime(),
|
||||
TimeInMeshCap: inMeshCap(),
|
||||
FirstMessageDeliveriesWeight: 2,
|
||||
FirstMessageDeliveriesDecay: scoreDecay(oneHundredEpochs),
|
||||
FirstMessageDeliveriesCap: 5,
|
||||
MeshMessageDeliveriesWeight: 0,
|
||||
MeshMessageDeliveriesDecay: 0,
|
||||
MeshMessageDeliveriesCap: 0,
|
||||
MeshMessageDeliveriesThreshold: 0,
|
||||
MeshMessageDeliveriesWindow: 0,
|
||||
MeshMessageDeliveriesActivation: 0,
|
||||
MeshFailurePenaltyWeight: 0,
|
||||
MeshFailurePenaltyDecay: 0,
|
||||
InvalidMessageDeliveriesWeight: -2000,
|
||||
InvalidMessageDeliveriesDecay: scoreDecay(invalidDecayPeriod),
|
||||
}
|
||||
}
|
||||
|
||||
func oneSlotDuration() time.Duration {
|
||||
return time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second
|
||||
}
|
||||
@ -531,7 +558,7 @@ func scoreByWeight(weight, threshold float64) float64 {
|
||||
func maxScore() float64 {
|
||||
totalWeight := beaconBlockWeight + aggregateWeight + syncContributionWeight +
|
||||
attestationTotalWeight + syncCommitteesTotalWeight + attesterSlashingWeight +
|
||||
proposerSlashingWeight + voluntaryExitWeight
|
||||
proposerSlashingWeight + voluntaryExitWeight + blsToExecutionChangeWeight
|
||||
return (maxInMeshScore + maxFirstDeliveryScore) * totalWeight
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ var gossipTopicMappings = map[string]proto.Message{
|
||||
AggregateAndProofSubnetTopicFormat: ðpb.SignedAggregateAttestationAndProof{},
|
||||
SyncContributionAndProofSubnetTopicFormat: ðpb.SignedContributionAndProof{},
|
||||
SyncCommitteeSubnetTopicFormat: ðpb.SyncCommitteeMessage{},
|
||||
BlsToExecutionChangeSubnetTopicFormat: ðpb.SignedBLSToExecutionChange{},
|
||||
}
|
||||
|
||||
// GossipTopicMappings is a function to return the assigned data type
|
||||
|
@ -26,6 +26,8 @@ const (
|
||||
GossipAggregateAndProofMessage = "beacon_aggregate_and_proof"
|
||||
// GossipContributionAndProofMessage is the name for the sync contribution and proof message type.
|
||||
GossipContributionAndProofMessage = "sync_committee_contribution_and_proof"
|
||||
// GossipBlsToExecutionChangeMessage is the name for the bls to execution change message type.
|
||||
GossipBlsToExecutionChangeMessage = "bls_to_execution_change"
|
||||
|
||||
// Topic Formats
|
||||
//
|
||||
@ -45,4 +47,6 @@ const (
|
||||
AggregateAndProofSubnetTopicFormat = GossipProtocolAndDigest + GossipAggregateAndProofMessage
|
||||
// SyncContributionAndProofSubnetTopicFormat is the topic format for the sync aggregate and proof subnet.
|
||||
SyncContributionAndProofSubnetTopicFormat = GossipProtocolAndDigest + GossipContributionAndProofMessage
|
||||
// BlsToExecutionChangeSubnetTopicFormat is the topic format for the bls to execution change subnet.
|
||||
BlsToExecutionChangeSubnetTopicFormat = GossipProtocolAndDigest + GossipBlsToExecutionChangeMessage
|
||||
)
|
||||
|
@ -31,6 +31,7 @@ go_library(
|
||||
"subscriber_beacon_aggregate_proof.go",
|
||||
"subscriber_beacon_attestation.go",
|
||||
"subscriber_beacon_blocks.go",
|
||||
"subscriber_bls_to_execution_change.go",
|
||||
"subscriber_handlers.go",
|
||||
"subscriber_sync_committee_message.go",
|
||||
"subscriber_sync_contribution_proof.go",
|
||||
@ -40,6 +41,7 @@ go_library(
|
||||
"validate_attester_slashing.go",
|
||||
"validate_beacon_attestation.go",
|
||||
"validate_beacon_blocks.go",
|
||||
"validate_bls_to_execution_change.go",
|
||||
"validate_proposer_slashing.go",
|
||||
"validate_sync_committee_message.go",
|
||||
"validate_sync_contribution_proof.go",
|
||||
@ -71,6 +73,7 @@ go_library(
|
||||
"//beacon-chain/db/filters:go_default_library",
|
||||
"//beacon-chain/execution:go_default_library",
|
||||
"//beacon-chain/operations/attestations:go_default_library",
|
||||
"//beacon-chain/operations/blstoexec:go_default_library",
|
||||
"//beacon-chain/operations/slashings:go_default_library",
|
||||
"//beacon-chain/operations/synccommittee:go_default_library",
|
||||
"//beacon-chain/operations/voluntaryexits:go_default_library",
|
||||
@ -158,6 +161,7 @@ go_test(
|
||||
"validate_attester_slashing_test.go",
|
||||
"validate_beacon_attestation_test.go",
|
||||
"validate_beacon_blocks_test.go",
|
||||
"validate_bls_to_execution_change_test.go",
|
||||
"validate_proposer_slashing_test.go",
|
||||
"validate_sync_committee_message_test.go",
|
||||
"validate_sync_contribution_proof_test.go",
|
||||
@ -185,6 +189,7 @@ go_test(
|
||||
"//beacon-chain/execution/testing:go_default_library",
|
||||
"//beacon-chain/forkchoice/doubly-linked-tree:go_default_library",
|
||||
"//beacon-chain/operations/attestations:go_default_library",
|
||||
"//beacon-chain/operations/blstoexec:go_default_library",
|
||||
"//beacon-chain/operations/slashings:go_default_library",
|
||||
"//beacon-chain/p2p:go_default_library",
|
||||
"//beacon-chain/p2p/encoder:go_default_library",
|
||||
|
@ -49,26 +49,16 @@ func (s *Service) registerForUpcomingFork(currEpoch types.Epoch) error {
|
||||
// will subscribe the new topics in advance.
|
||||
if isNextForkEpoch {
|
||||
nextEpoch := currEpoch + 1
|
||||
switch nextEpoch {
|
||||
case params.BeaconConfig().AltairForkEpoch:
|
||||
digest, err := forks.ForkDigestFromEpoch(nextEpoch, genRoot[:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not retrieve fork digest")
|
||||
}
|
||||
if s.subHandler.digestExists(digest) {
|
||||
return nil
|
||||
}
|
||||
s.registerSubscribers(nextEpoch, digest)
|
||||
digest, err := forks.ForkDigestFromEpoch(nextEpoch, genRoot[:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not retrieve fork digest")
|
||||
}
|
||||
if s.subHandler.digestExists(digest) {
|
||||
return nil
|
||||
}
|
||||
s.registerSubscribers(nextEpoch, digest)
|
||||
if nextEpoch == params.BeaconConfig().AltairForkEpoch {
|
||||
s.registerRPCHandlersAltair()
|
||||
case params.BeaconConfig().BellatrixForkEpoch:
|
||||
digest, err := forks.ForkDigestFromEpoch(nextEpoch, genRoot[:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not retrieve fork digest")
|
||||
}
|
||||
if s.subHandler.digestExists(digest) {
|
||||
return nil
|
||||
}
|
||||
s.registerSubscribers(nextEpoch, digest)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -109,9 +99,7 @@ func (s *Service) deregisterFromPastFork(currEpoch types.Epoch) error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to determine previous epoch fork data")
|
||||
}
|
||||
|
||||
switch prevFork.Epoch {
|
||||
case params.BeaconConfig().GenesisEpoch:
|
||||
if prevFork.Epoch == params.BeaconConfig().GenesisEpoch {
|
||||
s.unregisterPhase0Handlers()
|
||||
}
|
||||
// Run through all our current active topics and see
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/attestations"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/blstoexec"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/slashings"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/synccommittee"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/voluntaryexits"
|
||||
@ -66,6 +67,13 @@ func WithSyncCommsPool(syncCommsPool synccommittee.Pool) Option {
|
||||
}
|
||||
}
|
||||
|
||||
func WithBlsToExecPool(blsToExecPool blstoexec.PoolManager) Option {
|
||||
return func(s *Service) error {
|
||||
s.cfg.blsToExecPool = blsToExecPool
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithChainService(chain blockchainService) Option {
|
||||
return func(s *Service) error {
|
||||
s.cfg.chain = chain
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/execution"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/attestations"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/blstoexec"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/slashings"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/synccommittee"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/voluntaryexits"
|
||||
@ -75,6 +76,7 @@ type config struct {
|
||||
exitPool voluntaryexits.PoolManager
|
||||
slashingPool slashings.PoolManager
|
||||
syncCommsPool synccommittee.Pool
|
||||
blsToExecPool blstoexec.PoolManager
|
||||
chain blockchainService
|
||||
initialSync Checker
|
||||
stateNotifier statefeed.Notifier
|
||||
|
@ -120,6 +120,16 @@ func (s *Service) registerSubscribers(epoch types.Epoch, digest [4]byte) {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// New Gossip Topic in Capella
|
||||
if epoch >= params.BeaconConfig().CapellaForkEpoch {
|
||||
s.subscribe(
|
||||
p2p.BlsToExecutionChangeSubnetTopicFormat,
|
||||
s.validateBlsToExecutionChange,
|
||||
s.blsToExecutionChangeSubscriber,
|
||||
digest,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// subscribe to a given topic with a given validator and subscription handler.
|
||||
|
18
beacon-chain/sync/subscriber_bls_to_execution_change.go
Normal file
18
beacon-chain/sync/subscriber_bls_to_execution_change.go
Normal file
@ -0,0 +1,18 @@
|
||||
package sync
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func (s *Service) blsToExecutionChangeSubscriber(ctx context.Context, msg proto.Message) error {
|
||||
blsMsg, ok := msg.(*ethpb.SignedBLSToExecutionChange)
|
||||
if !ok {
|
||||
return errors.Errorf("incorrect type of message received, wanted %T but got %T", ðpb.SignedBLSToExecutionChange{}, msg)
|
||||
}
|
||||
s.cfg.blsToExecPool.InsertBLSToExecChange(blsMsg)
|
||||
return nil
|
||||
}
|
64
beacon-chain/sync/validate_bls_to_execution_change.go
Normal file
64
beacon-chain/sync/validate_bls_to_execution_change.go
Normal file
@ -0,0 +1,64 @@
|
||||
package sync
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v3/monitoring/tracing"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
func (s *Service) validateBlsToExecutionChange(ctx context.Context, pid peer.ID, msg *pubsub.Message) (pubsub.ValidationResult, error) {
|
||||
// Validation runs on publish (not just subscriptions), so we should approve any message from
|
||||
// ourselves.
|
||||
if pid == s.cfg.p2p.PeerID() {
|
||||
return pubsub.ValidationAccept, nil
|
||||
}
|
||||
|
||||
// The head state will be too far away to validate any execution change.
|
||||
if s.cfg.initialSync.Syncing() {
|
||||
return pubsub.ValidationIgnore, nil
|
||||
}
|
||||
|
||||
ctx, span := trace.StartSpan(ctx, "sync.validateBlsToExecutionChange")
|
||||
defer span.End()
|
||||
|
||||
m, err := s.decodePubsubMessage(msg)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return pubsub.ValidationReject, err
|
||||
}
|
||||
|
||||
blsChange, ok := m.(*ethpb.SignedBLSToExecutionChange)
|
||||
if !ok {
|
||||
return pubsub.ValidationReject, errWrongMessage
|
||||
}
|
||||
|
||||
// Check that the validator hasn't submitted a previous execution change.
|
||||
if s.cfg.blsToExecPool.ValidatorExists(blsChange.Message.ValidatorIndex) {
|
||||
return pubsub.ValidationIgnore, nil
|
||||
}
|
||||
st, err := s.cfg.chain.HeadState(ctx)
|
||||
if err != nil {
|
||||
return pubsub.ValidationIgnore, err
|
||||
}
|
||||
// Validate that the execution change object is valid.
|
||||
_, err = blocks.ValidateBLSToExecutionChange(st, blsChange)
|
||||
if err != nil {
|
||||
return pubsub.ValidationReject, err
|
||||
}
|
||||
// Validate the signature of the message using our batch gossip verifier.
|
||||
sigBatch, err := blocks.BLSChangesSignatureBatch(ctx, st, []*ethpb.SignedBLSToExecutionChange{blsChange})
|
||||
if err != nil {
|
||||
return pubsub.ValidationReject, err
|
||||
}
|
||||
res, err := s.validateWithBatchVerifier(ctx, "bls to execution change", sigBatch)
|
||||
if res != pubsub.ValidationAccept {
|
||||
return res, err
|
||||
}
|
||||
msg.ValidatorData = blsChange // Used in downstream subscriber
|
||||
return pubsub.ValidationAccept, nil
|
||||
}
|
389
beacon-chain/sync/validate_bls_to_execution_change_test.go
Normal file
389
beacon-chain/sync/validate_bls_to_execution_change_test.go
Normal file
@ -0,0 +1,389 @@
|
||||
package sync
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
mockChain "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain/testing"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
|
||||
testingdb "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v3/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/blstoexec"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p/encoder"
|
||||
mockp2p "github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p/testing"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
|
||||
mockSync "github.com/prysmaticlabs/prysm/v3/beacon-chain/sync/initial-sync/testing"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/util"
|
||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||
)
|
||||
|
||||
func TestService_ValidateBlsToExecutionChange(t *testing.T) {
|
||||
beaconDB := testingdb.SetupDB(t)
|
||||
defaultTopic := p2p.BlsToExecutionChangeSubnetTopicFormat
|
||||
fakeDigest := []byte{0xAB, 0x00, 0xCC, 0x9E}
|
||||
wantedExecAddress := []byte{0xd8, 0xdA, 0x6B, 0xF2, 0x69, 0x64, 0xaF, 0x9D, 0x7e, 0xEd, 0x9e, 0x03, 0xE5, 0x34, 0x15, 0xD3, 0x7a, 0xA9, 0x60, 0x45}
|
||||
defaultTopic = defaultTopic + "/" + encoder.ProtocolSuffixSSZSnappy
|
||||
chainService := &mockChain.ChainService{
|
||||
Genesis: time.Now(),
|
||||
ValidatorsRoot: [32]byte{'A'},
|
||||
}
|
||||
emptySig := [96]byte{}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
pid peer.ID
|
||||
msg *ethpb.SignedBLSToExecutionChange
|
||||
topic string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
svc *Service
|
||||
setupSvc func(s *Service, msg *ethpb.SignedBLSToExecutionChange, topic string) (*Service, string)
|
||||
args args
|
||||
want pubsub.ValidationResult
|
||||
}{
|
||||
{
|
||||
name: "Is syncing",
|
||||
svc: NewService(context.Background(),
|
||||
WithP2P(mockp2p.NewTestP2P(t)),
|
||||
WithInitialSync(&mockSync.Sync{IsSyncing: true}),
|
||||
WithChainService(chainService),
|
||||
WithStateNotifier(chainService.StateNotifier()),
|
||||
WithOperationNotifier(chainService.OperationNotifier()),
|
||||
),
|
||||
setupSvc: func(s *Service, msg *ethpb.SignedBLSToExecutionChange, topic string) (*Service, string) {
|
||||
s.cfg.stateGen = stategen.New(beaconDB, doublylinkedtree.New())
|
||||
s.cfg.beaconDB = beaconDB
|
||||
s.initCaches()
|
||||
return s, topic
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
pid: "random",
|
||||
topic: "junk",
|
||||
msg: ðpb.SignedBLSToExecutionChange{
|
||||
Message: ðpb.BLSToExecutionChange{
|
||||
ValidatorIndex: 0,
|
||||
FromBlsPubkey: make([]byte, 48),
|
||||
ToExecutionAddress: make([]byte, 20),
|
||||
},
|
||||
Signature: emptySig[:],
|
||||
}},
|
||||
want: pubsub.ValidationIgnore,
|
||||
},
|
||||
{
|
||||
name: "Bad Topic",
|
||||
svc: NewService(context.Background(),
|
||||
WithP2P(mockp2p.NewTestP2P(t)),
|
||||
WithInitialSync(&mockSync.Sync{IsSyncing: false}),
|
||||
WithChainService(chainService),
|
||||
WithStateNotifier(chainService.StateNotifier()),
|
||||
WithOperationNotifier(chainService.OperationNotifier()),
|
||||
),
|
||||
setupSvc: func(s *Service, msg *ethpb.SignedBLSToExecutionChange, topic string) (*Service, string) {
|
||||
s.cfg.stateGen = stategen.New(beaconDB, doublylinkedtree.New())
|
||||
s.cfg.beaconDB = beaconDB
|
||||
s.initCaches()
|
||||
return s, topic
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
pid: "random",
|
||||
topic: "junk",
|
||||
msg: ðpb.SignedBLSToExecutionChange{
|
||||
Message: ðpb.BLSToExecutionChange{
|
||||
ValidatorIndex: 0,
|
||||
FromBlsPubkey: make([]byte, 48),
|
||||
ToExecutionAddress: make([]byte, 20),
|
||||
},
|
||||
Signature: emptySig[:],
|
||||
}},
|
||||
want: pubsub.ValidationReject,
|
||||
},
|
||||
{
|
||||
name: "Already Seen Message",
|
||||
svc: NewService(context.Background(),
|
||||
WithP2P(mockp2p.NewTestP2P(t)),
|
||||
WithInitialSync(&mockSync.Sync{IsSyncing: false}),
|
||||
WithChainService(chainService),
|
||||
WithStateNotifier(chainService.StateNotifier()),
|
||||
WithOperationNotifier(chainService.OperationNotifier()),
|
||||
WithBlsToExecPool(blstoexec.NewPool()),
|
||||
),
|
||||
setupSvc: func(s *Service, msg *ethpb.SignedBLSToExecutionChange, topic string) (*Service, string) {
|
||||
s.cfg.stateGen = stategen.New(beaconDB, doublylinkedtree.New())
|
||||
s.cfg.beaconDB = beaconDB
|
||||
s.initCaches()
|
||||
s.cfg.blsToExecPool.InsertBLSToExecChange(ðpb.SignedBLSToExecutionChange{
|
||||
Message: ðpb.BLSToExecutionChange{
|
||||
ValidatorIndex: 10,
|
||||
FromBlsPubkey: make([]byte, 48),
|
||||
ToExecutionAddress: make([]byte, 20),
|
||||
},
|
||||
Signature: emptySig[:],
|
||||
})
|
||||
return s, topic
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
pid: "random",
|
||||
topic: fmt.Sprintf(defaultTopic, fakeDigest),
|
||||
msg: ðpb.SignedBLSToExecutionChange{
|
||||
Message: ðpb.BLSToExecutionChange{
|
||||
ValidatorIndex: 10,
|
||||
FromBlsPubkey: make([]byte, 48),
|
||||
ToExecutionAddress: make([]byte, 20),
|
||||
},
|
||||
Signature: emptySig[:],
|
||||
}},
|
||||
want: pubsub.ValidationIgnore,
|
||||
},
|
||||
{
|
||||
name: "Non-existent Validator Index",
|
||||
svc: NewService(context.Background(),
|
||||
WithP2P(mockp2p.NewTestP2P(t)),
|
||||
WithInitialSync(&mockSync.Sync{IsSyncing: false}),
|
||||
WithChainService(chainService),
|
||||
WithStateNotifier(chainService.StateNotifier()),
|
||||
WithOperationNotifier(chainService.OperationNotifier()),
|
||||
WithBlsToExecPool(blstoexec.NewPool()),
|
||||
),
|
||||
setupSvc: func(s *Service, msg *ethpb.SignedBLSToExecutionChange, topic string) (*Service, string) {
|
||||
s.cfg.stateGen = stategen.New(beaconDB, doublylinkedtree.New())
|
||||
s.cfg.beaconDB = beaconDB
|
||||
s.initCaches()
|
||||
st, _ := util.DeterministicGenesisStateCapella(t, 128)
|
||||
s.cfg.chain = &mockChain.ChainService{
|
||||
ValidatorsRoot: [32]byte{'A'},
|
||||
Genesis: time.Now().Add(-time.Second * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Duration(10)),
|
||||
State: st,
|
||||
}
|
||||
|
||||
msg.Message.ValidatorIndex = 130
|
||||
return s, topic
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
pid: "random",
|
||||
topic: fmt.Sprintf(defaultTopic, fakeDigest),
|
||||
msg: ðpb.SignedBLSToExecutionChange{
|
||||
Message: ðpb.BLSToExecutionChange{
|
||||
ValidatorIndex: 0,
|
||||
FromBlsPubkey: make([]byte, 48),
|
||||
ToExecutionAddress: make([]byte, 20),
|
||||
},
|
||||
Signature: emptySig[:],
|
||||
}},
|
||||
want: pubsub.ValidationReject,
|
||||
},
|
||||
{
|
||||
name: "Invalid Withdrawal Pubkey",
|
||||
svc: NewService(context.Background(),
|
||||
WithP2P(mockp2p.NewTestP2P(t)),
|
||||
WithInitialSync(&mockSync.Sync{IsSyncing: false}),
|
||||
WithChainService(chainService),
|
||||
WithStateNotifier(chainService.StateNotifier()),
|
||||
WithOperationNotifier(chainService.OperationNotifier()),
|
||||
WithBlsToExecPool(blstoexec.NewPool()),
|
||||
),
|
||||
setupSvc: func(s *Service, msg *ethpb.SignedBLSToExecutionChange, topic string) (*Service, string) {
|
||||
s.cfg.stateGen = stategen.New(beaconDB, doublylinkedtree.New())
|
||||
s.cfg.beaconDB = beaconDB
|
||||
s.initCaches()
|
||||
st, keys := util.DeterministicGenesisStateCapella(t, 128)
|
||||
s.cfg.chain = &mockChain.ChainService{
|
||||
ValidatorsRoot: [32]byte{'A'},
|
||||
Genesis: time.Now().Add(-time.Second * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Duration(10)),
|
||||
State: st,
|
||||
}
|
||||
|
||||
msg.Message.ValidatorIndex = 50
|
||||
// Provide invalid withdrawal key for validator
|
||||
msg.Message.FromBlsPubkey = keys[0].PublicKey().Marshal()
|
||||
msg.Message.ToExecutionAddress = wantedExecAddress
|
||||
return s, topic
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
pid: "random",
|
||||
topic: fmt.Sprintf(defaultTopic, fakeDigest),
|
||||
msg: ðpb.SignedBLSToExecutionChange{
|
||||
Message: ðpb.BLSToExecutionChange{
|
||||
ValidatorIndex: 0,
|
||||
FromBlsPubkey: make([]byte, 48),
|
||||
ToExecutionAddress: make([]byte, 20),
|
||||
},
|
||||
Signature: emptySig[:],
|
||||
}},
|
||||
want: pubsub.ValidationReject,
|
||||
},
|
||||
{
|
||||
name: "Invalid Credentials in State",
|
||||
svc: NewService(context.Background(),
|
||||
WithP2P(mockp2p.NewTestP2P(t)),
|
||||
WithInitialSync(&mockSync.Sync{IsSyncing: false}),
|
||||
WithChainService(chainService),
|
||||
WithStateNotifier(chainService.StateNotifier()),
|
||||
WithOperationNotifier(chainService.OperationNotifier()),
|
||||
WithBlsToExecPool(blstoexec.NewPool()),
|
||||
),
|
||||
setupSvc: func(s *Service, msg *ethpb.SignedBLSToExecutionChange, topic string) (*Service, string) {
|
||||
s.cfg.stateGen = stategen.New(beaconDB, doublylinkedtree.New())
|
||||
s.cfg.beaconDB = beaconDB
|
||||
s.initCaches()
|
||||
st, keys := util.DeterministicGenesisStateCapella(t, 128)
|
||||
assert.NoError(t, st.ApplyToEveryValidator(func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error) {
|
||||
newCreds := make([]byte, 32)
|
||||
newCreds[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
||||
copy(newCreds[12:], wantedExecAddress)
|
||||
val.WithdrawalCredentials = newCreds
|
||||
return true, val, nil
|
||||
}))
|
||||
s.cfg.chain = &mockChain.ChainService{
|
||||
ValidatorsRoot: [32]byte{'A'},
|
||||
Genesis: time.Now().Add(-time.Second * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Duration(10)),
|
||||
State: st,
|
||||
}
|
||||
|
||||
msg.Message.ValidatorIndex = 50
|
||||
// Provide Correct withdrawal pubkey
|
||||
msg.Message.FromBlsPubkey = keys[51].PublicKey().Marshal()
|
||||
msg.Message.ToExecutionAddress = wantedExecAddress
|
||||
return s, topic
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
pid: "random",
|
||||
topic: fmt.Sprintf(defaultTopic, fakeDigest),
|
||||
msg: ðpb.SignedBLSToExecutionChange{
|
||||
Message: ðpb.BLSToExecutionChange{
|
||||
ValidatorIndex: 0,
|
||||
FromBlsPubkey: make([]byte, 48),
|
||||
ToExecutionAddress: make([]byte, 20),
|
||||
},
|
||||
Signature: emptySig[:],
|
||||
}},
|
||||
want: pubsub.ValidationReject,
|
||||
},
|
||||
{
|
||||
name: "Invalid Execution Change Signature",
|
||||
svc: NewService(context.Background(),
|
||||
WithP2P(mockp2p.NewTestP2P(t)),
|
||||
WithInitialSync(&mockSync.Sync{IsSyncing: false}),
|
||||
WithChainService(chainService),
|
||||
WithStateNotifier(chainService.StateNotifier()),
|
||||
WithOperationNotifier(chainService.OperationNotifier()),
|
||||
WithBlsToExecPool(blstoexec.NewPool()),
|
||||
),
|
||||
setupSvc: func(s *Service, msg *ethpb.SignedBLSToExecutionChange, topic string) (*Service, string) {
|
||||
s.cfg.stateGen = stategen.New(beaconDB, doublylinkedtree.New())
|
||||
s.cfg.beaconDB = beaconDB
|
||||
s.initCaches()
|
||||
st, keys := util.DeterministicGenesisStateCapella(t, 128)
|
||||
s.cfg.chain = &mockChain.ChainService{
|
||||
ValidatorsRoot: [32]byte{'A'},
|
||||
Genesis: time.Now().Add(-time.Second * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Duration(10)),
|
||||
State: st,
|
||||
}
|
||||
|
||||
msg.Message.ValidatorIndex = 50
|
||||
// Provide invalid withdrawal key for validator
|
||||
msg.Message.FromBlsPubkey = keys[51].PublicKey().Marshal()
|
||||
msg.Message.ToExecutionAddress = wantedExecAddress
|
||||
badSig := make([]byte, 96)
|
||||
copy(badSig, []byte{'j', 'u', 'n', 'k'})
|
||||
msg.Signature = badSig
|
||||
return s, topic
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
pid: "random",
|
||||
topic: fmt.Sprintf(defaultTopic, fakeDigest),
|
||||
msg: ðpb.SignedBLSToExecutionChange{
|
||||
Message: ðpb.BLSToExecutionChange{
|
||||
ValidatorIndex: 0,
|
||||
FromBlsPubkey: make([]byte, 48),
|
||||
ToExecutionAddress: make([]byte, 20),
|
||||
},
|
||||
Signature: emptySig[:],
|
||||
}},
|
||||
want: pubsub.ValidationReject,
|
||||
},
|
||||
{
|
||||
name: "Valid Execution Change Message",
|
||||
svc: NewService(context.Background(),
|
||||
WithP2P(mockp2p.NewTestP2P(t)),
|
||||
WithInitialSync(&mockSync.Sync{IsSyncing: false}),
|
||||
WithChainService(chainService),
|
||||
WithStateNotifier(chainService.StateNotifier()),
|
||||
WithOperationNotifier(chainService.OperationNotifier()),
|
||||
WithBlsToExecPool(blstoexec.NewPool()),
|
||||
),
|
||||
setupSvc: func(s *Service, msg *ethpb.SignedBLSToExecutionChange, topic string) (*Service, string) {
|
||||
s.cfg.stateGen = stategen.New(beaconDB, doublylinkedtree.New())
|
||||
s.cfg.beaconDB = beaconDB
|
||||
s.initCaches()
|
||||
st, keys := util.DeterministicGenesisStateCapella(t, 128)
|
||||
s.cfg.chain = &mockChain.ChainService{
|
||||
ValidatorsRoot: [32]byte{'A'},
|
||||
Genesis: time.Now().Add(-time.Second * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Duration(10)),
|
||||
State: st,
|
||||
}
|
||||
|
||||
msg.Message.ValidatorIndex = 50
|
||||
// Provide invalid withdrawal key for validator
|
||||
msg.Message.FromBlsPubkey = keys[51].PublicKey().Marshal()
|
||||
msg.Message.ToExecutionAddress = wantedExecAddress
|
||||
epoch := slots.ToEpoch(st.Slot())
|
||||
domain, err := signing.Domain(st.Fork(), epoch, params.BeaconConfig().DomainBLSToExecutionChange, st.GenesisValidatorsRoot())
|
||||
assert.NoError(t, err)
|
||||
htr, err := signing.SigningData(msg.Message.HashTreeRoot, domain)
|
||||
assert.NoError(t, err)
|
||||
msg.Signature = keys[51].Sign(htr[:]).Marshal()
|
||||
return s, topic
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
pid: "random",
|
||||
topic: fmt.Sprintf(defaultTopic, fakeDigest),
|
||||
msg: ðpb.SignedBLSToExecutionChange{
|
||||
Message: ðpb.BLSToExecutionChange{
|
||||
ValidatorIndex: 0,
|
||||
FromBlsPubkey: make([]byte, 48),
|
||||
ToExecutionAddress: make([]byte, 20),
|
||||
},
|
||||
Signature: emptySig[:],
|
||||
}},
|
||||
want: pubsub.ValidationAccept,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tt.svc, tt.args.topic = tt.setupSvc(tt.svc, tt.args.msg, tt.args.topic)
|
||||
marshalledObj, err := tt.args.msg.MarshalSSZ()
|
||||
assert.NoError(t, err)
|
||||
marshalledObj = snappy.Encode(nil, marshalledObj)
|
||||
msg := &pubsub.Message{
|
||||
Message: &pubsubpb.Message{
|
||||
Data: marshalledObj,
|
||||
Topic: &tt.args.topic,
|
||||
},
|
||||
ReceivedFrom: "",
|
||||
ValidatorData: nil,
|
||||
}
|
||||
if got, err := tt.svc.validateBlsToExecutionChange(tt.args.ctx, tt.args.pid, msg); got != tt.want {
|
||||
_ = err
|
||||
t.Errorf("validateBlsToExecutionChange() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user