|
| 1 | +package services |
| 2 | + |
| 3 | +import ( |
| 4 | + "bytes" |
| 5 | + "context" |
| 6 | + "fmt" |
| 7 | + |
| 8 | + "github.com/Giulio2002/bls" |
| 9 | + "github.com/ledgerwatch/erigon/cl/beacon/beaconevents" |
| 10 | + "github.com/ledgerwatch/erigon/cl/beacon/synced_data" |
| 11 | + "github.com/ledgerwatch/erigon/cl/clparams" |
| 12 | + "github.com/ledgerwatch/erigon/cl/cltypes" |
| 13 | + "github.com/ledgerwatch/erigon/cl/fork" |
| 14 | + "github.com/ledgerwatch/erigon/cl/pool" |
| 15 | + "github.com/ledgerwatch/erigon/cl/utils" |
| 16 | +) |
| 17 | + |
| 18 | +type blsToExecutionChangeService struct { |
| 19 | + operationsPool pool.OperationsPool |
| 20 | + emitters *beaconevents.Emitters |
| 21 | + syncedDataManager *synced_data.SyncedDataManager |
| 22 | + beaconCfg *clparams.BeaconChainConfig |
| 23 | +} |
| 24 | + |
| 25 | +func NewBLSToExecutionChangeService( |
| 26 | + operationsPool pool.OperationsPool, |
| 27 | + emitters *beaconevents.Emitters, |
| 28 | + syncedDataManager *synced_data.SyncedDataManager, |
| 29 | + beaconCfg *clparams.BeaconChainConfig, |
| 30 | +) BLSToExecutionChangeService { |
| 31 | + return &blsToExecutionChangeService{ |
| 32 | + operationsPool: operationsPool, |
| 33 | + emitters: emitters, |
| 34 | + syncedDataManager: syncedDataManager, |
| 35 | + beaconCfg: beaconCfg, |
| 36 | + } |
| 37 | +} |
| 38 | + |
| 39 | +func (s *blsToExecutionChangeService) ProcessMessage(ctx context.Context, subnet *uint64, msg *cltypes.SignedBLSToExecutionChange) error { |
| 40 | + defer s.emitters.Publish("bls_to_execution_change", msg) |
| 41 | + |
| 42 | + // [IGNORE] The signed_bls_to_execution_change is the first valid signed bls to execution change received |
| 43 | + // for the validator with index signed_bls_to_execution_change.message.validator_index. |
| 44 | + if s.operationsPool.BLSToExecutionChangesPool.Has(msg.Signature) { |
| 45 | + return nil |
| 46 | + } |
| 47 | + change := msg.Message |
| 48 | + |
| 49 | + state := s.syncedDataManager.HeadState() |
| 50 | + if state == nil { |
| 51 | + return nil |
| 52 | + } |
| 53 | + |
| 54 | + // [IGNORE] current_epoch >= CAPELLA_FORK_EPOCH, where current_epoch is defined by the current wall-clock time. |
| 55 | + if !(state.Version() >= clparams.CapellaVersion) { |
| 56 | + return ErrIgnore |
| 57 | + } |
| 58 | + |
| 59 | + // ref: https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#new-process_bls_to_execution_change |
| 60 | + // assert address_change.validator_index < len(state.validators) |
| 61 | + validator, err := state.ValidatorForValidatorIndex(int(change.ValidatorIndex)) |
| 62 | + if err != nil { |
| 63 | + return fmt.Errorf("unable to retrieve state: %v", err) |
| 64 | + } |
| 65 | + wc := validator.WithdrawalCredentials() |
| 66 | + |
| 67 | + // assert validator.withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX |
| 68 | + if wc[0] != byte(s.beaconCfg.BLSWithdrawalPrefixByte) { |
| 69 | + return fmt.Errorf("invalid withdrawal credentials prefix") |
| 70 | + } |
| 71 | + |
| 72 | + // assert validator.withdrawal_credentials[1:] == hash(address_change.from_bls_pubkey)[1:] |
| 73 | + // Perform full validation if requested. |
| 74 | + // Check the validator's withdrawal credentials against the provided message. |
| 75 | + hashedFrom := utils.Sha256(change.From[:]) |
| 76 | + if !bytes.Equal(hashedFrom[1:], wc[1:]) { |
| 77 | + return fmt.Errorf("invalid withdrawal credentials") |
| 78 | + } |
| 79 | + |
| 80 | + // assert bls.Verify(address_change.from_bls_pubkey, signing_root, signed_address_change.signature) |
| 81 | + genesisValidatorRoot := state.GenesisValidatorsRoot() |
| 82 | + domain, err := fork.ComputeDomain(s.beaconCfg.DomainBLSToExecutionChange[:], utils.Uint32ToBytes4(uint32(s.beaconCfg.GenesisForkVersion)), genesisValidatorRoot) |
| 83 | + if err != nil { |
| 84 | + return err |
| 85 | + } |
| 86 | + signedRoot, err := fork.ComputeSigningRoot(change, domain) |
| 87 | + if err != nil { |
| 88 | + return err |
| 89 | + } |
| 90 | + valid, err := bls.Verify(msg.Signature[:], signedRoot[:], change.From[:]) |
| 91 | + if err != nil { |
| 92 | + return err |
| 93 | + } |
| 94 | + if !valid { |
| 95 | + return fmt.Errorf("invalid signature") |
| 96 | + } |
| 97 | + s.operationsPool.BLSToExecutionChangesPool.Insert(msg.Signature, msg) |
| 98 | + return nil |
| 99 | +} |
0 commit comments