コード例 #1
0
ファイル: test_merkle_tree.py プロジェクト: sanko61/cilantro
    def test_data_for_hash_doesnt_exist(self):
        leaves = [b'1', b'2', b'3']
        hashed_leaves = list(map(Hasher.hash, leaves))

        m = MerkleTree.from_raw_transactions(leaves)

        self.assertRaises(AssertionError, m.data_for_hash, '0' * 64)
コード例 #2
0
    def enter_from_interpret(self):
        assert self.parent.interpreter.queue_size > 0, "Entered consensus state, but interpreter queue is empty!"

        # Merkle-ize transaction queue and create signed merkle hash
        all_tx = self.parent.interpreter.queue_binary
        self.log.debugv(
            "Delegate got tx from interpreter queue: {}".format(all_tx))
        self.merkle = MerkleTree.from_raw_transactions(all_tx)
        self.log.debugv("Delegate got merkle hash {}".format(
            self.merkle.root_as_hex))
        self.signature = wallet.sign(self.parent.signing_key, self.merkle.root)

        # Create merkle signature message and publish it
        merkle_sig = MerkleSignature.create(sig_hex=self.signature,
                                            timestamp='now',
                                            sender=self.parent.verifying_key)
        self.log.debugv("Broadcasting signature {}".format(self.signature))
        self.parent.composer.send_pub_msg(filter=delegate_delegate,
                                          message=merkle_sig)

        # Now that we've computed/composed the merkle tree hash, validate all our pending signatures
        for sig in [
                s for s in self.parent.pending_sigs if self.validate_sig(s)
        ]:
            self.signatures.append(sig)

        self.check_majority()
コード例 #3
0
ファイル: test_consensus.py プロジェクト: sanko61/cilantro
    def test_tx_request_replies_with_correct_data(self):
        """
        Tests that a delegate who receives a TransactionRequest in Consensus state replies with the correct data
        """
        mock_sm = MagicMock()
        state = DelegateConsensusState(mock_sm)

        # Build a merkle tree and attach it to the state
        tx_objects = [build_test_transaction() for _ in range(5)]
        tx_blobs = [tx.serialize() for tx in tx_objects]
        tx_hashes = [Hasher.hash(blob) for blob in tx_blobs]
        merkle_tree = MerkleTree.from_raw_transactions(tx_blobs)

        state.merkle = merkle_tree

        # Build a TransactionRequest for a few of these transactions
        requested_hashes = tx_hashes[1:4]
        expected_blobs = tx_blobs[1:4]
        request = TransactionRequest.create(
            transaction_hashes=requested_hashes)

        # Finally, ensure the reply is what we expect it to be
        reply = state.handle_tx_request(request)

        self.assertEquals(reply.raw_transactions, expected_blobs)
コード例 #4
0
    def enter_from_interpret(self):
        assert self.parent.interpreter.queue_size > 0, "Entered consensus state, but interpreter queue is empty!"
        assert self.parent.interpreter.queue_size == BLOCK_SIZE, \
            "Consensus state entered with {} transactions in queue, but the BLOCK_SIZE is {}!"\
            .format(self.parent.interpreter.queue_size, BLOCK_SIZE)

        # Merkle-ize transaction queue and create signed merkle hash
        all_tx = self.parent.interpreter.queue_binary
        self.merkle = MerkleTree.from_raw_transactions(all_tx)
        self.signature = wallet.sign(self.parent.signing_key, self.merkle.root)

        self.log.info("Delegate entering consensus state with merkle hash {}, and latest block hash {}"
                      .format(self.merkle.root_as_hex, self.parent.current_hash))
        self.log.spam("Delegate got merkle leaves {}".format(self.merkle.leaves_as_hex))

        # Create merkle signature message and publish it
        merkle_sig = MerkleSignature.create(sig_hex=self.signature, timestamp='now',
                                            sender=self.parent.verifying_key)
        self.log.debugv("Broadcasting signature {}".format(self.signature))
        self.parent.composer.send_pub_msg(filter=DELEGATE_DELEGATE_FILTER, message=merkle_sig)

        # Now that we've computed/composed the merkle tree hash, validate all our pending signatures
        for sig in [s for s in self.parent.pending_sigs if self.validate_sig(s)]:
            self.signatures.append(sig)

        # Add our own signature
        self.signatures.append(merkle_sig)

        self.check_majority()
