コード例 #1
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()
コード例 #2
0
def build_valid_block_data(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 = 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)

    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
    }
コード例 #3
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()
コード例 #4
0
    def test_valid_sender(self):
        # Confirm no error when correct public key is used
        msg = b'this is a pretend merkle tree hash'
        sk, vk = wallet.new()
        signature = wallet.sign(sk, msg)

        timestamp = 'now'
        MerkleSignature.create(sig_hex=signature,
                               timestamp=timestamp,
                               sender=vk)  # no error thrown
コード例 #5
0
    def create_tx_struct(sender_s, sender_v, policy, method):
        tx = transaction_capnp.VoteTransaction.new_message()

        tx.payload.sender = sender_v
        tx.payload.policy = policy
        tx.payload.method = method
        payload_binary = tx.payload.copy().to_bytes()

        tx.metadata.proof = SHA3POW.find(payload_binary)[0]
        tx.metadata.signature = wallet.sign(sender_s, payload_binary)

        return tx
コード例 #6
0
    def create_tx_struct(sender_s, sender_v, secret):
        # Adjust amount for fixed point arithmetic
        tx = transaction_capnp.RedeemTransaction.new_message()

        tx.payload.sender = sender_v
        tx.payload.secret = secret
        payload_binary = tx.payload.copy().to_bytes()

        tx.metadata.proof = SHA3POW.find(payload_binary)[0]
        tx.metadata.signature = wallet.sign(sender_s, payload_binary)

        return tx
コード例 #7
0
    def _create_merkle_sig(self, msg: bytes):
        """
        Helper method to create a MerkleSignature and wallet keys
        :return: A tuple container (MerkleSignature, signing_key, verifying_key)
        """
        assert type(msg) == bytes, "Must pass in bytes"

        sk, vk = wallet.new()
        signature = wallet.sign(sk, msg)
        ms = MerkleSignature.create(sig_hex=signature, timestamp=TIMESTAMP, sender=vk)

        return ms, sk, vk
コード例 #8
0
    def test_deserialization_valid_json(self):
        # Test valid json throws no errors
        msg = b'this is a pretend merkle tree hash'
        sk, vk = wallet.new()
        signature = wallet.sign(sk, msg)

        d = {
            MerkleSignature.SIG: signature,
            MerkleSignature.TS: 'now',
            MerkleSignature.SENDER: vk
        }
        binary = json.dumps(d).encode()
        MerkleSignature.from_bytes(binary)
コード例 #9
0
    def test_verify_valid_ms(self):
        """
        Tests that MerkleSignature.verify(...) returns true given a proper msg and vk
        """
        # Test merkle tree verify() validates correct verifying (public) keys
        msg = b'this is a pretend merkle tree hash'
        timestamp = 'now'
        sk, vk = wallet.new()
        signature = wallet.sign(sk, msg)
        ms = MerkleSignature.create(sig_hex=signature,
                                    timestamp=timestamp,
                                    sender=vk)

        self.assertTrue(ms.verify(msg))
コード例 #10
0
    def test_invalid_timestamp(self):
        """
        Test that if the timestamp field is not formatted as expected an error will be thrown
        """
        msg = b'this is a pretend merkle tree hash'
        sk, vk = wallet.new()
        signature = wallet.sign(sk, msg)

        timestamp = 99
        self.assertRaises(
            TypeError,
            MerkleSignature.create(sig_hex=signature,
                                   timestamp=timestamp,
                                   sender=vk))
コード例 #11
0
ファイル: contract.py プロジェクト: sanko61/cilantro
    def create_contract_tx(sender_sk: str, code_str: str):
        validate_hex(sender_sk, 64, 'sender signing key')

        struct = transaction_capnp.ContractTransaction.new_message()

        struct.payload.sender = wallet.get_vk(sender_sk)
        struct.payload.code = code_str

        payload_binary = struct.payload.copy().to_bytes()

        struct.metadata.proof = SHA3POW.find(payload_binary)[0]
        struct.metadata.signature = wallet.sign(sender_sk, payload_binary)

        return ContractTransaction.from_data(struct)
コード例 #12
0
    def test_valid_creation(self):
        """
        Tests that a MerkleSignature created with some argument has the expected properties
        """
        msg = b'this is a pretend merkle tree hash'
        timestamp = 'now'
        sk, vk = wallet.new()
        signature = wallet.sign(sk, msg)
        ms = MerkleSignature.create(sig_hex=signature,
                                    timestamp=timestamp,
                                    sender=vk)

        self.assertEqual(ms.signature, signature)
        self.assertEqual(ms.timestamp, timestamp)
        self.assertEqual(ms.sender, vk)
