Ejemplo n.º 1
0
    def test_contract_with_4bit_shard_mask(self):
        EXPECTED_PAYLOAD = "a12180532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d464c0c8c103e8c2000f42401c0b666f6f2e6261722e62617a066c61756e6368000418c2a33af8bd2cba7fa714a840a308a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75a0251c"

        mask = BitVector(4)
        mask.set(3, 1)
        mask.set(2, 1)

        # build the payload bytes for the transaction
        payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_signer(IDENTITIES[0])
        payload.charge_rate = 1000
        payload.charge_limit = 1000000
        payload.valid_from = 100
        payload.valid_until = 200
        payload.target_chain_code('foo.bar.baz', mask)
        payload.action = 'launch'

        # sign the final transaction
        transaction_bytes = encode_transaction(payload, [ENTITIES[0]])

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)
Ejemplo n.º 2
0
    def create(self, owner: Entity, contract: 'SmartContract', fee: int):
        ENDPOINT = 'create'
        # format the data to be closed by the transaction

        # wildcard for the moment
        shard_mask = BitVector()

        # build up the basic transaction information
        tx = Transaction()
        tx.from_address = Address(owner)
        tx.valid_until = 10000
        tx.charge_rate = 1
        tx.charge_limit = fee
        tx.target_chain_code(self.API_PREFIX, shard_mask)
        tx.action = ENDPOINT
        tx.data = self._encode_json({
            'text': contract.encoded_source,
            'digest': contract.digest.to_hex(),
        })
        tx.add_signer(owner)

        # encode and sign the transaction
        encoded_tx = encode_transaction(tx, [owner])

        # update the contracts owner
        contract.owner = owner

        # submit the transaction
        return self._post_tx_json(encoded_tx, ENDPOINT)
Ejemplo n.º 3
0
    def test_contract_with_large_shard_mask(self):
        EXPECTED_DIGEST = "a4eff45d0374d29f259aba25fb06dd67394149b636927d199062102d91c0f7bf"
        EXPECTED_PAYLOAD = \
            "a1418000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d464c0c8c103e8c2000f42" \
            "4041eaab0b666f6f2e6261722e62617a066c61756e63680000000000000000000418c2a33af8bd2cba7fa714a840" \
            "a308a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bb" \
            "dc75a0251c"

        mask = BitVector(16)
        mask.set(15, 1)
        mask.set(14, 1)
        mask.set(13, 1)
        mask.set(11, 1)
        mask.set(9, 1)
        mask.set(7, 1)
        mask.set(5, 1)
        mask.set(3, 1)
        mask.set(1, 1)
        mask.set(0, 1)

        # build the payload bytes for the transaction
        with mock.patch('random.getrandbits') as mock_counter:
            mock_counter.side_effect = [0]
            payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_signer(IDENTITIES[0])
        payload.charge_rate = 1000
        payload.charge_limit = 1000000
        payload.valid_from = 100
        payload.valid_until = 200
        payload.target_chain_code('foo.bar.baz', mask)
        payload.action = 'launch'

        # sign the final transaction
        transaction_bytes = encode_transaction(payload, [ENTITIES[0]])

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)

        # Check payload digest
        buffer = io.BytesIO()
        encode_payload(buffer, payload)
        self.assertEqual(sha256_hash(buffer.getvalue()), EXPECTED_DIGEST)
Ejemplo n.º 4
0
    def test_contract_with_4bit_shard_mask(self):
        EXPECTED_DIGEST = "7915d6393fb07dbb4ff6896ef0f57025e5153b744d3a652b0f4815f129a9033c"
        EXPECTED_PAYLOAD = \
            "a1418000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d464c0c8c103e8c2000f42" \
            "401c0b666f6f2e6261722e62617a066c61756e63680000000000000000000418c2a33af8bd2cba7fa714a840a308" \
            "a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75" \
            "a0251c"

        mask = BitVector(4)
        mask.set(3, 1)
        mask.set(2, 1)

        # build the payload bytes for the transaction
        with mock.patch('random.getrandbits') as mock_counter:
            mock_counter.side_effect = [0]
            payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_signer(IDENTITIES[0])
        payload.charge_rate = 1000
        payload.charge_limit = 1000000
        payload.valid_from = 100
        payload.valid_until = 200
        payload.target_chain_code('foo.bar.baz', mask)
        payload.action = 'launch'

        # sign the final transaction
        transaction_bytes = encode_transaction(payload, [ENTITIES[0]])

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)

        # Check payload digest
        buffer = io.BytesIO()
        encode_payload(buffer, payload)
        self.assertEqual(sha256_hash(buffer.getvalue()), EXPECTED_DIGEST)
