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 sign_block(block, private): block_hash = block.get_hash() signature = Private.sign(block_hash, private) signed_block = SignedBlock() signed_block.set_block(block) signed_block.set_signature(signature) return signed_block
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_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_commit_random_transaction(rand, pubkey_index, epoch_hash, node_private): tx = CommitRandomTransaction() tx.rand = rand tx.pubkey_index = pubkey_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 create_split_random_transaction(encoded_splits, pubkey_index, epoch_hash, node_private): tx = SplitRandomTransaction() tx.pieces = encoded_splits tx.pubkey_index = pubkey_index tx.signature = Private.sign(tx.get_signing_hash(epoch_hash), node_private) return tx
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_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_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_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_split_pack_unpack(self): dummy_private = Private.generate() original = SplitRandomTransaction() original.pieces = [os.urandom(128), os.urandom(127), os.urandom(128)] original.pubkey_index = 0 original.signature = Private.sign( original.get_signing_hash(b"epoch_hash"), dummy_private) raw = original.pack() restored = SplitRandomTransaction() restored.parse(raw) self.assertEqual(original.get_hash(), restored.get_hash()) self.assertEqual(original.get_signing_hash(b"epoch_hash"), restored.get_signing_hash(b"epoch_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 create_dummy_commit_reveal(random_bytes, epoch_hash): node_private = Private.generate() private = Private.generate() encoded = Private.encrypt(random_bytes, private) commit = CommitRandomTransaction() commit.rand = encoded commit.pubkey_index = 10 commit.signature = Private.sign(commit.get_signing_hash(epoch_hash), node_private) reveal = RevealRandomTransaction() reveal.commit_hash = commit.get_hash() reveal.key = Keys.to_bytes(private) return commit, reveal
def test_pack_parse_commit_transaction(self): for i in range(10): dummy_private = Private.generate() original = CommitRandomTransaction() original.rand = Private.encrypt(os.urandom(32), dummy_private) original.pubkey_index = i original.signature = Private.sign( original.get_signing_hash(b"epoch_hash"), dummy_private) raw = original.pack() restored = CommitRandomTransaction() restored.parse(raw) self.assertEqual(TransactionParser.pack(original), TransactionParser.pack(restored)) self.assertEqual(original.get_hash(), restored.get_hash()) self.assertEqual(original.get_signing_hash(b"epoch_hash"), restored.get_signing_hash(b"epoch_hash"))
def test_penalty(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() last_block_number = Epoch.get_epoch_end_block_number(1) prev_hash = ChainGenerator.fill_with_dummies( dag, genesis_hash, range(1, last_block_number)) block = BlockFactory.create_block_with_timestamp( [prev_hash], BLOCK_TIME * last_block_number) tx = PenaltyTransaction() tx.conflicts = [prev_hash] tx.signature = Private.sign(tx.get_hash(), node_private) block.system_txs = [tx] signed_block = BlockFactory.sign_block(block, node_private) dag.add_signed_block(last_block_number, signed_block) initial_validators_order = permissions.get_signers_indexes( genesis_hash) # we substract two here: one because it is last but one block # and one, because epoch starts from 1 validator_index_to_penalize = initial_validators_order[ last_block_number - 2] resulting_validators = permissions.get_validators(block.get_hash()) self.assertNotEqual(len(initial_validators), len(resulting_validators)) initial_validators.pop(validator_index_to_penalize) init_pubkeys = list( map(lambda validator: validator.public_key, initial_validators)) result_pubkeys = list( map(lambda validator: validator.public_key, resulting_validators)) self.assertEqual(init_pubkeys, result_pubkeys)
def test_stake_release_by_genesis_validator(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() # get one of validators genesis_validator = initial_validators[9] # create stake release transaction for new stakeholder tx_release = StakeReleaseTransaction() tx_release.pubkey = Keys.to_bytes(genesis_validator.public_key) tx_release.signature = Private.sign(tx_release.get_hash(), 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) resulting_validators = permissions.get_validators(block.get_hash()) pub_keys = [] for validator in resulting_validators: pub_keys.append(validator.public_key) self.assertNotIn(genesis_validator.public_key, pub_keys)
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_remove_from_validators_by_penalty_gossip(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() # get one of validators genesis_validator_private = Private.generate() genesis_validator_public = initial_validators[9].public_key # put to 10 block gossip+ AND gossip- by one node block = BlockFactory.create_block_with_timestamp([prev_hash], BLOCK_TIME * 10) gossip_negative_tx = NegativeGossipTransaction() gossip_negative_tx.pubkey = genesis_validator_public gossip_negative_tx.timestamp = Time.get_current_time() gossip_negative_tx.number_of_block = 5 gossip_negative_tx.signature = Private.sign( gossip_negative_tx.get_hash(), genesis_validator_private) # create and add to block negative gossip block.system_txs.append(gossip_negative_tx) gossip_positive_tx = PositiveGossipTransaction() gossip_positive_tx.pubkey = genesis_validator_public gossip_positive_tx.timestamp = Time.get_current_time() gossip_positive_tx.block_hash = dag.blocks_by_number[5][0].get_hash() gossip_positive_tx.signature = Private.sign( gossip_positive_tx.get_hash(), genesis_validator_private) # create and add to block positive gossip for same number 5 block block.system_txs.append(gossip_positive_tx) signed_block = BlockFactory.sign_block(block, genesis_validator_private) dag.add_signed_block(10, signed_block) prev_hash = block.get_hash() # -------------------------------------------------- # put to 11 block penalty gossip block = BlockFactory.create_block_with_timestamp([prev_hash], BLOCK_TIME * 11) penalty_gossip_tx = PenaltyGossipTransaction() penalty_gossip_tx.timestamp = Time.get_current_time() penalty_gossip_tx.conflicts = [ gossip_positive_tx.get_hash(), gossip_negative_tx.get_hash() ] # set genesis validator for sign penalty gossip penalty_gossip_tx.signature = Private.sign( penalty_gossip_tx.get_hash(), genesis_validator_private) block.system_txs.append(penalty_gossip_tx) signed_block = BlockFactory.sign_block(block, genesis_validator_private) dag.add_signed_block(11, signed_block) prev_hash = block.get_hash() # -------------------------------------------------- # verify that genesis node is steel in validators list current_epoch_hash = epoch.get_epoch_hashes() # for now we DO NOT NEED to recalculate validators (send genesis block hash) resulting_validators = permissions.get_validators( current_epoch_hash.get(prev_hash)) pub_keys = [] for validator in resulting_validators: pub_keys.append(validator.public_key) self.assertIn(genesis_validator_public, pub_keys) # produce epoch till end from chain.params import ROUND_DURATION for i in range(12, (ROUND_DURATION * 6 + 4)): 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() # check for new epoch self.assertTrue(epoch.is_new_epoch_upcoming(i)) self.assertTrue(epoch.current_epoch == 2) # recalculate validators for last block hash resulting_validators = permissions.get_validators(prev_hash) pub_keys = [] for validator in resulting_validators: pub_keys.append(validator.public_key) self.assertNotIn(genesis_validator_public, pub_keys)
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 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 create_penalty_transaction(conflicts, node_private): tx = PenaltyTransaction() tx.conflicts = conflicts tx.signature = Private.sign(tx.get_hash(), node_private) return tx
def create_penalty_gossip_transaction(conflict, node_private): tx = PenaltyGossipTransaction() tx.timestamp = Time.get_current_time() tx.conflicts = conflict tx.signature = Private.sign(tx.get_hash(), node_private) return tx
def create_stake_hold_transaction(amount, node_private): tx = StakeHoldTransaction() tx.amount = amount tx.pubkey = Private.publickey(node_private) tx.signature = Private.sign(tx.get_hash(), node_private) return tx
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)