コード例 #5
0
ファイル: test_merkle_tree.py プロジェクト: sanko61/cilantro
    def test_data_for_hash(self):
        leaves = [b'1', b'2', b'3']
        hashed_leaves = list(map(Hasher.hash, leaves))

        m = MerkleTree.from_raw_transactions(leaves)

        for i in range(len(leaves)):
            self.assertEquals(m.data_for_hash(hashed_leaves[i]), leaves[i])
コード例 #6
0
    def test_eq(self):
        nodes = [secrets.token_bytes(8) for _ in range(4)]
        tree = MerkleTree.from_raw_transactions(nodes)

        msg = tree.root

        sig1, sk1, vk1 = self._create_merkle_sig(msg)
        sig2, sk2, vk2 = self._create_merkle_sig(msg)
        sig3, sk3, vk3 = self._create_merkle_sig(msg)
        sig4, sk4, vk4 = self._create_merkle_sig(msg)

        signatures = [sig1, sig2, sig3, sig4]

        bc1 = BlockContender.create(signatures, merkle_leaves=tree.leaves_as_hex, prev_block_hash='A' * 64)
        bc2 = BlockContender.create(signatures, merkle_leaves=tree.leaves_as_hex, prev_block_hash='A' * 64)

        self.assertEquals(bc1, bc2)
コード例 #7
0
    def test_validate_signatures(self):
        nodes = [secrets.token_bytes(8) for _ in range(4)]
        tree = MerkleTree.from_raw_transactions(nodes)

        msg = tree.root

        sig1, sk1, vk1 = self._create_merkle_sig(msg)
        sig2, sk2, vk2 = self._create_merkle_sig(msg)
        sig3, sk3, vk3 = self._create_merkle_sig(msg)
        sig4, sk4, vk4 = self._create_merkle_sig(msg)

        signatures = [sig1, sig2, sig3, sig4]

        bc = BlockContender.create(signatures,
                                   merkle_leaves=tree.leaves_as_hex)
        is_valid = bc.validate_signatures()

        self.assertTrue(is_valid)
コード例 #8
0
    def test_validate_signatures_invalid(self):
        nodes = [secrets.token_bytes(8) for _ in range(4)]
        tree = MerkleTree.from_raw_transactions(nodes)

        msg = tree.root

        bad_msg = b'lol this is def not a merkle root'

        sig1, sk1, vk1 = self._create_merkle_sig(msg)
        sig2, sk2, vk2 = self._create_merkle_sig(msg)
        sig3, sk3, vk3 = self._create_merkle_sig(msg)
        sig4, sk4, vk4 = self._create_merkle_sig(bad_msg)

        signatures = [sig1, sig2, sig3, sig4]

        bc = BlockContender.create(signatures, merkle_leaves=tree.leaves_as_hex, prev_block_hash="A" * 64)
        is_valid = bc.validate_signatures()

        self.assertFalse(is_valid)
コード例 #9
0
ファイル: sub_block_builder.py プロジェクト: sanko61/cilantro
    async def _interpret_next_subtree(self, num_of_batches = 1):
        self.log.debug("Starting to make a new sub-block {} for block {}"
                       .format(self.sub_block_num, self.block_num))
        # get next batch of txns ??  still need to decide whether to unpack a bag or check for end of txn batch
        while(num_of_batches > 0):
            txn = self.pending_txs.popleft()
            if txn == end_of_batch:
                num_of_batches = num_of_batches - 1
            else:
                self.interpreter.interpret(txn)  # this is a blocking call. either async or threads??
            if not self._interpret:         # do we need abort??
                self.interpreter.flush(update_state=False)
                return;

        # Merkle-ize transaction queue and create signed merkle hash
        all_tx = self.interpreter.queue_binary
        self.merkle = MerkleTree.from_raw_transactions(all_tx)
        self.signature = wallet.sign(self.signing_key, self.merkle.root)

        # Create merkle signature message and publish it
        merkle_sig = MerkleSignature.create(sig_hex=self.signature,
                                            timestamp='now',
                                            sender=self.verifying_key)
        self.send_signature(merkle_sig)  # send signature to block manager
