def validate_attestation(crystallized_state: CrystallizedState, active_state: ActiveState, attestation: 'AttestationRecord', block: 'Block', config: Dict[str, Any]=DEFAULT_CONFIG) -> None: if not attestation.slot < block.slot_number: raise Exception("Attestation slot number too high") if not (attestation.slot > block.slot_number - config['cycle_length']): raise Exception( "Attestation slot number too low:\n" "\tFound: %s, Needed greater than: %s" % (attestation.slot, block.slot_number - config['cycle_length']) ) parent_hashes = get_signed_parent_hashes( active_state, block, attestation, config ) attestation_indices = get_attestation_indices( crystallized_state, attestation, config ) # # validate bitfield # if not (len(attestation.attester_bitfield) == get_bitfield_length(len(attestation_indices))): raise Exception( "Attestation has incorrect bitfield length. Found: %s, Expected: %s" % (len(attestation.attester_bitfield), get_bitfield_length(len(attestation_indices))) ) # check if end bits are zero last_bit = len(attestation_indices) if last_bit % 8 != 0: for i in range(8 - last_bit % 8): if has_voted(attestation.attester_bitfield, last_bit + i): raise Exception("Attestation has non-zero trailing bits") # # validate aggregate_sig # in_cycle_slot_height = attestation.slot % config['cycle_length'] pub_keys = [ crystallized_state.validators[index].pubkey for i, index in enumerate(attestation_indices) if has_voted(attestation.attester_bitfield, i) ] message = blake( in_cycle_slot_height.to_bytes(8, byteorder='big') + b''.join(parent_hashes) + attestation.shard_id.to_bytes(2, byteorder='big') + attestation.shard_block_hash ) if not bls.verify(message, bls.aggregate_pubs(pub_keys), attestation.aggregate_sig): raise Exception("Attestation aggregate signature fails")
def update_ffg_and_crosslink_progress(crystallized_state, crosslinks, ffg_voter_bitfield, votes, config=DEFAULT_CONFIG): # Verify the attestations of crosslink hashes crosslink_votes = { vote.shard_block_hash + vote.shard_id.to_bytes(2, 'big'): vote.voter_bitfield for vote in crosslinks } new_ffg_bitfield = ffg_voter_bitfield total_voters = 0 # The shards that are selected to be crosslinking crosslink_shards = get_crosslink_shards(crystallized_state, config=config) for vote in votes: attestation = get_crosslink_aggvote_msg(vote.shard_id, vote.shard_block_hash, crystallized_state) # Check if this shard is in the crosslink shards list assert vote.shard_id in crosslink_shards indices = get_crosslink_notaries( crystallized_state, vote.shard_id, crosslink_shards=crosslink_shards, config=config, ) votekey = vote.shard_block_hash + vote.shard_id.to_bytes(2, 'big') if votekey not in crosslink_votes: crosslink_votes[votekey] = b"" * get_bitfield_length(len(indices)) bitfield = crosslink_votes[votekey] pubs = [] for i, index in enumerate(indices): if has_voted(vote.notary_bitfield, i): pubs.append(crystallized_state.active_validators[index].pubkey) if has_voted(new_ffg_bitfield, index): new_ffg_bitfield = set_voted(new_ffg_bitfield, index) bitfield = set_voted(bitfield, i) total_voters += 1 assert bls.verify(attestation, bls.aggregate_pubs(pubs), vote.aggregate_sig) crosslink_votes[votekey] = bitfield print('Verified aggregate vote') new_crosslinks = [ PartialCrosslinkRecord(shard_id=int.from_bytes(h[32:], 'big'), shard_block_hash=h[:32], voter_bitfield=crosslink_votes[h]) for h in sorted(crosslink_votes.keys()) ] return new_crosslinks, new_ffg_bitfield, total_voters
def process_attestations(validator_set, attestation_indices, attestation_bitfield, msg, aggregate_sig): # Verify the attestations of the parent pubs = [] attesters = [] assert len(attestation_bitfield) == get_bitfield_length( len(attestation_indices)) for i, index in enumerate(attestation_indices): if has_voted(attestation_bitfield, i): pubs.append(validator_set[index].pubkey) attesters.append(index) assert len(attesters) <= 128 assert bls.verify(msg, bls.aggregate_pubs(pubs), aggregate_sig) print('Verified aggregate sig') return attesters
def validate_attestation(crystallized_state: CrystallizedState, active_state: ActiveState, attestation: 'AttestationRecord', block: 'Block', parent_block: 'Block', config: Dict[str, Any] = DEFAULT_CONFIG) -> None: # Verify attestation.slot_number if not attestation.slot <= parent_block.slot_number: raise Exception("Attestation slot number too high:\n" "\tFound: %s Needed less than or equal to %s" % (attestation.slot, parent_block.slot_number)) if not (attestation.slot >= max( parent_block.slot_number - config['cycle_length'] + 1, 0)): raise Exception( "Attestation slot number too low:\n" "\tFound: %s, Needed greater than or equalt to: %s" % (attestation.slot, max(parent_block.slot_number - config['cycle_length'] + 1, 0))) # TODO: Verify that the justified_slot and justified_block_hash given are in # the chain and are equal to or earlier than the last_justified_slot # in the crystallized state. parent_hashes = get_signed_parent_hashes(active_state, block, attestation, config) attestation_indices = get_attestation_indices(crystallized_state, attestation, config) # # validate bitfield # if not (len(attestation.attester_bitfield) == get_bitfield_length( len(attestation_indices))): raise Exception( "Attestation has incorrect bitfield length. Found: %s, Expected: %s" % (len(attestation.attester_bitfield), get_bitfield_length(len(attestation_indices)))) # check if end bits are zero last_bit = len(attestation_indices) if last_bit % 8 != 0: for i in range(8 - last_bit % 8): if has_voted(attestation.attester_bitfield, last_bit + i): raise Exception("Attestation has non-zero trailing bits") # # validate aggregate_sig # pub_keys = [ crystallized_state.validators[index].pubkey for i, index in enumerate(attestation_indices) if has_voted(attestation.attester_bitfield, i) ] message = blake( attestation.slot.to_bytes(8, byteorder='big') + b''.join(parent_hashes) + attestation.shard_id.to_bytes(2, byteorder='big') + attestation.shard_block_hash + attestation.justified_slot.to_bytes(8, 'big')) if not bls.verify(message, bls.aggregate_pubs(pub_keys), attestation.aggregate_sig): raise Exception("Attestation aggregate signature fails")
def test_bitfield_length(attester_count, bitfield_length): assert get_bitfield_length(attester_count) == bitfield_length
def validate_attestation(crystallized_state: CrystallizedState, active_state: ActiveState, attestation: 'AttestationRecord', block: 'Block', parent_block: 'Block', config: Dict[str, Any] = DEFAULT_CONFIG) -> bool: # # validate slot number # if not attestation.slot <= parent_block.slot_number: raise ValidationError("Attestation slot number too high:\n" "\tFound: %s Needed less than or equal to %s" % (attestation.slot, parent_block.slot_number)) if not (attestation.slot >= max( parent_block.slot_number - config['cycle_length'] + 1, 0)): raise ValidationError( "Attestation slot number too low:\n" "\tFound: %s, Needed greater than or equalt to: %s" % (attestation.slot, max(parent_block.slot_number - config['cycle_length'] + 1, 0))) # # validate justified_slot and justified_block_hash # if attestation.justified_slot > crystallized_state.last_justified_slot: raise ValidationError( "attestation.justified_slot %s should be equal to or earlier than" " crystallized_state.last_justified_slot %s" % ( attestation.justified_slot, crystallized_state.last_justified_slot, )) justified_block = active_state.chain.get_block_by_hash( attestation.justified_block_hash) if justified_block is None: raise ValidationError( "justified_block_hash %s is not in the canonical chain" % attestation.justified_block_hash) if justified_block.slot_number != attestation.justified_slot: raise ValidationError( "justified_slot %s doesn't match justified_block_hash" % attestation.justified_slot) parent_hashes = get_signed_parent_hashes(active_state, block, attestation, config) attestation_indices = get_attestation_indices(crystallized_state, attestation, config) # # validate bitfield # if not (len(attestation.attester_bitfield) == get_bitfield_length( len(attestation_indices))): raise ValidationError( "Attestation has incorrect bitfield length. Found: %s, Expected: %s" % (len(attestation.attester_bitfield), get_bitfield_length(len(attestation_indices)))) # check if end bits are zero last_bit = len(attestation_indices) if last_bit % 8 != 0: for i in range(8 - last_bit % 8): if has_voted(attestation.attester_bitfield, last_bit + i): raise ValidationError("Attestation has non-zero trailing bits") # # validate aggregate_sig # pub_keys = [ crystallized_state.validators[validator_index].pubkey for committee_index, validator_index in enumerate(attestation_indices) if has_voted(attestation.attester_bitfield, committee_index) ] message = blake( attestation.slot.to_bytes(8, byteorder='big') + b''.join(parent_hashes) + attestation.shard_id.to_bytes(2, byteorder='big') + attestation.shard_block_hash + attestation.justified_slot.to_bytes(8, 'big')) if not bls.verify(message, bls.aggregate_pubs(pub_keys), attestation.aggregate_sig): raise ValidationError("Attestation aggregate signature fails") return True