From db397cc5f37787d004a9c16c4ca7b1c05b9de653 Mon Sep 17 00:00:00 2001 From: Dustin Brody Date: Thu, 23 Jul 2020 16:38:28 +0200 Subject: [PATCH] lazily initialize validator public keys, which were a third or more of sync CPU usage --- beacon_chain/spec/beaconstate.nim | 2 +- beacon_chain/spec/crypto.nim | 39 +++++++++++++++++++++++++------ beacon_chain/spec/signatures.nim | 14 +++++------ 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/beacon_chain/spec/beaconstate.nim b/beacon_chain/spec/beaconstate.nim index 40d5abc9b..6874002eb 100644 --- a/beacon_chain/spec/beaconstate.nim +++ b/beacon_chain/spec/beaconstate.nim @@ -413,7 +413,7 @@ proc process_registry_updates*(state: var BeaconState, compute_activation_exit_epoch(get_current_epoch(state)) # https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#is_valid_indexed_attestation -func is_valid_indexed_attestation*( +proc is_valid_indexed_attestation*( state: BeaconState, indexed_attestation: SomeIndexedAttestation, flags: UpdateFlags): bool = # Check if ``indexed_attestation`` is not empty, has sorted and unique diff --git a/beacon_chain/spec/crypto.nim b/beacon_chain/spec/crypto.nim index 333da1232..83a194d71 100644 --- a/beacon_chain/spec/crypto.nim +++ b/beacon_chain/spec/crypto.nim @@ -24,6 +24,8 @@ {.push raises: [Defect].} import + # Standard library + options, tables, # Internal ./digest, # Status @@ -103,13 +105,34 @@ func toPubKey*(privkey: ValidatorPrivKey): ValidatorPubKey = else: privkey.getKey +proc toRealPubKey(pubkey: ValidatorPubKey): Option[ValidatorPubKey] = + var validatorKeyCache {.threadvar.}: Table[Hash, Option[ValidatorPubKey]] + + if pubkey.kind == Real: + return some(pubkey) + + doAssert pubkey.kind == OpaqueBlob + + let key = hash(pubkey.blob) + try: + validatorKeyCache[key] + except KeyError: + var val: blscurve.PublicKey + let maybeRealKey = + if fromBytes(val, pubkey.blob): + some ValidatorPubKey(kind: Real, blsValue: val) + else: + none(ValidatorPubKey) + validatorKeyCache[key] = maybeRealKey + maybeRealKey + func aggregate*(x: var ValidatorSig, other: ValidatorSig) = ## Aggregate 2 Validator Signatures ## This assumes that they are real signatures x.blsValue.aggregate(other.blsValue) # https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/beacon-chain.md#bls-signatures -func blsVerify*( +proc blsVerify*( pubkey: ValidatorPubKey, message: openArray[byte], signature: ValidatorSig): bool = ## Check that a signature is valid for a message @@ -122,7 +145,8 @@ func blsVerify*( if signature.kind != Real: # Invalid signatures are possible in deposits (discussed with Danny) return false - if pubkey.kind != Real: + let realkey = toRealPubKey(pubkey) + if realkey.isNone: # TODO: chronicles warning return false @@ -135,13 +159,13 @@ func blsVerify*( # # a way to create many false positive matches. This seems odd. # if pubkey.getBytes() == default(ValidatorPubKey).getBytes(): # return true - pubkey.blsValue.verify(message, signature.blsValue) + realkey.get.blsValue.verify(message, signature.blsValue) func blsSign*(privkey: ValidatorPrivKey, message: openArray[byte]): ValidatorSig = ## Computes a signature from a secret key and a message ValidatorSig(kind: Real, blsValue: SecretKey(privkey).sign(message)) -func blsFastAggregateVerify*( +proc blsFastAggregateVerify*( publicKeys: openArray[ValidatorPubKey], message: openArray[byte], signature: ValidatorSig @@ -168,9 +192,10 @@ func blsFastAggregateVerify*( return false var unwrapped: seq[PublicKey] for pubkey in publicKeys: - if pubkey.kind != Real: + let realkey = toRealPubKey(pubkey) + if realkey.isNone: return false - unwrapped.add pubkey.blsValue + unwrapped.add realkey.get.blsValue fastAggregateVerify(unwrapped, message, signature.blsValue) @@ -220,7 +245,7 @@ func fromRaw*(T: type ValidatorPrivKey, bytes: openArray[byte]): BlsResult[T] = func fromRaw*[N, T](BT: type BlsValue[N, T], bytes: openArray[byte]): BlsResult[BT] = # This is a workaround, so that we can deserialize the serialization of a # default-initialized BlsValue without raising an exception - when defined(ssz_testing): + when defined(ssz_testing) or T is blscurve.PublicKey: # Only for SSZ parsing tests, everything is an opaque blob ok BT(kind: OpaqueBlob, blob: toArray(N, bytes)) else: diff --git a/beacon_chain/spec/signatures.nim b/beacon_chain/spec/signatures.nim index 44793349e..f37401d0a 100644 --- a/beacon_chain/spec/signatures.nim +++ b/beacon_chain/spec/signatures.nim @@ -29,7 +29,7 @@ func get_slot_signature*( blsSign(privKey, signing_root.data) -func verify_slot_signature*( +proc verify_slot_signature*( fork: Fork, genesis_validators_root: Eth2Digest, slot: Slot, pubkey: ValidatorPubKey, signature: SomeSig): bool = withTrust(signature): @@ -51,7 +51,7 @@ func get_epoch_signature*( blsSign(privKey, signing_root.data) -func verify_epoch_signature*( +proc verify_epoch_signature*( fork: Fork, genesis_validators_root: Eth2Digest, epoch: Epoch, pubkey: ValidatorPubKey, signature: SomeSig): bool = withTrust(signature): @@ -73,7 +73,7 @@ func get_block_signature*( blsSign(privKey, signing_root.data) -func verify_block_signature*( +proc verify_block_signature*( fork: Fork, genesis_validators_root: Eth2Digest, slot: Slot, blck: Eth2Digest | SomeBeaconBlock | BeaconBlockHeader, pubkey: ValidatorPubKey, @@ -99,7 +99,7 @@ func get_aggregate_and_proof_signature*(fork: Fork, genesis_validators_root: Eth blsSign(privKey, signing_root.data) -func verify_aggregate_and_proof_signature*(fork: Fork, genesis_validators_root: Eth2Digest, +proc verify_aggregate_and_proof_signature*(fork: Fork, genesis_validators_root: Eth2Digest, aggregate_and_proof: AggregateAndProof, pubkey: ValidatorPubKey, signature: SomeSig): bool = withTrust(signature): @@ -124,7 +124,7 @@ func get_attestation_signature*( blsSign(privKey, signing_root.data) -func verify_attestation_signature*( +proc verify_attestation_signature*( fork: Fork, genesis_validators_root: Eth2Digest, attestation_data: AttestationData, pubkeys: openArray[ValidatorPubKey], @@ -150,7 +150,7 @@ func get_deposit_signature*(preset: RuntimePreset, blsSign(privKey, signing_root.data) -func verify_deposit_signature*(preset: RuntimePreset, +proc verify_deposit_signature*(preset: RuntimePreset, deposit: DepositData): bool = let deposit_message = deposit.getDepositMessage() @@ -160,7 +160,7 @@ func verify_deposit_signature*(preset: RuntimePreset, blsVerify(deposit.pubkey, signing_root.data, deposit.signature) -func verify_voluntary_exit_signature*( +proc verify_voluntary_exit_signature*( fork: Fork, genesis_validators_root: Eth2Digest, voluntary_exit: VoluntaryExit, pubkey: ValidatorPubKey, signature: SomeSig): bool =