Esempio n. 1
0
    def test_store_block_inserts_transactions(self):
        num_txs = 4

        with DB() as db:
            initial_txs = len(db.tables.transactions.select().run(db.ex))

        mn_sk = Constants.Testnet.Masternodes[0]['sk']
        timestamp = random.randint(0, pow(2, 32))
        raw_transactions = [build_test_transaction().serialize() for _ in range(num_txs)]

        tree = MerkleTree(raw_transactions)
        bc = build_test_contender(tree=tree)

        BlockStorageDriver.store_block(block_contender=bc, raw_transactions=raw_transactions, publisher_sk=mn_sk, timestamp=timestamp)
        block_hash = BlockStorageDriver._get_latest_block_hash()

        with DB() as db:
            transactions = db.tables.transactions
            all_tx_query = transactions.select().run(db.ex)

            # Ensure the correct number of transactions was inserted
            self.assertEquals(len(all_tx_query) - initial_txs, num_txs)

            # Ensure the transactions were correctly inserted
            for raw_tx in raw_transactions:
                tx_hash = Hasher.hash(raw_tx)

                rows = transactions.select().where(transactions.hash == tx_hash).run(db.ex)
                self.assertTrue(rows, "Expected there to be a row for inserted tx {}".format(raw_tx))

                tx_row = rows[0]
                self.assertEquals(tx_row['hash'], tx_hash, "Expected fetched tx to have hash equal to its hashed data")
                self.assertEquals(tx_row['data'], encode_tx(raw_tx), "Expected tx data col to equal encoded raw tx")
                self.assertEquals(tx_row['block_hash'], block_hash, "Expected inserted tx to reference last block")
Esempio n. 2
0
    def test_get_child_block_hashes(self):
        mn_sk = masternodes[0]['sk']
        timestamp = random.randint(0, pow(2, 32))
        raw_transactions1 = [
            build_test_transaction().serialize() for _ in range(4)
        ]
        raw_transactions2 = [
            build_test_transaction().serialize() for _ in range(4)
        ]
        new_hashes = []

        starting_hash = BlockStorageDriver.get_latest_block_hash()

        # Store 2 blocks
        for raw_txs in (raw_transactions1, raw_transactions2):
            tree = MerkleTree(raw_txs)
            bc = build_test_contender(tree=tree)

            h = BlockStorageDriver.store_block(block_contender=bc,
                                               raw_transactions=raw_txs,
                                               publisher_sk=mn_sk,
                                               timestamp=timestamp)
            new_hashes.append(h)

        actual_new_hashes = BlockStorageDriver.get_child_block_hashes(
            starting_hash)
        self.assertEquals(actual_new_hashes, new_hashes)
Esempio n. 3
0
    def test_validate_blockchain_invalid(self):
        reset_db()

        # Stuff a bunch of valid blocks in
        for _ in range(4):
            mn_sk = masternodes[0]['sk']
            timestamp = random.randint(0, pow(2, 32))
            raw_transactions = [
                build_test_transaction().serialize() for _ in range(19)
            ]

            tree = MerkleTree(raw_transactions)
            bc = build_test_contender(tree=tree)

            BlockStorageDriver.store_block(block_contender=bc,
                                           raw_transactions=raw_transactions,
                                           publisher_sk=mn_sk,
                                           timestamp=timestamp)

        # Stuff a sketch block in that doesn't link to the last
        sketch_block = self._build_block_data(
        )  # by default this has prev_block_hash = 'AAAAA...'
        sketch_block['hash'] = BlockStorageDriver.compute_block_hash(
            sketch_block)
        with DB() as db:
            db.tables.blocks.insert(
                [BlockStorageDriver._encode_block(sketch_block)]).run(db.ex)

        self.assertRaises(InvalidBlockLinkException,
                          BlockStorageDriver.validate_blockchain)
Esempio n. 4
0
    def test_get_raw_transaction_from_multiple_blocks(self):
        mn_sk = masternodes[0]['sk']
        timestamp = random.randint(0, pow(2, 32))
        raw_transactions1 = [
            build_test_transaction().serialize() for _ in range(4)
        ]
        raw_transactions2 = [
            build_test_transaction().serialize() for _ in range(4)
        ]
        block_hashes = []

        # Store 2 blocks
        for raw_txs in (raw_transactions1, raw_transactions2):
            tree = MerkleTree(raw_txs)
            bc = build_test_contender(tree=tree)

            h = BlockStorageDriver.store_block(block_contender=bc,
                                               raw_transactions=raw_txs,
                                               publisher_sk=mn_sk,
                                               timestamp=timestamp)
            block_hashes.append(h)

        added_txs = BlockStorageDriver.get_raw_transactions_from_block(
            block_hashes)

        for tx in raw_transactions1 + raw_transactions2:
            self.assertTrue(tx in added_txs)