コード例 #10
0
ファイル: blocks.py プロジェクト: Mat001/cilantro
    def store_block(cls,
                    block_contender: BlockContender,
                    raw_transactions: List[bytes],
                    publisher_sk: str,
                    timestamp: int = 0):
        """

        Persist a new block to the blockchain, along with the raw transactions associated with the block. An exception
        will be raised if an error occurs either validating the new block data, or storing the block. Thus, it is
        recommended that this method is wrapped in a try block.

        :param block_contender: A BlockContender instance
        :param raw_transactions: A list of ordered raw transactions contained in the block
        :param publisher_sk: The signing key of the publisher (a Masternode) who is publishing the block
        :param timestamp: The time the block was published, in unix epoch time. If 0, time.time() is used
        :return: None
        :raises: An assertion error if invalid args are passed into this function, or a BlockStorageValidationException
         if validation fails on the attempted block

        TODO -- think really hard and make sure that this is 'collision proof' (extremely unlikely, but still possible)
        - could there be a hash collision in the Merkle tree nodes?
        - hash collision in block hash space?
        - hash collision in transaction space?
        """
        assert isinstance(
            block_contender, BlockContender
        ), "Expected block_contender arg to be BlockContender instance"
        assert is_valid_hex(
            publisher_sk,
            64), "Invalid signing key {}. Expected 64 char hex str".format(
                publisher_sk)

        if not timestamp:
            timestamp = int(time.time())

        tree = MerkleTree.from_raw_transactions(raw_transactions)

        publisher_vk = ED25519Wallet.get_vk(publisher_sk)
        publisher_sig = ED25519Wallet.sign(publisher_sk, tree.root)

        # Build and validate block_data
        block_data = {
            'block_contender': block_contender,
            'timestamp': timestamp,
            'merkle_root': tree.root_as_hex,
            'merkle_leaves': tree.leaves_as_concat_hex_str,
            'prev_block_hash': cls._get_latest_block_hash(),
            'masternode_signature': publisher_sig,
            'masternode_vk': publisher_vk,
        }
        cls._validate_block_data(block_data)

        # Compute block hash
        block_hash = cls._compute_block_hash(block_data)

        # Encode block data for serialization and finally persist the data
        log.info(
            "Attempting to persist new block with hash {}".format(block_hash))
        block_data = cls._encode_block(block_data)

        with DB() as db:
            # Store block
            res = db.tables.blocks.insert([{
                'hash': block_hash,
                **block_data
            }]).run(db.ex)
            if res:
                log.info(
                    "Successfully inserted new block with number {} and hash {}"
                    .format(res['last_row_id'], block_hash))
            else:
                log.error(
                    "Error inserting block! Got None/False result back from insert query. Result={}"
                    .format(res))
                return

            # Store raw transactions
            log.info(
                "Attempting to store {} raw transactions associated with block hash {}"
                .format(len(raw_transactions), block_hash))
            tx_rows = [{
                'hash': Hasher.hash(raw_tx),
                'data': encode_tx(raw_tx),
                'block_hash': block_hash
            } for raw_tx in raw_transactions]

            res = db.tables.transactions.insert(tx_rows).run(db.ex)
            if res:
                log.info("Successfully inserted {} transactions".format(
                    res['row_count']))
            else:
                log.error(
                    "Error inserting raw transactions! Got None from insert query. Result={}"
                    .format(res))