Ejemplo n.º 5
0
    def test_contract_with_4bit_shard_mask(self):
        EXPECTED_DIGEST = "e1ac018356792e492aaac92bf6928af1e47ed987761b81cafb51f1106f403eee"
        EXPECTED_PAYLOAD = \
            "a1618000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d464c0c8c103e8c2000f42" \
            "401c0b666f6f2e6261722e62617a066c61756e63680000000000000000000418c2a33af8bd2cba7fa714a840a308" \
            "a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75" \
            "a0251c"

        mask = BitVector(4)
        mask.set(3, 1)
        mask.set(2, 1)

        # build the payload bytes for the transaction
        with mock.patch('random.getrandbits') as mock_counter:
            mock_counter.side_effect = [0]
            payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_signer(IDENTITIES[0])
        payload.charge_rate = 1000
        payload.charge_limit = 1000000
        payload.valid_from = 100
        payload.valid_until = 200
        payload.target_chain_code('foo.bar.baz', mask)
        payload.action = 'launch'

        # sign the final transaction
        payload.sign(ENTITIES[0])
        transaction_bytes = transaction.encode_transaction(payload)

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = transaction.decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)

        # Check payload digest
        self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)
Ejemplo n.º 6
0
    def wealth(self, entity: Entity, amount: int):
        """
        Creates wealth for specified account

        :param private_key_bin: The bytes of the private key of the targeted address
        :param amount: The amount of wealth to be generated
        :param fee: The fee value to be used for the transaction
        :return: The digest of the submitted transaction
        :raises: ApiError on any failures
        """
        ENDPOINT = 'wealth'

        # format the data to be closed by the transaction

        # wildcard for the moment
        shard_mask = BitVector()

        # build up the basic transaction information
        tx = Transaction()
        tx.from_address = Address(entity)
        tx.valid_until = 10000
        tx.charge_rate = 1
        tx.charge_limit = 10
        tx.target_chain_code(self.API_PREFIX, shard_mask)
        tx.action = 'wealth'
        tx.add_signer(entity)

        # format the transaction payload
        tx.data = self._encode_json({
            'address': entity.public_key,
            'amount': amount
        })

        # encode and sign the transaction
        encoded_tx = encode_transaction(tx, [entity])

        # submit the transaction
        return self._post_tx_json(encoded_tx, ENDPOINT)
Ejemplo n.º 7
0
    def test_chain_code(self):
        EXPECTED_DIGEST = "25cc72ca7d4871aaaabd027af129ecd4327adde5ec0c9977bfe11018d4bab64a"

        EXPECTED_PAYLOAD = \
            "a1608000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d400c103e8c2000f424080" \
            "0b666f6f2e6261722e62617a066c61756e636802676f00000000000000000418c2a33af8bd2cba7fa714a840a308" \
            "a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75" \
            "a0251c"

        # build the payload bytes for the transaction
        with mock.patch('random.getrandbits') as mock_counter:
            mock_counter.side_effect = [0]
            payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_signer(IDENTITIES[0])
        payload.charge_rate = 1000
        payload.charge_limit = 1000000
        payload.target_chain_code('foo.bar.baz', BitVector())
        payload.action = 'launch'
        payload.data = 'go'.encode('ascii')

        # sign the final transaction
        payload.sign(ENTITIES[0])

        transaction_bytes = transaction.encode_transaction(payload)

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = transaction.decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)

        # Check payload digest
        self.assertEqual(sha256_hex(payload.encode_payload()), EXPECTED_DIGEST)
Ejemplo n.º 8
0
    def test_chain_code(self):
        EXPECTED_DIGEST = "7032dd625b0a93aec85fa03696d0ecbc9de19d834ce3fd1d1ed9cf8a56d9f62e"
        EXPECTED_PAYLOAD = \
            "a1408000532398dd883d1990f7dad3fde6a53a53347afc2680a04748f7f15ad03cadc4d400c103e8c2000f424080" \
            "0b666f6f2e6261722e62617a066c61756e636802676f00000000000000000418c2a33af8bd2cba7fa714a840a308" \
            "a217aa4483880b1ef14b4fdffe08ab956e3f4b921cec33be7c258cfd7025a2b9a942770e5b17758bcc4961bbdc75" \
            "a0251c"

        # build the payload bytes for the transaction
        with mock.patch('random.getrandbits') as mock_counter:
            mock_counter.side_effect = [0]
            payload = Transaction()
        payload.from_address = IDENTITIES[0]
        payload.add_signer(IDENTITIES[0])
        payload.charge_rate = 1000
        payload.charge_limit = 1000000
        payload.target_chain_code('foo.bar.baz', BitVector())
        payload.action = 'launch'
        payload.data = 'go'.encode('ascii')

        # sign the final transaction
        transaction_bytes = encode_transaction(payload, [ENTITIES[0]])

        self.assertIsExpectedTx(payload, transaction_bytes, EXPECTED_PAYLOAD)

        # attempt to decode a transaction from the generated bytes
        buffer = io.BytesIO(transaction_bytes)
        success, tx = decode_transaction(buffer)

        self.assertTrue(success)
        self.assertTxAreEqual(payload, tx)

        # Check payload digest
        buffer = io.BytesIO()
        encode_payload(buffer, payload)
        self.assertEqual(sha256_hash(buffer.getvalue()), EXPECTED_DIGEST)
