def test_find_conflicts(self): dag = Dag(0) watcher = ConflictWatcher(dag) actor1 = Private.publickey(Private.generate()) actor2 = Private.publickey(Private.generate()) block1_hash = ChainGenerator.insert_dummy(dag, [dag.genesis_hash()], 1) watcher.on_new_block_by_validator(block1_hash, 1, actor1) block2_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2) watcher.on_new_block_by_validator(block2_hash, 1, actor2) block2c_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2) watcher.on_new_block_by_validator(block2c_hash, 1, actor2) # block3_hash = ChainGenerator.insert_dummy(dag, [block2_hash, block2c_hash], 3) # watcher.on_new_block_by_validator(block3_hash, 1, actor3) tops = dag.get_top_hashes() explicits, candidate_groups = watcher.find_conflicts_in_between(tops) self.assertEqual(len(explicits), 0) self.assertEqual(len(candidate_groups), 1) self.assertEqual(len(candidate_groups[0]), 2) self.assertIn(block2_hash, candidate_groups[0]) self.assertIn(block2c_hash, candidate_groups[0])
def test_different_timeslot_watch(self): dag = Dag(0) conflict_watcher = ConflictWatcher(dag) actor1 = Private.publickey(Private.generate()) actor2 = Private.publickey(Private.generate()) actor3 = Private.publickey(Private.generate()) block1_hash = ChainGenerator.insert_dummy(dag, [dag.genesis_hash()], 1) conflict_watcher.on_new_block_by_validator(block1_hash, 1, actor1) block2_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2) conflict_watcher.on_new_block_by_validator(block2_hash, 1, actor2) # second block is signed by third validator # its not possible by usual means, but quite possible when we have two different epoch seeds block2c_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2) conflict_watcher.on_new_block_by_validator(block2c_hash, 1, actor3) block3_hash = ChainGenerator.insert_dummy(dag, [block2_hash, block2c_hash], 3) conflict_watcher.on_new_block_by_validator(block3_hash, 1, actor3) conflicts = conflict_watcher.get_conflicts_by_block(block3_hash) self.assertEqual(len(conflicts), 2) self.assertIn(block2c_hash, conflicts) self.assertIn(block3_hash, conflicts)
def test_same_timeslot_watch(self): dag = Dag(0) conflict_watcher = ConflictWatcher(dag) actor1 = Private.publickey(Private.generate()) actor2 = Private.publickey(Private.generate()) actor3 = Private.publickey(Private.generate()) block1_hash = ChainGenerator.insert_dummy(dag, [dag.genesis_hash()], 1) conflict_watcher.on_new_block_by_validator(block1_hash, 1, actor1) block2_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2) conflict_watcher.on_new_block_by_validator(block2_hash, 1, actor2) block2c_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2) conflict_watcher.on_new_block_by_validator(block2c_hash, 1, actor2) block3_hash = ChainGenerator.insert_dummy(dag, [block2_hash, block2c_hash], 3) conflict_watcher.on_new_block_by_validator(block3_hash, 1, actor3) conflicts = conflict_watcher.get_conflicts_by_block(block2_hash) self.assertEqual(len(conflicts), 2) self.assertIn(block2_hash, conflicts) self.assertIn(block2c_hash, conflicts) conflicts = conflict_watcher.get_conflicts_by_block(block1_hash) self.assertEqual(conflicts, None)
def test_explicit_conflict(self): dag = Dag(0) watcher = ConflictWatcher(dag) actor1 = Private.publickey(Private.generate()) actor2 = Private.publickey(Private.generate()) block1_hash = ChainGenerator.insert_dummy(dag, [dag.genesis_hash()], 1) watcher.on_new_block_by_validator(block1_hash, 1, actor2) block2_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2) watcher.on_new_block_by_validator(block2_hash, 1, actor1) block3_hash = ChainGenerator.insert_dummy(dag, [block2_hash], 3) watcher.on_new_block_by_validator(block3_hash, 1, actor2) block3c_hash = ChainGenerator.insert_dummy(dag, [block2_hash], 3) watcher.on_new_block_by_validator(block3c_hash, 1, actor2) tops = dag.get_top_hashes() #here block was signed by node even before merge appeared #this is explicit merge and both following blocks are conflicting explicits, candidates = watcher.find_conflicts_in_between(tops) self.assertEqual(len(explicits), 2) self.assertEqual(len(candidates), 0) self.assertIn(block3_hash, explicits) self.assertIn(block3c_hash, explicits)
def test_both_types_of_conflicts(self): dag = Dag(0) watcher = ConflictWatcher(dag) actor1 = Private.publickey(Private.generate()) actor2 = Private.publickey(Private.generate()) actor3 = Private.publickey(Private.generate()) block1_hash = ChainGenerator.insert_dummy(dag, [dag.genesis_hash()], 1) watcher.on_new_block_by_validator(block1_hash, 1, actor1) block2_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2) watcher.on_new_block_by_validator(block2_hash, 1, actor2) block2c_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2) watcher.on_new_block_by_validator(block2c_hash, 1, actor2) block3_hash = ChainGenerator.insert_dummy(dag, [block2_hash], 3) watcher.on_new_block_by_validator(block3_hash, 1, actor3) #this is possible if we have two epoch seeds block4_hash = ChainGenerator.insert_dummy(dag, [block2c_hash], 4) watcher.on_new_block_by_validator(block4_hash, 1, actor1) tops = dag.get_top_hashes() explicits, candidate_groups = watcher.find_conflicts_in_between(tops) self.assertEqual(len(explicits), 1) self.assertIn(block4_hash, explicits) self.assertEqual(len(candidate_groups), 1) self.assertEqual(len(candidate_groups[0]), 2) self.assertIn(block2_hash, candidate_groups[0]) self.assertIn(block2c_hash, candidate_groups[0])
def create_positive_gossip_transaction(block_hash, node_private): tx = PositiveGossipTransaction() tx.timestamp = Time.get_current_time() tx.block_hash = block_hash tx.pubkey = Private.publickey(node_private) tx.signature = Private.sign(tx.get_hash(), node_private) return tx
def create_negative_gossip_transaction(number_of_block, node_private): tx = NegativeGossipTransaction() tx.timestamp = Time.get_current_time() tx.number_of_block = number_of_block tx.pubkey = Private.publickey(node_private) tx.signature = Private.sign(tx.get_hash(), node_private) return tx
def create_public_key_transaction(generated_private, epoch_hash, validator_index, node_private): tx = PublicKeyTransaction() tx.generated_pubkey = Private.publickey(generated_private) tx.pubkey_index = validator_index tx.signature = Private.sign(tx.get_signing_hash(epoch_hash), node_private) return tx
def create_payment_transaction(from_tx, amount, to, node_private): tx = PaymentTransaction() tx.from_tx = from_tx tx.amount = amount tx.to = to tx.pubkey = Private.publickey(node_private) tx.signature = Private.sign(tx.get_hash(), node_private) return tx
def get_payment_transactions_for_signing(self, block_number): node_public = Private.publickey(self.block_signer.private_key) pseudo_address = sha256(node_public).digest() block_reward = TransactionFactory.create_block_reward( pseudo_address, block_number) block_reward_hash = block_reward.get_hash() self.owned_utxos.append(block_reward_hash) payment_txs = [block_reward] + self.mempool.pop_payment_transactions() return payment_txs
def test_different_epoch_watch(self): dag = Dag(0) conflict_watcher = ConflictWatcher(dag) actor1 = Private.publickey(Private.generate()) actor2 = Private.publickey(Private.generate()) actor3 = Private.publickey(Private.generate()) block1_hash = ChainGenerator.insert_dummy(dag, [dag.genesis_hash()], 1) conflict_watcher.on_new_block_by_validator(block1_hash, 1, actor1) block2_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2) conflict_watcher.on_new_block_by_validator(block2_hash, 1, actor2) block2c_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2) conflict_watcher.on_new_block_by_validator(block2c_hash, 1, actor2) block3_hash = ChainGenerator.insert_dummy(dag, [block2_hash, block2c_hash], 3) conflict_watcher.on_new_block_by_validator(block3_hash, 1, actor3) #switch to next epoch block4_hash = ChainGenerator.insert_dummy(dag, [block3_hash], 4) conflict_watcher.on_new_block_by_validator(block4_hash, 2, actor2) block4c_hash = ChainGenerator.insert_dummy(dag, [block3_hash], 4) conflict_watcher.on_new_block_by_validator(block4c_hash, 2, actor2) #first epoch conflicts conflicts = conflict_watcher.get_conflicts_by_block(block2_hash) self.assertEqual(len(conflicts), 2) self.assertIn(block2_hash, conflicts) self.assertIn(block2c_hash, conflicts) #second epoch conflicts of the same public key conflicts = conflict_watcher.get_conflicts_by_block(block4_hash) self.assertEqual(len(conflicts), 2) self.assertIn(block4_hash, conflicts) self.assertIn(block4c_hash, conflicts) conflicts = conflict_watcher.get_conflicts_by_block(block1_hash) self.assertEqual(conflicts, None)
def extract_shared_random(self, block_hash): if block_hash == self.dag.genesis_block().get_hash(): return 0 private_keys = self.get_private_keys_for_epoch(block_hash) public_keys = self.get_public_keys_for_epoch(block_hash) published_private_keys = self.filter_out_skipped_public_keys( private_keys, public_keys) random_pieces_list = self.get_random_splits_for_epoch(block_hash) # self.log("pubkeys") # for _, public_key in public_keys.items(): # self.log(Keys.to_visual_string(public_key)) # self.log("privkeys converted") private_key_count = 0 # amount of sent keys matching_keys_count = 0 # amount of keys which have matching pubkeys for key in published_private_keys: if not key: # self.log("None") continue pubkey = Private.publickey(key) # self.log(Keys.to_visual_string(pubkey)) private_key_count += 1 if Keys.to_bytes(pubkey) in public_keys.values(): matching_keys_count += 1 pubkey_count = len(public_keys) self.log("pubkey count", pubkey_count, "privkey count", private_key_count, "of them matching", matching_keys_count) half_of_pubkeys = int(pubkey_count / 2) + 1 half_of_privkeys = int(private_key_count / 2) + 1 # TODO we should have a special handling for when not enough keys was sent for each round assert pubkey_count > 1, "Not enough public keys to decrypt random" assert private_key_count > 1, "Not enough private keys to decrypt random" assert pubkey_count >= half_of_privkeys, "Not enough public keys to decrypt random" assert private_key_count >= half_of_pubkeys, "Not enough private keys to decrypt random" assert matching_keys_count >= half_of_pubkeys, "Not enough matching keys in epoch" assert matching_keys_count >= half_of_privkeys, "Not enough matching keys in epoch" ordered_private_keys_count = len( private_keys) # total amount of both sent and unsent keys randoms_list = [] for random_pieces in random_pieces_list: assert ordered_private_keys_count >= len( random_pieces ), "Amount of splits must match amount of public keys" random = decode_random( random_pieces, Keys.list_from_bytes(published_private_keys)) randoms_list.append(random) seed = sum_random(randoms_list) return seed
def filter_out_skipped_public_keys(private_keys, public_keys): filtered_private_keys = [] for private_key in private_keys: if private_key == None: filtered_private_keys.append(None) else: expected_public = Private.publickey( Keys.from_bytes(private_key)) if Keys.to_bytes(expected_public) in public_keys.values(): filtered_private_keys.append(private_key) return filtered_private_keys
def test_pack_parse_stakerelease_transaction(self): private = Private.generate() original = StakeReleaseTransaction() original.pubkey = Private.publickey(private) original.signature = Private.sign(original.get_hash(), Private.generate()) raw = original.pack() restored = StakeReleaseTransaction() restored.parse(raw) self.assertEqual(original.get_hash(), restored.get_hash())
def test_pack_parse_penalty_transaction(self): original = PenaltyTransaction() original.violator_pubkey = Private.publickey(Private.generate()) original.conflicts = [os.urandom(32), os.urandom(32), os.urandom(32)] original.signature = Private.sign(original.get_hash(), Private.generate()) raw = original.pack() restored = PenaltyTransaction() restored.parse(raw) self.assertEqual(original.get_hash(), restored.get_hash())
def test_pack_parse_stakehold_transaction(self): private = Private.generate() original = StakeHoldTransaction() original.amount = 1000 original.pubkey = Private.publickey(private) original.signature = Private.sign(original.get_hash(), private) raw = original.pack() restored = StakeHoldTransaction() restored.parse(raw) self.assertEqual(original.get_hash(), restored.get_hash())
def test_parse_pack_gossip_negative(self): private = Private.generate() original = NegativeGossipTransaction() original.pubkey = Private.publickey(private) original.timestamp = Time.get_current_time() original.number_of_block = 47 original.signature = Private.sign(original.get_hash(), private) raw = original.pack() restored = NegativeGossipTransaction() restored.parse(raw) self.assertEqual(original.get_hash(), restored.get_hash())
def test_hold_stake(self): dag = Dag(0) epoch = Epoch(dag) permissions = Permissions(epoch) node_private = Private.generate() initial_validators = Validators.read_genesis_validators_from_file() genesis_hash = dag.genesis_block().get_hash() prev_hash = genesis_hash for i in range(1, 9): block = BlockFactory.create_block_with_timestamp([prev_hash], BLOCK_TIME * i) signed_block = BlockFactory.sign_block(block, node_private) dag.add_signed_block(i, signed_block) prev_hash = block.get_hash() block = BlockFactory.create_block_with_timestamp([prev_hash], BLOCK_TIME * 9) tx = StakeHoldTransaction() tx.amount = 1000 node_new_private = Private.generate() tx.pubkey = Private.publickey(node_new_private) tx.signature = Private.sign(tx.get_hash(), node_new_private) block.system_txs.append(tx) signed_block = BlockFactory.sign_block(block, node_private) dag.add_signed_block(9, signed_block) resulting_validators = permissions.get_validators(block.get_hash()) pub_keys = [] for validator in resulting_validators: pub_keys.append(validator.public_key) self.assertIn(Private.publickey(node_new_private), pub_keys)
def test_pack_parse_penalty_gossip_transaction(self): private = Private.generate() original = PenaltyGossipTransaction() original.timestamp = Time.get_current_time() block = BlockFactory.create_block_with_timestamp( [], timestamp=original.timestamp) gossip_positive_tx = PositiveGossipTransaction() gossip_positive_tx.pubkey = Private.publickey(private) gossip_positive_tx.timestamp = Time.get_current_time() gossip_positive_tx.block_hash = BlockFactory.sign_block( block, private).get_hash() gossip_positive_tx.signature = Private.sign(original.get_hash(), private) gossip_negative_tx = NegativeGossipTransaction() gossip_negative_tx.pubkey = Private.publickey(private) gossip_negative_tx.timestamp = Time.get_current_time() gossip_negative_tx.number_of_block = 47 gossip_negative_tx.signature = Private.sign(original.get_hash(), private) original.conflicts = [ gossip_positive_tx.get_hash(), gossip_negative_tx.get_hash() ] original.signature = Private.sign(original.get_hash(), private) original.block_hash = BlockFactory.sign_block(block, private).get_hash() raw = original.pack() restored = PenaltyGossipTransaction() restored.parse(raw) self.assertEqual(original.get_hash(), restored.get_hash())
def test_parse_pack_gossip_positive(self): private = Private.generate() original = PositiveGossipTransaction() original.pubkey = Private.publickey(private) original.timestamp = Time.get_current_time() block = BlockFactory.create_block_with_timestamp( [], timestamp=original.timestamp) original.block_hash = BlockFactory.sign_block(block, private).get_hash() original.signature = Private.sign(original.get_hash(), private) raw = original.pack() restored = PositiveGossipTransaction() restored.parse(raw) self.assertEqual(original.get_hash(), restored.get_hash())
def test_encryption_and_decryption(self): private_keys = [] public_keys = [] for i in range(0, 5): private = Private.generate() private_keys.append(private) public_keys.append(Private.publickey(private)) raw_private_keys = Keys.list_to_bytes(private_keys) decoded_private_keys = Keys.list_from_bytes(raw_private_keys) random_bytes = os.urandom(32) random_value = int.from_bytes(random_bytes, byteorder='big') splits = split_secret(random_bytes, 3, 5) encoded_splits = encode_splits(splits, public_keys) decoded_random = decode_random(encoded_splits, decoded_private_keys) self.assertEqual(random_value, decoded_random)
def test_decryption_failure(self): private_keys = [] public_keys = [] for i in range(0, 5): private = Private.generate() private_keys.append(private) public_keys.append(Private.publickey(private)) raw_private_keys = Keys.list_to_bytes(private_keys) decoded_private_keys = Keys.list_from_bytes(raw_private_keys) random_bytes = os.urandom(32) random_value = int.from_bytes(random_bytes, byteorder='big') splits = split_secret(random_bytes, 3, 5) encoded_splits = encode_splits(splits, public_keys) encoded_splits[2] = os.urandom(len( encoded_splits[2])) #corrupt one of the splits encoded_splits[4] = os.urandom(len( encoded_splits[4])) #corrupt another split decoded_random = decode_random(encoded_splits, decoded_private_keys) self.assertEqual(random_value, decoded_random)
def test_explicit_conflict_right_on_common_ancestor(self): dag = Dag(0) watcher = ConflictWatcher(dag) actor2 = Private.publickey(Private.generate()) #consider common ancestor already resolved block1_hash = ChainGenerator.insert_dummy(dag, [dag.genesis_hash()], 1) watcher.on_new_block_by_validator(block1_hash, 1, actor2) block2_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2) watcher.on_new_block_by_validator(block2_hash, 1, actor2) block2c_hash = ChainGenerator.insert_dummy(dag, [block1_hash], 2) watcher.on_new_block_by_validator(block2c_hash, 1, actor2) tops = dag.get_top_hashes() explicits, candidates = watcher.find_conflicts_in_between(tops) self.assertEqual(len(explicits), 2) self.assertEqual(len(candidates), 0) self.assertIn(block2_hash, explicits) self.assertIn(block2c_hash, explicits)
def __init__(self, genesis_creation_time, node_id, network, block_signer=BlockSigner(Private.generate()), validators=Validators(), behaviour=Behaviour(), logger=DummyLogger()): self.logger = logger self.dag = Dag(genesis_creation_time) self.epoch = Epoch(self.dag) self.epoch.set_logger(self.logger) self.permissions = Permissions(self.epoch, validators) self.mempool = Mempool() self.utxo = Utxo(self.logger) self.conflict_watcher = ConflictWatcher(self.dag) self.behaviour = behaviour self.block_signer = block_signer self.node_pubkey = Private.publickey(block_signer.private_key) self.logger.info("Public key is %s", Keys.to_visual_string(self.node_pubkey)) self.network = network self.node_id = node_id self.epoch_private_keys = [] # TODO make this single element # self.epoch_private_keys where first element is era number, and second is key to reveal commited random self.reveals_to_send = {} self.sent_shares_epochs = [] # epoch hashes of secret shares self.last_expected_timeslot = 0 self.last_signed_block_number = 0 self.tried_to_sign_current_block = False self.owned_utxos = [] self.terminated = False self.blocks_buffer = [ ] # uses while receive block and do not have its ancestor in local dag (before verify)
def validate_private_transactions_in_block(self, block, current_round): private_key_transactions = [] for tx in block.system_txs: if isinstance(tx, PrivateKeyTransaction): private_key_transactions.append(tx) private_key_transactions_count_in_block = len(private_key_transactions) if current_round != Round.PRIVATE: if private_key_transactions_count_in_block > 0: raise AcceptionException( "PrivateKeyTransaction was found in round " + current_round.name) return if private_key_transactions_count_in_block == 0: raise AcceptionException( "Block has no PrivateKeyTransaction in private round!") elif private_key_transactions_count_in_block > 1: raise AcceptionException( "Block has more than one PrivateKeyTransaction!") return # this check is too slow and I'm not sure if it's needed at all private_key = private_key_transactions[0].key expected_public = Private.publickey(private_key) epoch_hashes = self.epoch.get_epoch_hashes() for top, _epoch_hash in epoch_hashes.items(): public_keys = self.epoch.get_public_keys_for_epoch(top) if not Keys.to_bytes(expected_public) in public_keys.values(): raise AcceptionException( "No corresponding public key was found for private key in PrivateKeyTransaction!" )
def test_secret_sharing_rounds(self): dag = Dag(0) epoch = Epoch(dag) dummy_private = Private.generate() signers = [] for i in range(0, ROUND_DURATION + 1): signers.append(Private.generate()) private_keys = [] block_number = 1 genesis_hash = dag.genesis_block().get_hash() prev_hash = genesis_hash signer_index = 0 for i in Epoch.get_round_range(1, Round.PUBLIC): private = Private.generate() private_keys.append(private) signer = signers[signer_index] pubkey_tx = PublicKeyTransaction() pubkey_tx.generated_pubkey = Private.publickey(private) pubkey_tx.pubkey_index = signer_index pubkey_tx.signature = Private.sign( pubkey_tx.get_signing_hash(genesis_hash), signer) block = Block() block.timestamp = i * BLOCK_TIME block.prev_hashes = [prev_hash] block.system_txs = [pubkey_tx] signed_block = BlockFactory.sign_block(block, signer) dag.add_signed_block(i, signed_block) signer_index += 1 prev_hash = block.get_hash() prev_hash = ChainGenerator.fill_with_dummies( dag, prev_hash, Epoch.get_round_range(1, Round.COMMIT)) public_keys = [] for private in private_keys: public_keys.append(Private.publickey(private)) randoms_list = [] expected_random_pieces = [] for i in Epoch.get_round_range(1, Round.SECRETSHARE): random_bytes = os.urandom(32) random_value = int.from_bytes(random_bytes, byteorder='big') split_random_tx = SplitRandomTransaction() splits = split_secret(random_bytes, 2, 3) encoded_splits = encode_splits(splits, public_keys) split_random_tx.pieces = encoded_splits split_random_tx.pubkey_index = 0 expected_random_pieces.append(split_random_tx.pieces) split_random_tx.signature = Private.sign(pubkey_tx.get_hash(), dummy_private) block = Block() block.timestamp = i * BLOCK_TIME block.prev_hashes = [prev_hash] block.system_txs = [split_random_tx] signed_block = BlockFactory.sign_block(block, dummy_private) dag.add_signed_block(i, signed_block) randoms_list.append(random_value) prev_hash = block.get_hash() expected_seed = sum_random(randoms_list) prev_hash = ChainGenerator.fill_with_dummies( dag, prev_hash, Epoch.get_round_range(1, Round.REVEAL)) signer_index = 0 private_key_index = 0 raw_private_keys = [] for i in Epoch.get_round_range(1, Round.PRIVATE): private_key_tx = PrivateKeyTransaction() private_key_tx.key = Keys.to_bytes(private_keys[private_key_index]) raw_private_keys.append(private_key_tx.key) signer = signers[signer_index] block = Block() block.system_txs = [private_key_tx] block.prev_hashes = [prev_hash] block.timestamp = block_number * BLOCK_TIME signed_block = BlockFactory.sign_block(block, signer) dag.add_signed_block(i, signed_block) signer_index += 1 private_key_index += 1 prev_hash = block.get_hash() prev_hash = ChainGenerator.fill_with_dummies( dag, prev_hash, Epoch.get_round_range(1, Round.FINAL)) top_block_hash = dag.get_top_blocks_hashes()[0] random_splits = epoch.get_random_splits_for_epoch(top_block_hash) self.assertEqual(expected_random_pieces, random_splits) restored_randoms = [] for i in range(0, len(random_splits)): random = decode_random(random_splits[i], Keys.list_from_bytes(raw_private_keys)) restored_randoms.append(random) self.assertEqual(randoms_list, restored_randoms) seed = epoch.extract_shared_random(top_block_hash) self.assertEqual(expected_seed, seed)
def test_commit_reveal(self): dag = Dag(0) epoch = Epoch(dag) private = Private.generate() prev_hash = ChainGenerator.fill_with_dummies( dag, dag.genesis_block().get_hash(), Epoch.get_round_range(1, Round.PUBLIC)) randoms_list = [] for i in Epoch.get_round_range(1, Round.COMMIT): random_value = int.from_bytes(os.urandom(32), byteorder='big') randoms_list.append(random_value) expected_seed = sum_random(randoms_list) reveals = [] epoch_hash = dag.genesis_block().get_hash() for i in Epoch.get_round_range(1, Round.COMMIT): rand = randoms_list.pop() random_bytes = rand.to_bytes(32, byteorder='big') commit, reveal = TestEpoch.create_dummy_commit_reveal( random_bytes, epoch_hash) commit_block = BlockFactory.create_block_with_timestamp( [prev_hash], i * BLOCK_TIME) commit_block.system_txs = [commit] signed_block = BlockFactory.sign_block(commit_block, private) dag.add_signed_block(i, signed_block) prev_hash = commit_block.get_hash() reveals.append(reveal) revealing_key = Keys.from_bytes(reveal.key) encrypted_bytes = Public.encrypt(random_bytes, Private.publickey(revealing_key)) decrypted_bytes = Private.decrypt(encrypted_bytes, revealing_key) # TODO check if encryption decryption can work million times in a row self.assertEqual(decrypted_bytes, random_bytes) revealed_value = Private.decrypt(commit.rand, revealing_key) self.assertEqual(revealed_value, random_bytes) # self.assertEqual(len(reveals), ROUND_DURATION) prev_hash = ChainGenerator.fill_with_dummies( dag, prev_hash, Epoch.get_round_range(1, Round.SECRETSHARE)) for i in Epoch.get_round_range(1, Round.REVEAL): reveal_block = BlockFactory.create_block_with_timestamp( [prev_hash], i * BLOCK_TIME) reveal_block.system_txs = [reveals.pop()] signed_block = BlockFactory.sign_block(reveal_block, private) dag.add_signed_block(i, signed_block) prev_hash = reveal_block.get_hash() prev_hash = ChainGenerator.fill_with_dummies( dag, prev_hash, Epoch.get_round_range(1, Round.PRIVATE)) prev_hash = ChainGenerator.fill_with_dummies( dag, prev_hash, Epoch.get_round_range(1, Round.FINAL)) seed = epoch.reveal_commited_random(prev_hash) self.assertEqual(expected_seed, seed)
def create_stake_release_transaction(node_private): tx = StakeReleaseTransaction() tx.pubkey = Private.publickey(node_private) tx.signature = Private.sign(tx.get_hash(), node_private) return tx
def test_merged_chain_with_block_conflict(self): dag = Dag(0) watcher = ConflictWatcher(dag) actor1 = Private.publickey(Private.generate()) actor2 = Private.publickey(Private.generate()) actor3 = Private.publickey(Private.generate()) block1_hash, block1_reward = ChainGenerator.insert_dummy_with_payments( dag, [dag.genesis_hash()], [], 1) watcher.on_new_block_by_validator(block1_hash, 1, actor1) payment1 = TransactionFactory.create_payment(block1_reward, 0, [os.urandom(32)], [15]) block2_hash, block2_reward = ChainGenerator.insert_dummy_with_payments( dag, [block1_hash], [payment1], 2) watcher.on_new_block_by_validator(block2_hash, 1, actor2) #another block by the same validator spending the same output payment1c = TransactionFactory.create_payment(block1_reward, 0, [os.urandom(32)], [15]) block2c_hash, block2c_reward = ChainGenerator.insert_dummy_with_payments( dag, [block1_hash], [payment1c], 2) watcher.on_new_block_by_validator(block2c_hash, 1, actor2) block3_hash, block3_reward = ChainGenerator.insert_dummy_with_payments( dag, [block2_hash, block2c_hash], [], 3) watcher.on_new_block_by_validator(block3_hash, 1, actor3) # DagVisualizer.visualize(dag, True) iterator = MergingIter(dag, block3_hash, watcher) payments = [ block.block.payment_txs for block in iterator if block != None ] payments = list(reversed(payments)) spent, unspent = Resolver.resolve(payments) self.assertEqual(len(spent), 0) self.assertEqual(len(unspent), 3) self.assertIn(Entry(block2_reward, 0), unspent) self.assertIn(Entry(block3_reward, 0), unspent) self.assertIn(Entry(payment1.get_hash(), 0), unspent) self.assertNotIn(Entry(payment1c.get_hash(), 0), unspent) total_block_rewards = 0 iterator = MergingIter(dag, block3_hash, watcher) for block in iterator: if block: if not block.block.payment_txs: continue #it might be genesis, or just some silly validator who decided not to earn a reward block_reward = block.block.payment_txs[0] total_block_rewards += block_reward.amounts[0] unspent_total = 0 unspent_list = unspent #HACKY rename :) for unspent in unspent_list: unspent_tx = dag.payments_by_hash[unspent.tx] unspent_output = unspent.number unspent_amount = unspent_tx.amounts[unspent_output] unspent_total += unspent_amount self.assertEqual(total_block_rewards, unspent_total)
def test_release_stake(self): # base initialization dag = Dag(0) epoch = Epoch(dag) permissions = Permissions(epoch) node_private = Private.generate() initial_validators = Validators.read_genesis_validators_from_file() genesis_hash = dag.genesis_block().get_hash() prev_hash = genesis_hash for i in range(1, 9): block = BlockFactory.create_block_with_timestamp([prev_hash], BLOCK_TIME * i) signed_block = BlockFactory.sign_block(block, node_private) dag.add_signed_block(i, signed_block) prev_hash = block.get_hash() block = BlockFactory.create_block_with_timestamp([prev_hash], BLOCK_TIME * 9) # create new node for stake hold new_node_private = Private.generate() new_node_public = Private.publickey(new_node_private) # create transaction for stake hold for new node tx_hold = StakeHoldTransaction() tx_hold.amount = 2000 tx_hold.pubkey = Keys.to_bytes(new_node_public) tx_hold.signature = Private.sign(tx_hold.get_hash(), new_node_private) # append signed stake hold transaction block.system_txs.append(tx_hold) # sign block by one of validators signed_block = BlockFactory.sign_block(block, node_private) # add signed block to DAG dag.add_signed_block(9, signed_block) resulting_validators = permissions.get_validators(block.get_hash()) pub_keys = [] for validator in resulting_validators: pub_keys.append(validator.public_key) self.assertIn(new_node_public, pub_keys) # add blocks for new epoch for i in range(10, 18): block = BlockFactory.create_block_with_timestamp([prev_hash], BLOCK_TIME * i) signed_block = BlockFactory.sign_block(block, node_private) dag.add_signed_block(i, signed_block) prev_hash = block.get_hash() # create stake release transaction for new stakeholder tx_release = StakeReleaseTransaction() tx_release.pubkey = Keys.to_bytes(new_node_public) tx_release.signature = Private.sign(tx_hold.get_hash(), new_node_private) # append signed stake release transaction block.system_txs.append(tx_release) # sign block by one of validators signed_block = BlockFactory.sign_block(block, node_private) # add signed block to DAG dag.add_signed_block(19, signed_block) # verify that new stake holder now is NOT in validators list (after stake release transaction signed by holder) resulting_validators = permissions.get_validators(block.get_hash()) pub_keys = [] for validator in resulting_validators: pub_keys.append(validator.public_key) self.assertNotIn(new_node_public, pub_keys)