예제 #1
0
    def test_deserialize_valid_object(self):
        """
        Tests that the same object is recovered when serialized and deserialized
        """
        msg = b'payload'
        nodes = ['A' * 64, 'B' * 64, 'C' * 64, 'D' * 64]

        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, nodes, 'A' * 64)

        bc_ser = bc.serialize()

        clone = BlockContender.from_bytes(bc_ser)

        for i in range(len(signatures)):
            self.assertEqual(bc.signatures[i], clone.signatures[i])

        for i in range(len(nodes)):
            self.assertEqual(bc.merkle_leaves[i], clone.merkle_leaves[i])
예제 #2
0
    def test_create_bc_normal_fields(self):
        msg = b'payload'
        nodes = ['A' * 64, 'B' * 64, 'C' * 64, 'D' * 64]

        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]

        BlockContender.create(signatures, nodes, 'A' * 64)  # should not throw an error
예제 #3
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)
예제 #4
0
    def test_bc_creation_from_bytes(self):
        msg = b'DEADBEEF'
        nodes = ['A' * 64, 'B' * 64]

        sig1, sk1, vk1 = self._create_merkle_sig(msg)
        sig2, sk2, vk2 = self._create_merkle_sig(msg)
        signatures = [sig1, sig2]

        bc = BlockContender.create(signatures, nodes, 'A' * 64)

        clone = BlockContender.from_bytes(bc.serialize())

        # assert bc.signatures = signature over all signatures
        for i in range(len(signatures)):
            self.assertTrue(clone.signatures[i] == (signatures[i]))

        for i in range(len(nodes)):
            self.assertTrue(clone.merkle_leaves[i] == (nodes[i]))
예제 #5
0
 def create(cls, hash: str, merkle_root: str, merkle_leaves: str,
            prev_block_hash: str, timestamp: int, masternode_signature: str,
            masternode_vk: str, block_contender: BlockContender):
     struct = blockdata_capnp.BlockMetaData.new_message()
     struct.hash = hash
     struct.merkleRoot = merkle_root
     struct.merkleLeaves = merkle_leaves
     struct.prevBlockHash = prev_block_hash
     struct.timestamp = timestamp
     struct.masternodeSignature = masternode_signature
     struct.masternodeVk = masternode_vk
     assert type(block_contender) == BlockContender, 'Not a block contender'
     struct.blockContender = block_contender.serialize()
     return cls.from_data(struct)
예제 #6
0
    def check_majority(self):
        self.log.debug("delegate has {} signatures out of {} total TESTNET_DELEGATES"
                       .format(len(self.signatures), self.NUM_DELEGATES))

        if len(self.signatures) >= MAJORITY and not self.in_consensus:
            self.log.important("Delegate in consensus!")
            self.in_consensus = True

            # Create BlockContender and send it to all Masternode(s)
            bc = BlockContender.create(signatures=self.signatures, merkle_leaves=self.merkle.leaves_as_hex,
                                       prev_block_hash=self.parent.current_hash)
            for mn_vk in VKBook.get_masternodes():
                self.log.debug("Delegate sending block contender to masternode with VK {}".format(mn_vk))
                self.parent.composer.send_request_msg(message=bc, vk=mn_vk)
예제 #7
0
    def check_majority(self):
        self.log.debug(
            "delegate has {} signatures out of {} total delegates".format(
                len(self.signatures), self.NUM_DELEGATES))

        if len(self.signatures) >= majority:
            self.log.important("Delegate in consensus!")
            self.in_consensus = True

            # DEBUG LINE -- todo remove later
            # self.log.notice("Delegate creating contender with merk leaves {}".format(self.merkle.leaves_as_hex))

            # Create BlockContender and send it to all Masternode(s)
            bc = BlockContender.create(signatures=self.signatures,
                                       merkle_leaves=self.merkle.leaves_as_hex)
            for mn_vk in VKBook.get_masternodes():
                self.parent.composer.send_request_msg(message=bc, vk=mn_vk)
