github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/core/blocks/deposit.go (about) 1 package blocks 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/pkg/errors" 8 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 9 iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface" 10 pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 11 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 12 "github.com/prysmaticlabs/prysm/shared/bls" 13 "github.com/prysmaticlabs/prysm/shared/bytesutil" 14 "github.com/prysmaticlabs/prysm/shared/depositutil" 15 "github.com/prysmaticlabs/prysm/shared/mathutil" 16 "github.com/prysmaticlabs/prysm/shared/params" 17 "github.com/prysmaticlabs/prysm/shared/trieutil" 18 ) 19 20 // ProcessPreGenesisDeposits processes a deposit for the beacon state before chainstart. 21 func ProcessPreGenesisDeposits( 22 ctx context.Context, 23 beaconState iface.BeaconState, 24 deposits []*ethpb.Deposit, 25 ) (iface.BeaconState, error) { 26 var err error 27 beaconState, err = ProcessDeposits(ctx, beaconState, deposits) 28 if err != nil { 29 return nil, errors.Wrap(err, "could not process deposit") 30 } 31 beaconState, err = ActivateValidatorWithEffectiveBalance(beaconState, deposits) 32 if err != nil { 33 return nil, err 34 } 35 return beaconState, nil 36 } 37 38 // ActivateValidatorWithEffectiveBalance updates validator's effective balance, and if it's above MaxEffectiveBalance, validator becomes active in genesis. 39 func ActivateValidatorWithEffectiveBalance(beaconState iface.BeaconState, deposits []*ethpb.Deposit) (iface.BeaconState, error) { 40 for _, deposit := range deposits { 41 pubkey := deposit.Data.PublicKey 42 index, ok := beaconState.ValidatorIndexByPubkey(bytesutil.ToBytes48(pubkey)) 43 // In the event of the pubkey not existing, we continue processing the other 44 // deposits. 45 if !ok { 46 continue 47 } 48 balance, err := beaconState.BalanceAtIndex(index) 49 if err != nil { 50 return nil, err 51 } 52 validator, err := beaconState.ValidatorAtIndex(index) 53 if err != nil { 54 return nil, err 55 } 56 validator.EffectiveBalance = mathutil.Min(balance-balance%params.BeaconConfig().EffectiveBalanceIncrement, params.BeaconConfig().MaxEffectiveBalance) 57 if validator.EffectiveBalance == 58 params.BeaconConfig().MaxEffectiveBalance { 59 validator.ActivationEligibilityEpoch = 0 60 validator.ActivationEpoch = 0 61 } 62 if err := beaconState.UpdateValidatorAtIndex(index, validator); err != nil { 63 return nil, err 64 } 65 } 66 return beaconState, nil 67 } 68 69 // ProcessDeposits is one of the operations performed on each processed 70 // beacon block to verify queued validators from the Ethereum 1.0 Deposit Contract 71 // into the beacon chain. 72 // 73 // Spec pseudocode definition: 74 // For each deposit in block.body.deposits: 75 // process_deposit(state, deposit) 76 func ProcessDeposits( 77 ctx context.Context, 78 beaconState iface.BeaconState, 79 deposits []*ethpb.Deposit, 80 ) (iface.BeaconState, error) { 81 // Attempt to verify all deposit signatures at once, if this fails then fall back to processing 82 // individual deposits with signature verification enabled. 83 batchVerified, err := BatchVerifyDepositsSignatures(ctx, deposits) 84 if err != nil { 85 return nil, err 86 } 87 88 for _, deposit := range deposits { 89 if deposit == nil || deposit.Data == nil { 90 return nil, errors.New("got a nil deposit in block") 91 } 92 beaconState, err = ProcessDeposit(beaconState, deposit, batchVerified) 93 if err != nil { 94 return nil, errors.Wrapf(err, "could not process deposit from %#x", bytesutil.Trunc(deposit.Data.PublicKey)) 95 } 96 } 97 return beaconState, nil 98 } 99 100 // BatchVerifyDepositsSignatures batch verifies deposit signatures. 101 func BatchVerifyDepositsSignatures(ctx context.Context, deposits []*ethpb.Deposit) (bool, error) { 102 var err error 103 domain, err := helpers.ComputeDomain(params.BeaconConfig().DomainDeposit, nil, nil) 104 if err != nil { 105 return false, err 106 } 107 108 verified := false 109 if err := verifyDepositDataWithDomain(ctx, deposits, domain); err != nil { 110 log.WithError(err).Debug("Failed to batch verify deposits signatures, will try individual verify") 111 verified = true 112 } 113 return verified, nil 114 } 115 116 // ProcessDeposit takes in a deposit object and inserts it 117 // into the registry as a new validator or balance change. 118 // 119 // Spec pseudocode definition: 120 // def process_deposit(state: BeaconState, deposit: Deposit) -> None: 121 // # Verify the Merkle branch 122 // assert is_valid_merkle_branch( 123 // leaf=hash_tree_root(deposit.data), 124 // branch=deposit.proof, 125 // depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, # Add 1 for the List length mix-in 126 // index=state.eth1_deposit_index, 127 // root=state.eth1_data.deposit_root, 128 // ) 129 // 130 // # Deposits must be processed in order 131 // state.eth1_deposit_index += 1 132 // 133 // pubkey = deposit.data.pubkey 134 // amount = deposit.data.amount 135 // validator_pubkeys = [v.pubkey for v in state.validators] 136 // if pubkey not in validator_pubkeys: 137 // # Verify the deposit signature (proof of possession) which is not checked by the deposit contract 138 // deposit_message = DepositMessage( 139 // pubkey=deposit.data.pubkey, 140 // withdrawal_credentials=deposit.data.withdrawal_credentials, 141 // amount=deposit.data.amount, 142 // ) 143 // domain = compute_domain(DOMAIN_DEPOSIT) # Fork-agnostic domain since deposits are valid across forks 144 // signing_root = compute_signing_root(deposit_message, domain) 145 // if not bls.Verify(pubkey, signing_root, deposit.data.signature): 146 // return 147 // 148 // # Add validator and balance entries 149 // state.validators.append(get_validator_from_deposit(state, deposit)) 150 // state.balances.append(amount) 151 // else: 152 // # Increase balance by deposit amount 153 // index = ValidatorIndex(validator_pubkeys.index(pubkey)) 154 // increase_balance(state, index, amount) 155 func ProcessDeposit(beaconState iface.BeaconState, deposit *ethpb.Deposit, verifySignature bool) (iface.BeaconState, error) { 156 if err := verifyDeposit(beaconState, deposit); err != nil { 157 if deposit == nil || deposit.Data == nil { 158 return nil, err 159 } 160 return nil, errors.Wrapf(err, "could not verify deposit from %#x", bytesutil.Trunc(deposit.Data.PublicKey)) 161 } 162 if err := beaconState.SetEth1DepositIndex(beaconState.Eth1DepositIndex() + 1); err != nil { 163 return nil, err 164 } 165 pubKey := deposit.Data.PublicKey 166 amount := deposit.Data.Amount 167 index, ok := beaconState.ValidatorIndexByPubkey(bytesutil.ToBytes48(pubKey)) 168 if !ok { 169 if verifySignature { 170 domain, err := helpers.ComputeDomain(params.BeaconConfig().DomainDeposit, nil, nil) 171 if err != nil { 172 return nil, err 173 } 174 if err := verifyDepositDataSigningRoot(deposit.Data, domain); err != nil { 175 // Ignore this error as in the spec pseudo code. 176 log.Debugf("Skipping deposit: could not verify deposit data signature: %v", err) 177 return beaconState, nil 178 } 179 } 180 181 effectiveBalance := amount - (amount % params.BeaconConfig().EffectiveBalanceIncrement) 182 if params.BeaconConfig().MaxEffectiveBalance < effectiveBalance { 183 effectiveBalance = params.BeaconConfig().MaxEffectiveBalance 184 } 185 if err := beaconState.AppendValidator(ðpb.Validator{ 186 PublicKey: pubKey, 187 WithdrawalCredentials: deposit.Data.WithdrawalCredentials, 188 ActivationEligibilityEpoch: params.BeaconConfig().FarFutureEpoch, 189 ActivationEpoch: params.BeaconConfig().FarFutureEpoch, 190 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 191 WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch, 192 EffectiveBalance: effectiveBalance, 193 }); err != nil { 194 return nil, err 195 } 196 if err := beaconState.AppendBalance(amount); err != nil { 197 return nil, err 198 } 199 } else if err := helpers.IncreaseBalance(beaconState, index, amount); err != nil { 200 return nil, err 201 } 202 203 return beaconState, nil 204 } 205 206 func verifyDeposit(beaconState iface.ReadOnlyBeaconState, deposit *ethpb.Deposit) error { 207 // Verify Merkle proof of deposit and deposit trie root. 208 if deposit == nil || deposit.Data == nil { 209 return errors.New("received nil deposit or nil deposit data") 210 } 211 eth1Data := beaconState.Eth1Data() 212 if eth1Data == nil { 213 return errors.New("received nil eth1data in the beacon state") 214 } 215 216 receiptRoot := eth1Data.DepositRoot 217 leaf, err := deposit.Data.HashTreeRoot() 218 if err != nil { 219 return errors.Wrap(err, "could not tree hash deposit data") 220 } 221 if ok := trieutil.VerifyMerkleBranch( 222 receiptRoot, 223 leaf[:], 224 int(beaconState.Eth1DepositIndex()), 225 deposit.Proof, 226 params.BeaconConfig().DepositContractTreeDepth, 227 ); !ok { 228 return fmt.Errorf( 229 "deposit merkle branch of deposit root did not verify for root: %#x", 230 receiptRoot, 231 ) 232 } 233 234 return nil 235 } 236 237 func verifyDepositDataSigningRoot(obj *ethpb.Deposit_Data, domain []byte) error { 238 return depositutil.VerifyDepositSignature(obj, domain) 239 } 240 241 func verifyDepositDataWithDomain(ctx context.Context, deps []*ethpb.Deposit, domain []byte) error { 242 if len(deps) == 0 { 243 return nil 244 } 245 pks := make([]bls.PublicKey, len(deps)) 246 sigs := make([][]byte, len(deps)) 247 msgs := make([][32]byte, len(deps)) 248 for i, dep := range deps { 249 if ctx.Err() != nil { 250 return ctx.Err() 251 } 252 if dep == nil || dep.Data == nil { 253 return errors.New("nil deposit") 254 } 255 dpk, err := bls.PublicKeyFromBytes(dep.Data.PublicKey) 256 if err != nil { 257 return err 258 } 259 pks[i] = dpk 260 sigs[i] = dep.Data.Signature 261 depositMessage := &pb.DepositMessage{ 262 PublicKey: dep.Data.PublicKey, 263 WithdrawalCredentials: dep.Data.WithdrawalCredentials, 264 Amount: dep.Data.Amount, 265 } 266 sr, err := helpers.ComputeSigningRoot(depositMessage, domain) 267 if err != nil { 268 return err 269 } 270 msgs[i] = sr 271 } 272 verify, err := bls.VerifyMultipleSignatures(sigs, msgs, pks) 273 if err != nil { 274 return errors.Errorf("could not verify multiple signatures: %v", err) 275 } 276 if !verify { 277 return errors.New("one or more deposit signatures did not verify") 278 } 279 return nil 280 }