Ejemplo n.º 9
0
def decode_transaction(stream: io.BytesIO) -> (bool, Transaction):
    # ensure the at the magic is correctly configured
    magic = stream.read(1)[0]
    if magic != MAGIC:
        raise RuntimeError('Unable to parse transaction from stream, invalid magic')

    # extract the header bytes
    header = stream.read(2)

    # parse the header types
    version = (header[0] & 0xE0) >> 5
    charge_unit_flag = bool((header[0] & 0x08) >> 3)
    transfer_flag = bool((header[0] & 0x04) >> 2)
    multiple_transfers_flag = bool((header[0] & 0x02) >> 1)
    valid_from_flag = bool((header[0] & 0x01))

    contract_type = (header[1] & 0xC0) >> 6
    signature_count_minus1 = (header[1] & 0x3F)

    num_signatures = signature_count_minus1 + 1

    # ensure that the version is correct
    if version != VERSION:
        raise RuntimeError('Unable to parse transaction from stream, incompatible version')

    # Ready empty reserved byte
    stream.read(1)

    tx = Transaction()

    # decode the address from the thread
    tx.from_address = address.decode(stream)

    if transfer_flag:

        # determine the number of transfers that are present in the transaction
        if multiple_transfers_flag:
            transfer_count = integer.decode(stream) + 2
        else:
            transfer_count = 1

        for n in range(transfer_count):
            to = address.decode(stream)
            amount = integer.decode(stream)

            tx.add_transfer(to, amount)

    if valid_from_flag:
        tx.valid_from = integer.decode(stream)

    tx.valid_until = integer.decode(stream)
    tx.charge_rate = integer.decode(stream)

    assert not charge_unit_flag, "Currently the charge unit field is not supported"

    tx.charge_limit = integer.decode(stream)

    if contract_type != NO_CONTRACT:
        contract_header = int(stream.read(1)[0])

        wildcard = bool(contract_header & 0x80)

        shard_mask = BitVector()
        if not wildcard:
            extended_shard_mask_flag = bool(contract_header & 0x40)

            if not extended_shard_mask_flag:

                if contract_header & 0x10:
                    mask = 0xf
                    bit_size = 4
                else:
                    mask = 0x3
                    bit_size = 2

                # extract the shard mask from the header
                shard_mask = BitVector.from_bytes(bytes([contract_header & mask]), bit_size)

            else:
                bit_length = 1 << ((contract_header & 0x3F) + 3)
                byte_length = bit_length // 8

                assert (bit_length % 8) == 0  # this should be enforced as part of the spec

                # extract the mask from the next N bytes
                shard_mask = BitVector.from_bytes(stream.read(byte_length), bit_length)

        if contract_type == SMART_CONTRACT or contract_type == SYNERGETIC:
            contract_digest = address.decode(stream)
            contract_address = address.decode(stream)

            tx.target_contract(contract_digest, contract_address, shard_mask)

        elif contract_type == CHAIN_CODE:
            encoded_chain_code_name = bytearray.decode(stream)

            tx.target_chain_code(encoded_chain_code_name.decode('ascii'), shard_mask)

        else:
            # this is mostly a guard against a desync between this function and `_map_contract_mode`
            raise RuntimeError("Unhandled contract type")

        tx.action = bytearray.decode(stream).decode('ascii')
        tx.data = bytearray.decode(stream)

    # Read counter value
    tx.counter = struct.unpack('<Q', stream.read(8))[0]

    if signature_count_minus1 == 0x3F:
        additional_signatures = integer.decode(stream)
        num_signatures += additional_signatures

    # extract all the signing public keys from the stream
    public_keys = [identity.decode(stream) for _ in range(num_signatures)]

    # extract full copy of the payload
    payload_bytes = stream.getvalue()[:stream.tell()]

    verified = []
    for ident in public_keys:
        # for n in range(num_signatures):

        # extract the signature from the stream
        signature = bytearray.decode(stream)

        # verify if this signature is correct
        verified.append(ident.verify(payload_bytes, signature))

        # build a metadata object to store in the tx
        tx._signers[ident] = {
            'signature': signature,
            'verified': verified[-1],
        }

    return all(verified), tx