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 mock_make_attestations(parent_state, block, attester_share=0.8): crystallized_state, active_state = parent_state cycle_length = config['cycle_length'] in_cycle_slot_height = block.slot_number % cycle_length indices = crystallized_state.indices_for_slots[cycle_length + in_cycle_slot_height] print("Generating attestations for shards: %s" % len(indices)) attestations = [] for shard_and_committee in indices: shard_id = shard_and_committee.shard_id committee_indices = shard_and_committee.committee print("Generating attestation for shard %s" % shard_id) print("Committee size %s" % len(committee_indices)) # Create attestation attestation = AttestationRecord( slot=block.slot_number, shard_id=shard_and_committee.shard_id, oblique_parent_hashes=[], shard_block_hash=blake(bytes(str(shard_id), 'utf-8')), attester_bitfield=get_empty_bitfield(len(committee_indices))) # Randomly pick indices to include is_attesting = [ random.random() < attester_share for _ in range(len(committee_indices)) ] # Proposer always attests is_attesting[0] = True # Generating signatures and aggregating result parent_hashes = get_hashes_to_sign(active_state, block, config) message = blake( attestation.slot.to_bytes(8, byteorder='big') + b''.join(parent_hashes) + shard_id.to_bytes(2, byteorder='big') + attestation.shard_block_hash) sigs = [ bls.sign(message, keymap[crystallized_state.validators[indice].pubkey]) for i, indice in enumerate(committee_indices) if is_attesting[i] ] attestation.aggregate_sig = bls.aggregate_sigs(sigs) print('Aggregated sig') attestation_bitfield = get_empty_bitfield(len(committee_indices)) for i, attesting in enumerate(is_attesting): if attesting: attestation_bitfield = set_voted(attestation_bitfield, i) attestation.attester_bitfield = attestation_bitfield print('Aggregate bitfield:', bin(int.from_bytes(attestation_bitfield, 'big'))) attestations.append(attestation) return attestations
def test_validate_attestation_attester_bitfield(attestation_validation_fixture, config): (crystallized_state, active_state, original_attestation, block, parent_block) = attestation_validation_fixture attestation = copy.deepcopy(original_attestation) attestation.attester_bitfield = get_empty_bitfield(10) with pytest.raises(ValidationError): validate_attestation( crystallized_state, active_state, attestation, block, parent_block, config, ) attestation = copy.deepcopy(original_attestation) attestation_indices = get_attestation_indices(crystallized_state, attestation, config) last_bit = len(attestation_indices) attestation.attester_bitfield = set_voted(attestation.attester_bitfield, last_bit) with pytest.raises(ValidationError): validate_attestation( crystallized_state, active_state, attestation, block, parent_block, config, )
def test_bitfield_all_votes(): attesters = list(range(10)) bitfield = get_empty_bitfield(len(attesters)) for attester in attesters: bitfield = set_voted(bitfield, attester) for attester in attesters: assert has_voted(bitfield, attester) assert bitfield == b'\xff\xc0'
def test_bitfield_some_votes(): attesters = list(range(10)) voters = [0, 4, 5, 9] bitfield = get_empty_bitfield(len(attesters)) for voter in voters: bitfield = set_voted(bitfield, voter) assert bitfield == b'\x8c\x40' for attester in attesters: if attester in voters: assert has_voted(bitfield, attester) else: assert not has_voted(bitfield, attester)
def test_bitfield_single_votes(): attesters = list(range(10)) bitfield = get_empty_bitfield(len(attesters)) assert set_voted(bitfield, 0) == b'\x80\x00' assert set_voted(bitfield, 1) == b'\x40\x00' assert set_voted(bitfield, 2) == b'\x20\x00' assert set_voted(bitfield, 7) == b'\x01\x00' assert set_voted(bitfield, 8) == b'\x00\x80' assert set_voted(bitfield, 9) == b'\x00\x40' for voter in attesters: bitfield = set_voted(b'\x00\x00', voter) for attester in attesters: if attester == voter: assert has_voted(bitfield, attester) else: assert not has_voted(bitfield, attester)
def mock_make_attestations(parent_state, block, attester_share=0.8): crystallized_state, active_state = parent_state cycle_length = config['cycle_length'] in_cycle_slot_height = block.slot_number % cycle_length indices = crystallized_state.shard_and_committee_for_slots[ cycle_length + in_cycle_slot_height] print("Generating attestations for shards: %s" % len(indices)) proposer_index_in_committee, proposer_shard_id = get_proposer_position( block, crystallized_state, config=config, ) attestations = [] for shard_and_committee in indices: shard_id = shard_and_committee.shard_id committee_indices = shard_and_committee.committee print("Generating attestation for shard %s" % shard_id) print("Committee size %s" % len(committee_indices)) justified_slot = crystallized_state.last_justified_slot justified_block_hash = active_state.chain.get_block_by_slot_number( justified_slot).hash # Create attestation attestation = AttestationRecord( slot=block.slot_number, shard_id=shard_and_committee.shard_id, oblique_parent_hashes=[], shard_block_hash=blake(bytes(str(shard_id), 'utf-8')), attester_bitfield=get_empty_bitfield(len(committee_indices)), justified_slot=justified_slot, justified_block_hash=justified_block_hash, ) # fill with roughly attester share fraction of voters is_attesting = [ i < attester_share * len(committee_indices) for i in range(len(committee_indices)) ] # Proposer always attests if shard_id == proposer_shard_id: is_attesting[proposer_index_in_committee] = True # Generating signatures and aggregating result parent_hashes = get_hashes_to_sign(active_state, block, config) message = blake( attestation.slot.to_bytes(8, byteorder='big') + b''.join(parent_hashes) + shard_id.to_bytes(2, byteorder='big') + attestation.shard_block_hash + attestation.justified_slot.to_bytes(8, byteorder='big')) sigs = [ bls.sign(message, keymap[crystallized_state.validators[indice].pubkey]) for i, indice in enumerate(committee_indices) if is_attesting[i] ] attestation.aggregate_sig = bls.aggregate_sigs(sigs) print('Aggregated sig') attestation_bitfield = get_empty_bitfield(len(committee_indices)) for i, attesting in enumerate(is_attesting): if attesting: attestation_bitfield = set_voted(attestation_bitfield, i) attestation.attester_bitfield = attestation_bitfield print('Aggregate bitfield:', bin(int.from_bytes(attestation_bitfield, 'big'))) attestations.append(attestation) return attestations
def make_unfinished_block(parent_state, parent, skips, attester_share=0.8, crosslink_shards_and_shares=None): if crosslink_shards_and_shares is None: crosslink_shards_and_shares = [] crystallized_state, active_state = parent_state parent_attestation = serialize(parent) indices, proposer = get_attesters_and_proposer( crystallized_state, active_state, skips, config ) print('Selected indices: %r' % indices) print('Selected block proposer: %d' % proposer) # Randomly pick indices to include is_attesting = [random.random() < attester_share for _ in indices] # Attestations sigs = [ bls.sign( parent_attestation, keymap[crystallized_state.active_validators[indices[i]].pubkey] ) for i, attesting in enumerate(is_attesting) if attesting ] attestation_aggregate_sig = bls.aggregate_sigs(sigs) print('Aggregated sig') attestation_bitfield = get_empty_bitfield(len(indices)) for i, attesting in enumerate(is_attesting): if attesting: attestation_bitfield = set_voted(attestation_bitfield, i) print('Aggregate bitfield:', bin(int.from_bytes(attestation_bitfield, 'big'))) # Randomly pick indices to include for crosslinks shard_aggregate_votes = [] # The shards that are selected to be crosslinking crosslink_shards = get_crosslink_shards(crystallized_state, config=config) for shard, crosslinker_share in crosslink_shards_and_shares: # Check if this shard is in the crosslink shards list assert shard in crosslink_shards print('Making crosslink in shard %d' % shard) indices = get_crosslink_notaries(crystallized_state, shard, crosslink_shards=crosslink_shards, config=config) print('Indices: %r' % indices) is_notarizing = [random.random() < attester_share for _ in indices] notary_bitfield = get_empty_bitfield(len(indices)) for i, notarizing in enumerate(is_notarizing): if notarizing: notary_bitfield = set_voted(notary_bitfield, i) print('Bitfield:', bin(int.from_bytes(notary_bitfield, 'big'))) shard_block_hash = blake(bytes([shard])) crosslink_attestation_hash = get_crosslink_aggvote_msg( shard, shard_block_hash, crystallized_state ) sigs = [ bls.sign( crosslink_attestation_hash, keymap[crystallized_state.active_validators[indices[i]].pubkey] ) for i, notarizing in enumerate(is_notarizing) if notarizing ] v = AggregateVote( shard_id=shard, shard_block_hash=shard_block_hash, notary_bitfield=notary_bitfield, aggregate_sig=list(bls.aggregate_sigs(sigs)) ) shard_aggregate_votes.append(v) print('Added %d shard aggregate votes' % len(crosslink_shards_and_shares)) block = Block( parent_hash=blake(parent_attestation), skip_count=skips, randao_reveal=blake(str(random.random()).encode('utf-8')), attestation_bitfield=attestation_bitfield, attestation_aggregate_sig=list(attestation_aggregate_sig), shard_aggregate_votes=shard_aggregate_votes, main_chain_ref=b'\x00'*32, state_hash=b'\x00'*64 ) return block, proposer
def test_bitfield_multiple_votes(): bitfield = get_empty_bitfield(1) bitfield = set_voted(bitfield, 0) bitfield = set_voted(bitfield, 0) assert has_voted(bitfield, 0)