예제 #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
    def test_bc_creation(self):
        """
        Tests that a created BlockContender has the expected properties
        """
        msg = b'DEADBEEF'
        nodes = ['A' * 64, 'B' * 64]

        sig1, sk1, vk1 = self._create_merkle_sig(msg)
        sig2, sk2, vk2 = self._create_merkle_sig(msg)
        signatures = [sig1, sig2]
        prev_b_hash = 'A' * 64

        bc = BlockContender.create(signatures, nodes, prev_b_hash)

        # assert bc.signatures = signature over all signatures
        for i in range(len(signatures)):
            self.assertTrue(bc.signatures[i] == (signatures[i]))

        for i in range(len(nodes)):
            self.assertTrue(bc.merkle_leaves[i] == (nodes[i]))

        self.assertEquals(bc.prev_block_hash, prev_b_hash)
예제 #10
0
    def validate_block_contender(self, block: BlockContender) -> bool:
        """
        Helper method to validate a block contender. For a block contender to be valid it must:
        1) Have a provable merkle tree, ie. all nodes must be hash of (left child + right child)
        2) Be signed by at least 2/3 of the top 32 delegates
        3) Have the correct number of transactions
        :param block_contender: The BlockContender to validate
        :return: True if the BlockContender is valid, false otherwise
        """
        # Development sanity checks (these should be removed in production)
        assert len(block.merkle_leaves) >= 1, "Masternode got block contender with no nodes! {}".format(block)
        assert len(block.signatures) >= majority, \
            "Received a block contender with only {} signatures (which is less than a majority of {}"\
            .format(len(block.signatures), majority)

        assert len(block.merkle_leaves) == max_queue_size, \
            "Block contender has {} merkle leaves, but MaxQueueSize is {}!!!\nmerkle_leaves={}"\
            .format(len(block.merkle_leaves), max_queue_size, block.merkle_leaves)

        # TODO validate the sigs are actually from the top N delegates
        # TODO -- ensure that this block contender's previous block is this Masternode's current block...

        return block.validate_signatures()
예제 #11
0
    def validate_block_contender(self, block: BlockContender) -> bool:
        """
        Helper method to validate a block contender. For a block contender to be valid it must:
        1) Have a provable merkle tree, ie. all nodes must be hash of (left child + right child)
        2) Be signed by at least 2/3 of the top 32 delegates
        3) Have the correct number of transactions
        4) Be a proposed child of the latest block in the database
        :param block_contender: The BlockContender to validate
        :return: True if the BlockContender is valid, false otherwise
        """
        # Development sanity checks
        # TODO -- in production these assertions should return False instead of raising an Exception
        assert len(
            block.merkle_leaves
        ) >= 1, "Masternode got block contender with no nodes! {}".format(
            block)
        assert len(block.signatures) >= MAJORITY, \
            "Received a block contender with only {} signatures (which is less than a MAJORITY of {}"\
            .format(len(block.signatures), MAJORITY)

        assert len(block.merkle_leaves) == BLOCK_SIZE, \
            "Block contender has {} merkle leaves, but block size is {}!!!\nmerkle_leaves={}"\
            .format(len(block.merkle_leaves), BLOCK_SIZE, block.merkle_leaves)

        # TODO validate the sigs are actually from the top N delegates

        if not block.prev_block_hash == BlockStorageDriver.get_latest_block_hash(
        ):
            self.log.warning(
                "BlockContender validation failed. Block contender's previous block hash {} does not "
                "match DB's latest block hash {}".format(
                    block.prev_block_hash,
                    BlockStorageDriver.get_latest_block_hash()))
            return False

        return block.validate_signatures()
예제 #12
0
 def block_contender(self) -> BlockContender:
     return BlockContender.from_bytes(self._data.blockContender)
예제 #13
0
def _deserialize_contender(block_contender: str) -> BlockContender:
    # Genesis Block Contender is None/Empty and thus should not be deserialized
    if block_contender == GENESIS_BLOCK_CONTENDER:
        return block_contender
    return BlockContender.from_bytes(bytes.fromhex(block_contender))
예제 #14
0
def _serialize_contender(block_contender: BlockContender) -> str:
    hex_str = block_contender.serialize().hex()
    return hex_str