'DomainWrapper' -> 'SigningRoot'
This commit is contained in:
parent
a65d96da04
commit
51bcb29e28
|
@ -34,7 +34,7 @@
|
|||
- [`DepositMessage`](#depositmessage)
|
||||
- [`DepositData`](#depositdata)
|
||||
- [`BeaconBlockHeader`](#beaconblockheader)
|
||||
- [`DomainWrapper`](#domainwrapper)
|
||||
- [`SigningRoot`](#signingroot)
|
||||
- [Beacon operations](#beacon-operations)
|
||||
- [`ProposerSlashing`](#proposerslashing)
|
||||
- [`AttesterSlashing`](#attesterslashing)
|
||||
|
@ -76,7 +76,7 @@
|
|||
- [`compute_start_slot_at_epoch`](#compute_start_slot_at_epoch)
|
||||
- [`compute_activation_exit_epoch`](#compute_activation_exit_epoch)
|
||||
- [`compute_domain`](#compute_domain)
|
||||
- [`compute_domain_wrapper_root`](#compute_domain_wrapper_root)
|
||||
- [`compute_signing_root`](#compute_signing_root)
|
||||
- [Beacon state accessors](#beacon-state-accessors)
|
||||
- [`get_current_epoch`](#get_current_epoch)
|
||||
- [`get_previous_epoch`](#get_previous_epoch)
|
||||
|
@ -378,11 +378,11 @@ class BeaconBlockHeader(Container):
|
|||
body_root: Root
|
||||
```
|
||||
|
||||
#### `DomainWrapper`
|
||||
#### `SigningRoot`
|
||||
|
||||
```python
|
||||
class DomainWrapper(Container):
|
||||
root: Root
|
||||
class SigningRoot(Container):
|
||||
object_root: Root
|
||||
domain: Domain
|
||||
```
|
||||
|
||||
|
@ -586,10 +586,10 @@ def bytes_to_int(data: bytes) -> uint64:
|
|||
|
||||
Eth2 makes use of BLS signatures as specified in the [IETF draft BLS specification](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-00). Specifically, eth2 uses the `BLS_SIG_BLS12381G2-SHA256-SSWU-RO-_POP_` ciphersuite which implements the following interfaces:
|
||||
|
||||
* `def Sign(SK: int, message: Bytes) -> BLSSignature`
|
||||
* `def Verify(PK: BLSPubkey, message: Bytes, signature: BLSSignature) -> bool`
|
||||
* `def Aggregate(signatures: Sequence[BLSSignature]) -> BLSSignature`
|
||||
* `def FastAggregateVerify(PKs: Sequence[BLSSignature], message: Bytes, signature: BLSSignature) -> bool`
|
||||
- `def Sign(SK: int, message: Bytes) -> BLSSignature`
|
||||
- `def Verify(PK: BLSPubkey, message: Bytes, signature: BLSSignature) -> bool`
|
||||
- `def Aggregate(signatures: Sequence[BLSSignature]) -> BLSSignature`
|
||||
- `def FastAggregateVerify(PKs: Sequence[BLSSignature], message: Bytes, signature: BLSSignature) -> bool`
|
||||
|
||||
Within these specifications, BLS signatures are treated as a module for notational clarity, thus to verify a signature `bls.Verify(...)` is used.
|
||||
|
||||
|
@ -676,7 +676,7 @@ def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: Indexe
|
|||
# Verify aggregate signature
|
||||
pubkeys = [state.validators[i].pubkey for i in indices]
|
||||
domain = get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch)
|
||||
message = compute_domain_wrapper_root(indexed_attestation.data, domain)
|
||||
message = compute_signing_root(indexed_attestation.data, domain)
|
||||
return bls.FastAggregateVerify(pubkeys, message, indexed_attestation.signature)
|
||||
```
|
||||
|
||||
|
@ -795,12 +795,12 @@ def compute_domain(domain_type: DomainType, fork_version: Version=Version()) ->
|
|||
return Domain(domain_type + fork_version)
|
||||
```
|
||||
|
||||
### `compute_domain_wrapper_root`
|
||||
### `compute_signing_root`
|
||||
|
||||
```python
|
||||
def compute_domain_wrapper_root(ssz_object: SSZObject, domain: Domain) -> Root:
|
||||
domain_wrapped_object = DomainWrapper(
|
||||
root=hash_tree_root(ssz_object),
|
||||
def compute_signing_root(ssz_object: SSZObject, domain: Domain) -> Root:
|
||||
domain_wrapped_object = SigningRoot(
|
||||
object_root=hash_tree_root(ssz_object),
|
||||
domain=domain,
|
||||
)
|
||||
return hash_tree_root(domain_wrapped_object)
|
||||
|
@ -1148,7 +1148,7 @@ def state_transition(state: BeaconState, signed_block: SignedBeaconBlock, valida
|
|||
```python
|
||||
def verify_block_signature(state: BeaconState, signed_block: SignedBeaconBlock) -> bool:
|
||||
proposer = state.validators[get_beacon_proposer_index(state)]
|
||||
message = compute_domain_wrapper_root(signed_block.message, get_domain(state, DOMAIN_BEACON_PROPOSER))
|
||||
message = compute_signing_root(signed_block.message, get_domain(state, DOMAIN_BEACON_PROPOSER))
|
||||
return bls.Verify(proposer.pubkey, message, signed_block.signature)
|
||||
```
|
||||
|
||||
|
@ -1448,7 +1448,7 @@ def process_randao(state: BeaconState, body: BeaconBlockBody) -> None:
|
|||
epoch = get_current_epoch(state)
|
||||
# Verify RANDAO reveal
|
||||
proposer = state.validators[get_beacon_proposer_index(state)]
|
||||
message = compute_domain_wrapper_root(epoch, get_domain(state, DOMAIN_RANDAO))
|
||||
message = compute_signing_root(epoch, get_domain(state, DOMAIN_RANDAO))
|
||||
assert bls.Verify(proposer.pubkey, message, body.randao_reveal)
|
||||
# Mix in RANDAO reveal
|
||||
mix = xor(get_randao_mix(state, epoch), hash(body.randao_reveal))
|
||||
|
@ -1497,7 +1497,7 @@ def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSla
|
|||
# Signatures are valid
|
||||
for signed_header in (proposer_slashing.signed_header_1, proposer_slashing.signed_header_2):
|
||||
domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(signed_header.message.slot))
|
||||
message = compute_domain_wrapper_root(signed_header.message, domain)
|
||||
message = compute_signing_root(signed_header.message, domain)
|
||||
assert bls.Verify(proposer.pubkey, message, signed_header.signature)
|
||||
|
||||
slash_validator(state, proposer_slashing.proposer_index)
|
||||
|
@ -1580,7 +1580,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None:
|
|||
pubkey=deposit.data.pubkey,
|
||||
withdrawal_credentials=deposit.data.withdrawal_credentials,
|
||||
amount=deposit.data.amount)
|
||||
message = compute_domain_wrapper_root(deposit_message, compute_domain(DOMAIN_DEPOSIT))
|
||||
message = compute_signing_root(deposit_message, compute_domain(DOMAIN_DEPOSIT))
|
||||
if not bls.Verify(pubkey, message, deposit.data.signature):
|
||||
return
|
||||
|
||||
|
@ -1617,7 +1617,7 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu
|
|||
assert get_current_epoch(state) >= validator.activation_epoch + PERSISTENT_COMMITTEE_PERIOD
|
||||
# Verify signature
|
||||
domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch)
|
||||
message = compute_domain_wrapper_root(voluntary_exit, domain)
|
||||
message = compute_signing_root(voluntary_exit, domain)
|
||||
assert bls.Verify(validator.pubkey, message, signed_voluntary_exit.signature)
|
||||
# Initiate exit
|
||||
initiate_validator_exit(state, voluntary_exit.validator_index)
|
||||
|
|
|
@ -430,7 +430,7 @@ def process_custody_key_reveal(state: BeaconState, reveal: CustodyKeyReveal) ->
|
|||
|
||||
# Verify signature
|
||||
domain = get_domain(state, DOMAIN_RANDAO, epoch_to_sign)
|
||||
message = compute_domain_wrapper_root(epoch_to_sign, domain)
|
||||
message = compute_signing_root(epoch_to_sign, domain)
|
||||
assert bls.Verify(revealer.pubkey, message, reveal.reveal)
|
||||
|
||||
# Decrement max reveal lateness if response is timely
|
||||
|
@ -482,7 +482,7 @@ def process_early_derived_secret_reveal(state: BeaconState, reveal: EarlyDerived
|
|||
pubkeys = [revealed_validator.pubkey, masker.pubkey]
|
||||
|
||||
domain = get_domain(state, DOMAIN_RANDAO, reveal.epoch)
|
||||
messages = [compute_domain_wrapper_root(message, domain)
|
||||
messages = [compute_signing_root(message, domain)
|
||||
for message in [hash_tree_root(reveal.epoch), reveal.mask]]
|
||||
|
||||
assert bls.AggregateVerify(pubkeys, messages, reveal.reveal)
|
||||
|
@ -582,7 +582,7 @@ def process_bit_challenge(state: BeaconState, challenge: CustodyBitChallenge) ->
|
|||
challenger = state.validators[challenge.challenger_index]
|
||||
domain = get_domain(state, DOMAIN_CUSTODY_BIT_CHALLENGE, get_current_epoch(state))
|
||||
# TODO incorrect hash-tree-root, but this changes with phase 1 PR #1483
|
||||
assert bls.Verify(challenger.pubkey, compute_domain_wrapper_root(challenge, domain), challenge.signature)
|
||||
assert bls.Verify(challenger.pubkey, compute_signing_root(challenge, domain), challenge.signature)
|
||||
# Verify challenger is slashable
|
||||
assert is_slashable_validator(challenger, get_current_epoch(state))
|
||||
# Verify attestation
|
||||
|
@ -606,7 +606,7 @@ def process_bit_challenge(state: BeaconState, challenge: CustodyBitChallenge) ->
|
|||
challenge.responder_index,
|
||||
)
|
||||
domain = get_domain(state, DOMAIN_RANDAO, epoch_to_sign)
|
||||
assert bls.Verify(responder.pubkey, compute_domain_wrapper_root(epoch_to_sign, domain), challenge.responder_key)
|
||||
assert bls.Verify(responder.pubkey, compute_signing_root(epoch_to_sign, domain), challenge.responder_key)
|
||||
# Verify the chunk count
|
||||
chunk_count = get_custody_chunk_count(attestation.data.crosslink)
|
||||
assert chunk_count == len(challenge.chunk_bits)
|
||||
|
|
|
@ -386,7 +386,7 @@ def process_shard_block_header(beacon_state: BeaconState, shard_state: ShardStat
|
|||
assert not proposer.slashed
|
||||
# Verify proposer signature
|
||||
domain = get_domain(beacon_state, DOMAIN_SHARD_PROPOSER, compute_epoch_of_shard_slot(block.slot))
|
||||
assert bls.Verify(proposer.pubkey, compute_domain_wrapper_root(block, domain), block.signature)
|
||||
assert bls.Verify(proposer.pubkey, compute_signing_root(block, domain), block.signature)
|
||||
```
|
||||
|
||||
#### Attestations
|
||||
|
@ -407,7 +407,7 @@ def process_shard_attestations(beacon_state: BeaconState, shard_state: ShardStat
|
|||
# Verify attester aggregate signature
|
||||
domain = get_domain(beacon_state, DOMAIN_SHARD_ATTESTER, compute_epoch_of_shard_slot(block.slot))
|
||||
shard_attestation_data = ShardAttestationData(slot=shard_state.slot, parent_root=block.parent_root)
|
||||
message = compute_domain_wrapper_root(shard_attestation_data, domain)
|
||||
message = compute_signing_root(shard_attestation_data, domain)
|
||||
assert bls.FastAggregateVerify(pubkeys, message, block.attestations)
|
||||
# Proposer micro-reward
|
||||
proposer_index = get_shard_proposer_index(beacon_state, shard_state.shard, block.slot)
|
||||
|
|
|
@ -137,7 +137,7 @@ def update_memory(memory: LightClientMemory, update: LightClientUpdate) -> None:
|
|||
# Verify shard attestations
|
||||
pubkeys = filter(lambda i: update.aggregation_bits[i], pubkeys)
|
||||
domain = compute_domain(DOMAIN_SHARD_ATTESTER, update.fork_version)
|
||||
message = compute_domain_wrapper_root(update.shard_block_root, domain)
|
||||
message = compute_signing_root(update.shard_block_root, domain)
|
||||
assert bls.FastAggregateVerify(pubkeys, message, update.signature)
|
||||
|
||||
# Update period committees if entering a new period
|
||||
|
|
|
@ -117,7 +117,7 @@ To submit a deposit:
|
|||
- Set `deposit_data.withdrawal_credentials` to `withdrawal_credentials`.
|
||||
- Set `deposit_data.amount` to `amount`.
|
||||
- Let `deposit_message` be a `DepositMessage` with all the `DepositData` contents except the `signature`.
|
||||
- Let `signature` be the result of `Sign` of the `compute_domain_wrapper_root(deposit_message, domain)` with `domain=compute_domain(DOMAIN_DEPOSIT)`. (Deposits are valid regardless of fork version, `compute_domain` will default to zeroes there).
|
||||
- Let `signature` be the result of `Sign` of the `compute_signing_root(deposit_message, domain)` with `domain=compute_domain(DOMAIN_DEPOSIT)`. (Deposits are valid regardless of fork version, `compute_domain` will default to zeroes there).
|
||||
- Let `deposit_data_root` be `hash_tree_root(deposit_data)`.
|
||||
- Send a transaction on the Ethereum 1.0 chain to `DEPOSIT_CONTRACT_ADDRESS` executing `def deposit(pubkey: bytes[48], withdrawal_credentials: bytes[32], signature: bytes[96], deposit_data_root: bytes32)` along with a deposit of `amount` Gwei.
|
||||
|
||||
|
@ -234,7 +234,7 @@ Set `block.body.randao_reveal = epoch_signature` where `epoch_signature` is obta
|
|||
```python
|
||||
def get_epoch_signature(state: BeaconState, block: BeaconBlock, privkey: int) -> BLSSignature:
|
||||
domain = get_domain(state, DOMAIN_RANDAO, compute_epoch_at_slot(block.slot))
|
||||
message = compute_domain_wrapper_root(compute_epoch_at_slot(block.slot), domain)
|
||||
message = compute_signing_root(compute_epoch_at_slot(block.slot), domain)
|
||||
return bls.Sign(privkey, message)
|
||||
```
|
||||
|
||||
|
@ -312,7 +312,7 @@ def compute_new_state_root(state: BeaconState, block: BeaconBlock) -> Root:
|
|||
```python
|
||||
def get_block_signature(state: BeaconState, header: BeaconBlockHeader, privkey: int) -> BLSSignature:
|
||||
domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(header.slot))
|
||||
message = compute_domain_wrapper_root(header, domain)
|
||||
message = compute_signing_root(header, domain)
|
||||
return bls.Sign(privkey, message)
|
||||
```
|
||||
|
||||
|
@ -371,7 +371,7 @@ Set `attestation.signature = signed_attestation_data` where `signed_attestation_
|
|||
```python
|
||||
def get_signed_attestation_data(state: BeaconState, attestation: IndexedAttestation, privkey: int) -> BLSSignature:
|
||||
domain = get_domain(state, DOMAIN_BEACON_ATTESTER, attestation.data.target.epoch)
|
||||
message = compute_domain_wrapper_root(attestation.data, domain)
|
||||
message = compute_signing_root(attestation.data, domain)
|
||||
return bls.Sign(privkey, message)
|
||||
```
|
||||
|
||||
|
@ -390,7 +390,7 @@ A validator is selected to aggregate based upon the return value of `is_aggregat
|
|||
```python
|
||||
def get_slot_signature(state: BeaconState, slot: Slot, privkey: int) -> BLSSignature:
|
||||
domain = get_domain(state, DOMAIN_BEACON_ATTESTER, compute_epoch_at_slot(slot))
|
||||
message = compute_domain_wrapper_root(slot, domain)
|
||||
message = compute_signing_root(slot, domain)
|
||||
return bls.Sign(privkey, message)
|
||||
```
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ def sign_attestation(spec, state, attestation):
|
|||
|
||||
def get_attestation_signature(spec, state, attestation_data, privkey):
|
||||
domain = spec.get_domain(state, spec.DOMAIN_BEACON_ATTESTER, attestation_data.target.epoch)
|
||||
message = spec.compute_domain_wrapper_root(attestation_data, domain)
|
||||
message = spec.compute_signing_root(attestation_data, domain)
|
||||
return bls.Sign(privkey, message)
|
||||
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ def apply_randao_reveal(spec, state, block, proposer_index=None):
|
|||
privkey = privkeys[proposer_index]
|
||||
|
||||
domain = spec.get_domain(state, spec.DOMAIN_RANDAO, spec.compute_epoch_at_slot(block.slot))
|
||||
message = spec.compute_domain_wrapper_root(spec.compute_epoch_at_slot(block.slot), domain)
|
||||
message = spec.compute_signing_root(spec.compute_epoch_at_slot(block.slot), domain)
|
||||
block.body.randao_reveal = bls.Sign(privkey, message)
|
||||
|
||||
|
||||
|
@ -42,7 +42,7 @@ def apply_sig(spec, state, signed_block, proposer_index=None):
|
|||
proposer_index = get_proposer_index_maybe(spec, state, block.slot, proposer_index)
|
||||
privkey = privkeys[proposer_index]
|
||||
domain = spec.get_domain(state, spec.DOMAIN_BEACON_PROPOSER, spec.compute_epoch_at_slot(block.slot))
|
||||
message = spec.compute_domain_wrapper_root(block, domain)
|
||||
message = spec.compute_signing_root(block, domain)
|
||||
|
||||
signed_block.signature = bls.Sign(privkey, message)
|
||||
|
||||
|
|
|
@ -6,6 +6,6 @@ def sign_block_header(spec, state, header, privkey):
|
|||
state=state,
|
||||
domain_type=spec.DOMAIN_BEACON_PROPOSER,
|
||||
)
|
||||
message = spec.compute_domain_wrapper_root(header, domain)
|
||||
message = spec.compute_signing_root(header, domain)
|
||||
signature = bls.Sign(privkey, message)
|
||||
return spec.SignedBeaconBlockHeader(message=header, signature=signature)
|
||||
|
|
|
@ -18,12 +18,12 @@ def get_valid_early_derived_secret_reveal(spec, state, epoch=None):
|
|||
|
||||
# Generate the secret that is being revealed
|
||||
domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch)
|
||||
message = spec.compute_domain_wrapper_root(spec.Epoch(epoch), domain)
|
||||
message = spec.compute_signing_root(spec.Epoch(epoch), domain)
|
||||
reveal = bls.Sign(privkeys[revealed_index], message)
|
||||
# Generate the mask (any random 32 bytes that don't reveal the masker's secret will do)
|
||||
mask = hash(reveal)
|
||||
# Generate masker's signature on the mask
|
||||
message = spec.compute_domain_wrapper_root(mask, domain)
|
||||
message = spec.compute_signing_root(mask, domain)
|
||||
masker_signature = bls.Sign(privkeys[masker_index], message)
|
||||
masked_reveal = bls.Aggregate([reveal, masker_signature])
|
||||
|
||||
|
@ -48,7 +48,7 @@ def get_valid_custody_key_reveal(spec, state, period=None):
|
|||
|
||||
# Generate the secret that is being revealed
|
||||
domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch_to_sign)
|
||||
message = spec.compute_domain_wrapper_root(spec.Epoch(epoch_to_sign), domain)
|
||||
message = spec.compute_signing_root(spec.Epoch(epoch_to_sign), domain)
|
||||
reveal = bls.Sign(privkeys[revealer_index], message)
|
||||
return spec.CustodyKeyReveal(
|
||||
revealer_index=revealer_index,
|
||||
|
@ -74,7 +74,7 @@ def get_valid_bit_challenge(spec, state, attestation, invalid_custody_bit=False)
|
|||
|
||||
# Generate the responder key
|
||||
domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch)
|
||||
message = spec.compute_domain_wrapper_root(spec.compute_domain_wrapper_root, domain)
|
||||
message = spec.compute_signing_root(spec.compute_signing_root, domain)
|
||||
responder_key = bls.Sign(privkeys[responder_index], message)
|
||||
|
||||
chunk_count = spec.get_custody_chunk_count(attestation.data.crosslink)
|
||||
|
|
|
@ -30,7 +30,7 @@ def sign_deposit_data(spec, deposit_data, privkey, state=None):
|
|||
pubkey=deposit_data.pubkey,
|
||||
withdrawal_credentials=deposit_data.withdrawal_credentials,
|
||||
amount=deposit_data.amount)
|
||||
message = spec.compute_domain_wrapper_root(deposit_message, domain)
|
||||
message = spec.compute_signing_root(deposit_message, domain)
|
||||
deposit_data.signature = bls.Sign(privkey, message)
|
||||
|
||||
|
||||
|
|
|
@ -26,5 +26,5 @@ def sign_shard_attestation(spec, beacon_state, shard_state, block, participants)
|
|||
|
||||
def get_attestation_signature(spec, beacon_state, shard_state, message_hash, block_epoch, privkey):
|
||||
domain = spec.get_domain(beacon_state, spec.DOMAIN_SHARD_ATTESTER, block_epoch)
|
||||
message = spec.compute_domain_wrapper(message_hash, domain)
|
||||
message = spec.compute_signing_root(message_hash, domain)
|
||||
return bls.Sign(privkey, message)
|
||||
|
|
|
@ -19,7 +19,7 @@ def sign_shard_block(spec, beacon_state, shard_state, block, proposer_index=None
|
|||
|
||||
privkey = privkeys[proposer_index]
|
||||
domain = spec.get_domain(beacon_state, spec.DOMAIN_SHARD_PROPOSER, spec.compute_epoch_of_shard_slot(block.slot))
|
||||
message = spec.compute_domain_wrapper(block, domain)
|
||||
message = spec.compute_signing_root(block, domain)
|
||||
block.signature = bls.Sign(privkey, message)
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ from eth2spec.utils import bls
|
|||
|
||||
def sign_voluntary_exit(spec, state, voluntary_exit, privkey):
|
||||
domain = spec.get_domain(state, spec.DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch)
|
||||
message = spec.compute_domain_wrapper_root(voluntary_exit, domain)
|
||||
message = spec.compute_signing_root(voluntary_exit, domain)
|
||||
return spec.SignedVoluntaryExit(
|
||||
message=voluntary_exit,
|
||||
signature=bls.Sign(privkey, message)
|
||||
|
|
|
@ -108,7 +108,7 @@ def test_invalid_block_sig(spec, state):
|
|||
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
domain = spec.get_domain(state, spec.DOMAIN_BEACON_PROPOSER, spec.compute_epoch_at_slot(block.slot))
|
||||
message = spec.compute_domain_wrapper_root(block, domain)
|
||||
message = spec.compute_signing_root(block, domain)
|
||||
invalid_signed_block = spec.SignedBeaconBlock(
|
||||
message=block,
|
||||
signature=bls.Sign(123456, message)
|
||||
|
@ -417,7 +417,7 @@ def test_voluntary_exit(spec, state):
|
|||
validator_index=validator_index,
|
||||
)
|
||||
domain = spec.get_domain(state, spec.DOMAIN_VOLUNTARY_EXIT)
|
||||
message = spec.compute_domain_wrapper_root(voluntary_exit, domain)
|
||||
message = spec.compute_signing_root(voluntary_exit, domain)
|
||||
signed_voluntary_exit = spec.SignedVoluntaryExit(
|
||||
message=voluntary_exit,
|
||||
signature=bls.Sign(privkeys[validator_index], message)
|
||||
|
|
Loading…
Reference in New Issue