Esempio n. 5
0
    def _build_valid_block_data(self, num_transactions=4) -> dict:
        """
        Utility method to build a dictionary with all the params needed to invoke store_block
        :param num_transactions:
        :return:
        """
        mn_sk = Constants.Testnet.Masternodes[0]['sk']
        mn_vk = ED25519Wallet.get_vk(mn_sk)
        timestamp = 9000

        raw_transactions = [build_test_transaction().serialize() for _ in range(num_transactions)]

        tree = MerkleTree(raw_transactions)
        merkle_leaves = tree.leaves_as_concat_hex_str
        merkle_root = tree.root_as_hex

        bc = build_test_contender(tree=tree)

        prev_block_hash = '0' * 64

        mn_sig = ED25519Wallet.sign(mn_sk, tree.root)

        return {
            'prev_block_hash': prev_block_hash,
            'block_contender': bc,
            'merkle_leaves': merkle_leaves,
            'merkle_root': merkle_root,
            'masternode_signature': mn_sig,
            'masternode_vk': mn_vk,
            'timestamp': timestamp
        }
Esempio n. 6
0
    def test_store_block_data_invalid_sk(self):
        raw_txs = [secrets.token_bytes(16) for _ in range(16)]
        tree = MerkleTree(leaves=raw_txs)

        bc = build_test_contender(tree=tree)
        bad_sk = 'X' * 128
        timestamp = 9000

        self.assertRaises(AssertionError, BlockStorageDriver.store_block, block_contender=bc, raw_transactions=raw_txs,
                          publisher_sk=bad_sk, timestamp=timestamp)
Esempio n. 7
0
    def test_validate_block_data_invalid_contender_leaves_mismatch(self):
        bd = self._build_valid_block_data(4)

        # Create a sketch block contender with leaves that are different from the merkle leaves in the block_data
        raw_transactions = [build_test_transaction().serialize() for _ in range(4)]
        tree = MerkleTree(raw_transactions)
        sketch_bc = build_test_contender(tree=tree)

        bd['block_contender'] = sketch_bc

        self.assertRaises(InvalidBlockContenderException, BlockStorageDriver._validate_block_data, bd)
Esempio n. 8
0
    def test_input_block_contender(self):
        """
        Tests that receiving a block contender in RunState pushes the SM into NewBlockState
        """
        mock_sm = MagicMock()
        bc = build_test_contender()

        state = MNRunState(state_machine=mock_sm)

        state.call_input_handler(bc, StateInput.REQUEST)

        mock_sm.transition.assert_called_with('MNNewBlockState', block=bc)
Esempio n. 9
0
    def test_store_block_contender_raw_tx_mismatch(self):
        mn_sk = Constants.Testnet.Masternodes[0]['sk']
        timestamp = random.randint(0, pow(2, 32))
        raw_transactions = [build_test_transaction().serialize() for _ in range(8)]

        tree = MerkleTree(raw_transactions)
        bc = build_test_contender(tree=tree)

        # Generate some arbitrary raw transactions that are not the same as the ones signed inside the BlockContender
        mismatched_transactions = [build_test_transaction().serialize() for _ in range(8)]

        self.assertRaises(InvalidBlockContenderException, BlockStorageDriver.store_block, block_contender=bc,
                          raw_transactions=mismatched_transactions, publisher_sk=mn_sk, timestamp=timestamp)
Esempio n. 10
0
    def test_get_raw_transaction(self):
        mn_sk = Constants.Testnet.Masternodes[0]['sk']
        timestamp = random.randint(0, pow(2, 32))
        raw_transactions = [build_test_transaction().serialize() for _ in range(4)]

        tree = MerkleTree(raw_transactions)
        bc = build_test_contender(tree=tree)

        BlockStorageDriver.store_block(block_contender=bc, raw_transactions=raw_transactions, publisher_sk=mn_sk, timestamp=timestamp)

        # Ensure all these transactions are retrievable
        for raw_tx in raw_transactions:
            retrieved_tx = BlockStorageDriver.get_raw_transaction(Hasher.hash(raw_tx))
            self.assertEquals(raw_tx, retrieved_tx)
Esempio n. 11
0
    def test_get_raw_transaction_from_block(self):
        mn_sk = Constants.Testnet.Masternodes[0]['sk']
        timestamp = random.randint(0, pow(2, 32))
        raw_transactions = [build_test_transaction().serialize() for _ in range(4)]

        tree = MerkleTree(raw_transactions)
        bc = build_test_contender(tree=tree)

        BlockStorageDriver.store_block(block_contender=bc, raw_transactions=raw_transactions, publisher_sk=mn_sk, timestamp=timestamp)
        latest_hash = BlockStorageDriver._get_latest_block_hash()

        added_txs = BlockStorageDriver.get_raw_transactions_from_block(block_hash=latest_hash)

        for tx in raw_transactions:
            self.assertTrue(tx in added_txs)