コード例 #13
0
    def test_invalid_sender_bad_hash(self):
        # Test an error is thrown when created with a sender of not valid hash
        msg = b'this is a pretend merkle tree hash'
        sk, vk = wallet.new()
        signature = wallet.sign(sk, msg)

        timestamp = 'now'
        vk_bad_hash = ''.join(
            'Z' for _ in range(64))  # verifying (public) key with bad hash
        self.assertRaises(
            Exception,
            MerkleSignature.create(sig_hex=signature,
                                   timestamp=timestamp,
                                   sender=vk_bad_hash,
                                   validate=False))
コード例 #14
0
    def test_invalid_sender_wrong_sender(self):
        """
        Tests that an error is raised during creation if an invalid sender field is passed in. A sender should be a
        64 character hex string verifying key.
        """
        # Test an error is thrown when MerkleSignature created with a sender that is not the correct public key
        msg = b'this is a pretend merkle tree hash'
        sk, vk = wallet.new()
        signature = wallet.sign(sk, msg)

        timestamp = 'now'
        vk_bad = wallet.new()[1]  # different verifying (public) key
        bad_public_key = MerkleSignature.create(sig_hex=signature,
                                                timestamp=timestamp,
                                                sender=vk_bad)
        self.assertRaises(Exception, bad_public_key)
コード例 #15
0
ファイル: merkle_signature.py プロジェクト: sanko61/cilantro
def build_test_merkle_sig(msg: bytes = b'some default payload',
                          sk=None,
                          vk=None) -> MerkleSignature:
    """
    Builds a 'test' merkle signature. Used exclusively for unit tests
    :return:
    """
    import time

    if not sk:
        sk, vk = wallet.new()

    signature = wallet.sign(sk, msg)

    return MerkleSignature.create(sig_hex=signature,
                                  timestamp=str(time.time()),
                                  sender=vk)
コード例 #16
0
ファイル: swap.py プロジェクト: sanko61/cilantro
    def create_tx_struct(sender_s, sender_v, receiver, amount, hashlock,
                         expiration):
        # Adjust amount for fixed point arithmetic
        # amount *= pow(10, Constants.Protocol.DecimalPrecision)
        # if type(amount) == float:
        #     amount = int(round(amount, 0))

        tx = transaction_capnp.SwapTransaction.new_message()

        tx.payload.sender = sender_v
        tx.payload.receiver = receiver
        tx.payload.amount = amount
        tx.payload.hashlock = hashlock
        tx.payload.expiration = expiration
        payload_binary = tx.payload.copy().to_bytes()

        tx.metadata.proof = SHA3POW.find(payload_binary)[0]
        tx.metadata.signature = wallet.sign(sender_s, payload_binary)

        return tx
コード例 #17
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
        }
コード例 #18
0
    def test_serialization(self):
        """
        Tests that a created block data reply successfully serializes and deserializes. The deserialized object should
        have the same properties as the original one before it was serialized.
        """
        msg = b'this is a pretend merkle tree hash'
        sk, vk = wallet.new()
        signature = wallet.sign(sk, msg)

        timestamp = 'now'
        valid_merkle_sig = MerkleSignature.create(sig_hex=signature,
                                                  timestamp=timestamp,
                                                  sender=vk)

        valid_merkle_sig_serialized = valid_merkle_sig.serialize()

        clone = MerkleSignature.from_bytes(valid_merkle_sig_serialized)

        self.assertEqual(valid_merkle_sig.signature, clone.signature)
        self.assertEqual(valid_merkle_sig.timestamp, clone.timestamp)
        self.assertEqual(valid_merkle_sig.sender, clone.sender)
コード例 #19
0
    def create_tx_struct(sender_s, sender_v, receiver, amount):
        # Adjust amount for fixed point arithmetic
        # amount *= pow(10, Constants.Protocol.DecimalPrecision)
        # if type(amount) == float:
        #     amount = int(round(amount, 0))

        # Quick assertion for now since we dont support real number amounts
        assert type(
            amount
        ) is int, "Transaction amount must be an integer (fixed point precision not yet supported)"

        tx = transaction_capnp.StandardTransaction.new_message()

        tx.payload.sender = sender_v
        tx.payload.receiver = receiver
        tx.payload.amount = amount
        payload_binary = tx.payload.copy().to_bytes()

        tx.metadata.proof = SHA3POW.find(payload_binary)[0]
        tx.metadata.signature = wallet.sign(sender_s, payload_binary)

        return tx
コード例 #20
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
コード例 #21
0
    def store_block(cls,
                    block_contender: BlockContender,
                    raw_transactions: List[bytes],
                    publisher_sk: str,
                    timestamp: int = 0) -> str:
        """
        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. If the block was successfully stored, this method will
        return the hash of the stored 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: The hash of the stored block
        :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 = wallet.get_vk(publisher_sk)
        publisher_sig = wallet.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
        log.info(
            "Attempting to persist new block with hash {}".format(block_hash))
        block_data = cls._encode_block(block_data)

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

            # 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))

            return block_hash