Esempio n. 12
0
    def test_get_latest_inserted(self):
        mn_sk = Constants.Testnet.Masternodes[0]['sk']
        timestamp = random.randint(0, pow(2, 32))
        raw_transactions = [build_test_transaction().serialize() for _ in range(19)]

        tree = MerkleTree(raw_transactions)
        bc = build_test_contender(tree=tree)

        BlockStorageDriver.store_block(block_contender=bc, raw_transactions=raw_transactions, publisher_sk=mn_sk, timestamp=timestamp)

        latest = BlockStorageDriver.get_latest_block()

        self.assertTrue(latest)
        self.assertEquals(latest['timestamp'], timestamp)
        self.assertEquals(latest['block_contender'], bc)
Esempio n. 13
0
    def test_get_raw_transactions_with_multiple_hashes(self):
        mn_sk = TESTNET_MASTERNODES[0]['sk']
        timestamp = random.randint(0, pow(2, 32))
        raw_transactions = [build_test_transaction().serialize() for _ in range(4)]
        hashes = list(map(Hasher.hash, raw_transactions))

        tree = MerkleTree(raw_transactions)
        bc = build_test_contender(tree=tree)

        BlockStorageDriver.store_block(block_contender=bc, raw_transactions=raw_transactions, publisher_sk=mn_sk, timestamp=timestamp)

        # Ensure all these transactions are retrievable
        retrieved_txs = BlockStorageDriver.get_raw_transactions(hashes)
        self.assertEquals(len(retrieved_txs), len(raw_transactions))
        for raw_tx in raw_transactions:
            self.assertTrue(raw_tx in retrieved_txs)
Esempio n. 14
0
    def test_validate_blockchain(self):
        reset_db()

        # Stuff a bunch of blocks in
        for _ in range(4):
            mn_sk = Constants.Testnet.Masternodes[0]['sk']
            timestamp = random.randint(0, pow(2, 32))
            raw_transactions = [build_test_transaction().serialize() for _ in range(19)]

            tree = MerkleTree(raw_transactions)
            bc = build_test_contender(tree=tree)

            BlockStorageDriver.store_block(block_contender=bc, raw_transactions=raw_transactions, publisher_sk=mn_sk,
                                           timestamp=timestamp)

        # This should not blow up
        BlockStorageDriver.validate_blockchain()
Esempio n. 15
0
    def test_store_block_inserts(self):
        with DB() as db:
            initial_num_blocks = len(db.tables.blocks.select().run(db.ex))

        mn_sk = Constants.Testnet.Masternodes[0]['sk']
        timestamp = random.randint(0, pow(2, 32))
        raw_transactions = [build_test_transaction().serialize() for _ in range(19)]

        tree = MerkleTree(raw_transactions)
        bc = build_test_contender(tree=tree)

        BlockStorageDriver.store_block(block_contender=bc, raw_transactions=raw_transactions, publisher_sk=mn_sk, timestamp=timestamp)

        with DB() as db:
            blocks = db.tables.blocks.select().run(db.ex)
            self.assertEquals(len(blocks) - initial_num_blocks, 1)
            self.assertEquals(blocks[-1]['timestamp'], timestamp)
Esempio n. 16
0
    def _build_block_data(self,
                          num_transactions=4,
                          ref_prev_block=False) -> dict:
        """
        Utility method to build a dictionary with all the params needed to invoke store_block
        :param num_transactions: Number of raw transactions in the block
        :param ref_prev_block: True if the block data's prev_block_hash should reference the previous block.
        Otherwise, prev_block_hash is set to default 000000...
        :return:
        """
        mn_sk = masternodes[0]['sk']
        mn_vk = wallet.get_vk(mn_sk)
        timestamp = 9000

        raw_transactions = [
            build_test_transaction().serialize()
            for _ in range(num_transactions)
        ]

        tree = MerkleTree(raw_transactions)
        merkle_leaves = tree.leaves_as_concat_hex_str
        merkle_root = tree.root_as_hex

        bc = build_test_contender(tree=tree)

        if ref_prev_block:
            prev_block_hash = BlockStorageDriver.get_latest_block_hash()
        else:
            prev_block_hash = '0' * 64

        mn_sig = wallet.sign(mn_sk, tree.root)

        return {
            'prev_block_hash': prev_block_hash,
            'block_contender': bc,
            'merkle_leaves': merkle_leaves,
            'merkle_root': merkle_root,
            'masternode_signature': mn_sig,
            'masternode_vk': mn_vk,
            'timestamp': timestamp
        }
Esempio n. 17
0
 def test_build_test_contender(self):
     """
     Tests build_test_contender. This is used exclusively unit tests, so we basically just want to make sure it
     doesn't blow up here first.
     """
     bc = build_test_contender()