예제 #1
0
def test_invalid_input_initialization(user_input, user_pub):
    from bigchaindb.common.transaction import Input

    with raises(TypeError):
        Input(user_input, user_pub)
    with raises(TypeError):
        Input(user_input, tx_input='somethingthatiswrong')
예제 #2
0
def test_input_deserialization_with_invalid_input(user_pub):
    from bigchaindb.common.transaction import Input

    ffill = {
        'owners_before': [user_pub],
        'fulfillment': None,
        'fulfills': None,
    }
    with raises(TypeError):
        Input.from_dict(ffill)
예제 #3
0
def test_input_deserialization_with_invalid_fulfillment_uri(user_pub):
    from bigchaindb.common.exceptions import InvalidSignature
    from bigchaindb.common.transaction import Input

    ffill = {
        'owners_before': [user_pub],
        'fulfillment': 'an invalid fulfillment',
        'fulfills': None,
    }
    with raises(InvalidSignature):
        Input.from_dict(ffill)
예제 #4
0
def test_input_serialization(ffill_uri, user_pub):
    from bigchaindb.common.transaction import Input
    from cryptoconditions import Fulfillment

    expected = {
        'owners_before': [user_pub],
        'fulfillment': ffill_uri,
        'fulfills': None,
    }
    input = Input(Fulfillment.from_uri(ffill_uri), [user_pub])
    assert input.to_dict() == expected
예제 #5
0
def test_input_deserialization_with_unsigned_fulfillment(ffill_uri, user_pub):
    from bigchaindb.common.transaction import Input
    from cryptoconditions import Fulfillment

    expected = Input(Fulfillment.from_uri(ffill_uri), [user_pub])
    ffill = {
        'owners_before': [user_pub],
        'fulfillment': Fulfillment.from_uri(ffill_uri),
        'fulfills': None,
    }
    input = Input.from_dict(ffill)

    assert input == expected
예제 #6
0
def test_multiple_input_validation_of_transfer_tx(user_input, user_output,
                                                  user_priv, user2_pub,
                                                  user2_priv, user3_pub,
                                                  user3_priv,
                                                  asset_definition):
    from bigchaindb.common.transaction import (Transaction, TransactionLink,
                                               Input, Output)
    from cryptoconditions import Ed25519Sha256
    from .utils import validate_transaction_model

    tx = Transaction(Transaction.CREATE, asset_definition, [user_input],
                     [user_output, deepcopy(user_output)])
    tx.sign([user_priv])

    inputs = [
        Input(cond.fulfillment, cond.public_keys,
              TransactionLink(tx.id, index))
        for index, cond in enumerate(tx.outputs)
    ]
    outputs = [
        Output(Ed25519Sha256(public_key=b58decode(user3_pub)), [user3_pub]),
        Output(Ed25519Sha256(public_key=b58decode(user3_pub)), [user3_pub])
    ]
    transfer_tx = Transaction('TRANSFER', {'id': tx.id}, inputs, outputs)
    transfer_tx = transfer_tx.sign([user_priv])

    assert transfer_tx.inputs_valid(tx.outputs) is True

    validate_transaction_model(tx)
예제 #7
0
def transfer_utx(user_output, user2_output, utx):
    from bigchaindb.common.transaction import (Input, TransactionLink,
                                               Transaction)
    user_output = user_output.to_dict()
    input = Input(utx.outputs[0].fulfillment, user_output['public_keys'],
                  TransactionLink(utx.id, 0))
    return Transaction('TRANSFER', {'id': utx.id}, [input], [user2_output])
예제 #8
0
def test_create_create_transaction_multiple_io(user_output, user2_output,
                                               user_pub, user2_pub,
                                               asset_definition):
    from bigchaindb.common.transaction import Transaction, Input

    # a fulfillment for a create transaction with multiple `owners_before`
    # is a fulfillment for an implicit threshold condition with
    # weight = len(owners_before)
    input = Input.generate([user_pub, user2_pub]).to_dict()
    expected = {
        'outputs': [user_output.to_dict(),
                    user2_output.to_dict()],
        'metadata': {
            'message': 'hello'
        },
        'inputs': [input],
        'operation': 'CREATE',
        'version': Transaction.VERSION
    }
    tx = Transaction.create([user_pub, user2_pub], [([user_pub], 1),
                                                    ([user2_pub], 1)],
                            metadata={
                                'message': 'hello'
                            }).to_dict()
    tx.pop('id')
    tx.pop('asset')

    assert tx == expected
def test_validate_tx_threshold_duplicated_pk(user_pub, user_priv,
                                             asset_definition):
    from cryptoconditions import Ed25519Sha256, ThresholdSha256
    from bigchaindb.common.transaction import Input, Output, Transaction

    threshold = ThresholdSha256(threshold=2)
    threshold.add_subfulfillment(Ed25519Sha256(public_key=b58decode(user_pub)))
    threshold.add_subfulfillment(Ed25519Sha256(public_key=b58decode(user_pub)))

    threshold_input = Input(threshold, [user_pub, user_pub])
    threshold_output = Output(threshold, [user_pub, user_pub])

    tx = Transaction(Transaction.CREATE, asset_definition, [threshold_input],
                     [threshold_output])
    expected = deepcopy(threshold_input)
    expected.fulfillment.subconditions[0]['body'].sign(
        str(tx).encode(), b58decode(user_priv))
    expected.fulfillment.subconditions[1]['body'].sign(
        str(tx).encode(), b58decode(user_priv))

    tx.sign([user_priv, user_priv])

    subconditions = tx.inputs[0].fulfillment.subconditions
    expected_subconditions = expected.fulfillment.subconditions
    assert subconditions[0]['body'].to_dict()['signature'] == \
        expected_subconditions[0]['body'].to_dict()['signature']
    assert subconditions[1]['body'].to_dict()['signature'] == \
        expected_subconditions[1]['body'].to_dict()['signature']

    assert tx.inputs[0].to_dict()['fulfillment'] == \
        expected.fulfillment.serialize_uri()
    assert tx.inputs_valid() is True
예제 #10
0
def prepare_transfer(inputs, outputs, metadata=None):
    """Create an instance of a :class:`~.Output`.

    Args:
        inputs (list of
                    (dict):
                        {
                            'tx': <(bigchaindb.common.transactionTransaction):
                                    input transaction, can differ but must have same asset id>,
                            'output': <(int): output index of tx>
                        }
                )
        outputs (list of
                    (dict):
                        {
                            'condition': <(cryptoconditions.Condition): output condition>,
                            'public_keys': <(optional list of base58): for indexing defaults to `None`>,
                            'amount': <(int): defaults to `1`>
                        }
                )
        metadata (dict)
    Raises:
        TypeError: if `public_keys` is not instance of `list`.
            """
    from bigchaindb.common.transaction import (Input, Output, TransactionLink)

    from bigchaindb.models import Transaction

    from cryptoconditions import (Fulfillment, Condition)

    asset = inputs[0]['tx']['asset']
    asset = {'id': asset['id'] if 'id' in asset else inputs[0]['tx']['id']}

    _inputs, _outputs = [], []

    for _input in inputs:

        _output = _input['tx']['outputs'][_input['output']]
        _inputs.append(
            Input(fulfillment=Condition.from_uri(_output['condition']['uri']),
                  owners_before=_output['public_keys'],
                  fulfills=TransactionLink(txid=_input['tx']['id'],
                                           output=_input['output'])))

    for output in outputs:
        _outputs.append(
            Output(fulfillment=output['condition'],
                   public_keys=output['public_keys']
                   if "public_keys" in output else [],
                   amount=output['amount'] if "amount" in output else 1))

    return Transaction(
        operation='TRANSFER',
        asset=asset,
        inputs=_inputs,
        outputs=_outputs,
        metadata=metadata,
    )
예제 #11
0
def create(owner_before, outputs, metadata, asset_data):
    """
    Generate a CREATE transaction.

    The CREATE transaction creates a new asset.
    """
    input_ = Input.generate([owner_before])
    outputs = [Output.from_dict(c) for c in listify(outputs)]
    tx = Transaction(Transaction.CREATE, {'data': asset_data}, [input_],
                     outputs, metadata)
    tx = Transaction._to_str(tx.to_dict())
    click.echo(tx)
    def test_non_create_input_not_found(self, b, user_pk):
        from cryptoconditions import Ed25519Sha256
        from bigchaindb.common.exceptions import InputDoesNotExist
        from bigchaindb.common.transaction import Input, TransactionLink
        from bigchaindb.models import Transaction

        # Create an input for a non existing transaction
        input = Input(Ed25519Sha256(public_key=b58decode(user_pk)), [user_pk],
                      TransactionLink('somethingsomething', 0))
        tx = Transaction.transfer([input], [([user_pk], 1)],
                                  asset_id='mock_asset_link')
        with pytest.raises(InputDoesNotExist):
            tx.validate(b)
예제 #13
0
def transfer(inputs, outputs, asset, metadata):
    """
    Generate a TRANSFER transaction.

    The TRANSFER transaction transfers ownership of a given asset.
    """
    inputs = [Input.from_dict(i) for i in listify(inputs)]
    outputs = [Output.from_dict(i) for i in listify(outputs)]
    tx = Transaction(Transaction.TRANSFER,
                     asset=asset,
                     inputs=inputs,
                     outputs=outputs,
                     metadata=metadata)
    click.echo(Transaction._to_str(tx.to_dict()))
예제 #14
0
def test_validate_tx_threshold_duplicated_pk(user_pub, user_priv,
                                             asset_definition):
    from cryptoconditions import Ed25519Sha256, ThresholdSha256
    from bigchaindb.common.transaction import Input, Output, Transaction

    threshold = ThresholdSha256(threshold=2)
    threshold.add_subfulfillment(Ed25519Sha256(public_key=b58decode(user_pub)))
    threshold.add_subfulfillment(Ed25519Sha256(public_key=b58decode(user_pub)))

    threshold_input = Input(threshold, [user_pub, user_pub])
    threshold_output = Output(threshold, [user_pub, user_pub])

    tx = Transaction(Transaction.CREATE, asset_definition, [threshold_input],
                     [threshold_output])

    tx_dict = tx.to_dict()
    tx_dict['inputs'][0]['fulfillment'] = None
    serialized_tx = json.dumps(tx_dict,
                               sort_keys=True,
                               separators=(',', ':'),
                               ensure_ascii=True)
    message = sha3_256(serialized_tx.encode()).digest()

    expected = deepcopy(threshold_input)
    expected.fulfillment.subconditions[0]['body'].sign(message,
                                                       b58decode(user_priv))
    expected.fulfillment.subconditions[1]['body'].sign(message,
                                                       b58decode(user_priv))

    tx.sign([user_priv, user_priv])

    subconditions = tx.inputs[0].fulfillment.subconditions
    expected_subconditions = expected.fulfillment.subconditions
    assert subconditions[0]['body'].to_dict()['signature'] == \
        expected_subconditions[0]['body'].to_dict()['signature']
    assert subconditions[1]['body'].to_dict()['signature'] == \
        expected_subconditions[1]['body'].to_dict()['signature']

    assert tx.inputs[0].to_dict()['fulfillment'] == \
        expected.fulfillment.serialize_uri()
    assert tx.inputs_valid() is True
예제 #15
0
def main():
    """ Main function """

    ctx = {}

    def pretty_json(data):
        return json.dumps(data, indent=2, sort_keys=True)

    client = server.create_app().test_client()

    host = 'example.com:9984'

    # HTTP Index
    res = client.get('/', environ_overrides={'HTTP_HOST': host})
    res_data = json.loads(res.data.decode())
    ctx['index'] = pretty_json(res_data)

    # API index
    res = client.get('/api/v1/', environ_overrides={'HTTP_HOST': host})
    ctx['api_index'] = pretty_json(json.loads(res.data.decode()))

    # tx create
    privkey = 'CfdqtD7sS7FgkMoGPXw55MVGGFwQLAoHYTcBhZDtF99Z'
    pubkey = '4K9sWUMFwTgaDGPfdynrbxWqWS6sWmKbZoTjxLtVUibD'
    asset = {'msg': 'Hello BigchainDB!'}
    tx = Transaction.create([pubkey], [([pubkey], 1)],
                            asset=asset,
                            metadata={'sequence': 0})
    tx = tx.sign([privkey])
    ctx['tx'] = pretty_json(tx.to_dict())
    ctx['public_keys'] = tx.outputs[0].public_keys[0]
    ctx['txid'] = tx.id

    # tx transfer
    privkey_transfer = '3AeWpPdhEZzWLYfkfYHBfMFC2r1f8HEaGS9NtbbKssya'
    pubkey_transfer = '3yfQPHeWAa1MxTX9Zf9176QqcpcnWcanVZZbaHb8B3h9'

    cid = 0
    input_ = Input(fulfillment=tx.outputs[cid].fulfillment,
                   fulfills=TransactionLink(txid=tx.id, output=cid),
                   owners_before=tx.outputs[cid].public_keys)
    tx_transfer = Transaction.transfer([input_], [([pubkey_transfer], 1)],
                                       asset_id=tx.id,
                                       metadata={'sequence': 1})
    tx_transfer = tx_transfer.sign([privkey])
    ctx['tx_transfer'] = pretty_json(tx_transfer.to_dict())
    ctx['public_keys_transfer'] = tx_transfer.outputs[0].public_keys[0]
    ctx['tx_transfer_id'] = tx_transfer.id

    # privkey_transfer_last = 'sG3jWDtdTXUidBJK53ucSTrosktG616U3tQHBk81eQe'
    pubkey_transfer_last = '3Af3fhhjU6d9WecEM9Uw5hfom9kNEwE7YuDWdqAUssqm'

    cid = 0
    input_ = Input(fulfillment=tx_transfer.outputs[cid].fulfillment,
                   fulfills=TransactionLink(txid=tx_transfer.id, output=cid),
                   owners_before=tx_transfer.outputs[cid].public_keys)
    tx_transfer_last = Transaction.transfer([input_],
                                            [([pubkey_transfer_last], 1)],
                                            asset_id=tx.id,
                                            metadata={'sequence': 2})
    tx_transfer_last = tx_transfer_last.sign([privkey_transfer])
    ctx['tx_transfer_last'] = pretty_json(tx_transfer_last.to_dict())
    ctx['tx_transfer_last_id'] = tx_transfer_last.id
    ctx['public_keys_transfer_last'] = tx_transfer_last.outputs[0].public_keys[
        0]

    # block
    node_private = "5G2kE1zJAgTajkVSbPAQWo4c2izvtwqaNHYsaNpbbvxX"
    node_public = "DngBurxfeNVKZWCEcDnLj1eMPAS7focUZTE5FndFGuHT"
    signature = "53wxrEQDYk1dXzmvNSytbCfmNVnPqPkDQaTnAe8Jf43s6ssejPxezkCvUnGTnduNUmaLjhaan1iRLi3peu6s5DzA"

    app_hash = 'f6e0c49c6d94d6924351f25bb334cf2a99af4206339bf784e741d1a5ab599056'
    block = lib.Block(height=1, transactions=[tx.to_dict()], app_hash=app_hash)
    block_dict = block._asdict()
    block_dict.pop('app_hash')
    ctx['block'] = pretty_json(block_dict)
    ctx['blockid'] = block.height

    # block status
    block_list = [block.height]
    ctx['block_list'] = pretty_json(block_list)

    base_path = os.path.join(os.path.dirname(__file__), 'source/http-samples')
    if not os.path.exists(base_path):
        os.makedirs(base_path)

    for name, tpl in TPLS.items():
        path = os.path.join(base_path, name + '.http')
        code = tpl % ctx
        with open(path, 'w') as handle:
            handle.write(code)
def main():
    """ Main function """

    ctx = {}

    def pretty_json(data):
        return json.dumps(data, indent=2, sort_keys=True)

    client = server.create_app().test_client()

    host = 'example.com:9984'

    # HTTP Index
    res = client.get('/', environ_overrides={'HTTP_HOST': host})
    res_data = json.loads(res.data.decode())
    res_data['keyring'] = [
        "6qHyZew94NMmUTYyHnkZsB8cxJYuRNEiEpXHe1ih9QX3",
        "AdDuyrTyjrDt935YnFu4VBCVDhHtY2Y6rcy7x2TFeiRi"
    ]
    res_data['public_key'] = 'NC8c8rYcAhyKVpx1PCV65CBmyq4YUbLysy3Rqrg8L8mz'
    ctx['index'] = pretty_json(res_data)

    # API index
    res = client.get('/api/v1/', environ_overrides={'HTTP_HOST': host})
    ctx['api_index'] = pretty_json(json.loads(res.data.decode()))

    # tx create
    privkey = 'CfdqtD7sS7FgkMoGPXw55MVGGFwQLAoHYTcBhZDtF99Z'
    pubkey = '4K9sWUMFwTgaDGPfdynrbxWqWS6sWmKbZoTjxLtVUibD'
    asset = {'msg': 'Hello BigchainDB!'}
    tx = Transaction.create([pubkey], [([pubkey], 1)],
                            asset=asset,
                            metadata={'sequence': 0})
    tx = tx.sign([privkey])
    ctx['tx'] = pretty_json(tx.to_dict())
    ctx['public_keys'] = tx.outputs[0].public_keys[0]
    ctx['txid'] = tx.id

    # tx transfer
    privkey_transfer = '3AeWpPdhEZzWLYfkfYHBfMFC2r1f8HEaGS9NtbbKssya'
    pubkey_transfer = '3yfQPHeWAa1MxTX9Zf9176QqcpcnWcanVZZbaHb8B3h9'

    cid = 0
    input_ = Input(fulfillment=tx.outputs[cid].fulfillment,
                   fulfills=TransactionLink(txid=tx.id, output=cid),
                   owners_before=tx.outputs[cid].public_keys)
    tx_transfer = Transaction.transfer([input_], [([pubkey_transfer], 1)],
                                       asset_id=tx.id,
                                       metadata={'sequence': 1})
    tx_transfer = tx_transfer.sign([privkey])
    ctx['tx_transfer'] = pretty_json(tx_transfer.to_dict())
    ctx['public_keys_transfer'] = tx_transfer.outputs[0].public_keys[0]
    ctx['tx_transfer_id'] = tx_transfer.id

    # privkey_transfer_last = 'sG3jWDtdTXUidBJK53ucSTrosktG616U3tQHBk81eQe'
    pubkey_transfer_last = '3Af3fhhjU6d9WecEM9Uw5hfom9kNEwE7YuDWdqAUssqm'

    cid = 0
    input_ = Input(fulfillment=tx_transfer.outputs[cid].fulfillment,
                   fulfills=TransactionLink(txid=tx_transfer.id, output=cid),
                   owners_before=tx_transfer.outputs[cid].public_keys)
    tx_transfer_last = Transaction.transfer([input_],
                                            [([pubkey_transfer_last], 1)],
                                            asset_id=tx.id,
                                            metadata={'sequence': 2})
    tx_transfer_last = tx_transfer_last.sign([privkey_transfer])
    ctx['tx_transfer_last'] = pretty_json(tx_transfer_last.to_dict())
    ctx['tx_transfer_last_id'] = tx_transfer_last.id
    ctx['public_keys_transfer_last'] = tx_transfer_last.outputs[0].public_keys[
        0]

    # block
    node_private = "5G2kE1zJAgTajkVSbPAQWo4c2izvtwqaNHYsaNpbbvxX"
    node_public = "DngBurxfeNVKZWCEcDnLj1eMPAS7focUZTE5FndFGuHT"
    signature = "53wxrEQDYk1dXzmvNSytbCfmNVnPqPkDQaTnAe8Jf43s6ssejPxezkCvUnGTnduNUmaLjhaan1iRLi3peu6s5DzA"
    block = Block(transactions=[tx],
                  node_pubkey=node_public,
                  voters=[node_public],
                  signature=signature)
    ctx['block'] = pretty_json(block.to_dict())
    ctx['blockid'] = block.id

    block_transfer = Block(transactions=[tx_transfer],
                           node_pubkey=node_public,
                           voters=[node_public],
                           signature=signature)
    ctx['block_transfer'] = pretty_json(block.to_dict())

    # vote
    DUMMY_SHA3 = '0123456789abcdef' * 4
    b = Bigchain(public_key=node_public, private_key=node_private)
    vote = b.vote(block.id, DUMMY_SHA3, True)
    ctx['vote'] = pretty_json(vote)

    # block status
    block_list = [block_transfer.id, block.id]
    ctx['block_list'] = pretty_json(block_list)

    base_path = os.path.join(os.path.dirname(__file__), 'source/http-samples')
    if not os.path.exists(base_path):
        os.makedirs(base_path)

    for name, tpl in TPLS.items():
        path = os.path.join(base_path, name + '.http')
        code = tpl % ctx
        with open(path, 'w') as handle:
            handle.write(code)
예제 #17
0
def user_user2_threshold_input(user_user2_threshold, user_pub, user2_pub):
    from bigchaindb.common.transaction import Input
    return Input(user_user2_threshold, [user_pub, user2_pub])
예제 #18
0
def user_input(user_Ed25519, user_pub):
    from bigchaindb.common.transaction import Input
    return Input(user_Ed25519, [user_pub])
예제 #19
0
def prepare_transfer_transaction(*, inputs, recipients, asset, metadata=None):
    """Prepares a ``"TRANSFER"`` transaction payload, ready to be
    fulfilled.

    Args:
        inputs (:obj:`dict` | :obj:`list` | :obj:`tuple`): One or more
            inputs holding the condition(s) that this transaction
            intends to fulfill. Each input is expected to be a
            :obj:`dict`.
        recipients (:obj:`str` | :obj:`list` | :obj:`tuple`): One or
            more public keys representing the new recipients(s) of the
            asset being transferred.
        asset (:obj:`dict`): A single-key dictionary holding the ``id``
            of the asset being transferred with this transaction.
        metadata (:obj:`dict`): Metadata associated with the
            transaction. Defaults to ``None``.

    Returns:
        dict: The prepared ``"TRANSFER"`` transaction.

    .. important::

        * ``asset`` MUST be in the form of::

            {
                'id': '<Asset ID (i.e. TX ID of its CREATE transaction)>'
            }

    Example:

        .. todo:: Replace this section with docs.

        In case it may not be clear what an input should look like, say
        Alice (public key: ``'3Cxh1eKZk3Wp9KGBWFS7iVde465UvqUKnEqTg2MW4wNf'``)
        wishes to transfer an asset over to Bob
        (public key: ``'EcRawy3Y22eAUSS94vLF8BVJi62wbqbD9iSUSUNU9wAA'``).
        Let the asset creation transaction payload be denoted by
        ``tx``::

            # noqa E501
            >>> tx
                {'asset': {'data': {'msg': 'Hello BigchainDB!'}},
                 'id': '9650055df2539223586d33d273cb8fd05bd6d485b1fef1caf7c8901a49464c87',
                 'inputs': [{'fulfillment': {'public_key': '3Cxh1eKZk3Wp9KGBWFS7iVde465UvqUKnEqTg2MW4wNf',
                                             'type': 'ed25519-sha-256'},
                             'fulfills': None,
                             'owners_before': ['3Cxh1eKZk3Wp9KGBWFS7iVde465UvqUKnEqTg2MW4wNf']}],
                 'metadata': None,
                 'operation': 'CREATE',
                 'outputs': [{'amount': '1',
                              'condition': {'details': {'public_key': '3Cxh1eKZk3Wp9KGBWFS7iVde465UvqUKnEqTg2MW4wNf',
                                                        'type': 'ed25519-sha-256'},
                                            'uri': 'ni:///sha-256;7ApQLsLLQgj5WOUipJg1txojmge68pctwFxvc3iOl54?fpt=ed25519-sha-256&cost=131072'},
                              'public_keys': ['3Cxh1eKZk3Wp9KGBWFS7iVde465UvqUKnEqTg2MW4wNf']}],
                 'version': '2.0'}

        Then, the input may be constructed in this way::

            output_index
            output = tx['transaction']['outputs'][output_index]
            input_ = {
                'fulfillment': output['condition']['details'],
                'input': {
                    'output_index': output_index,
                    'transaction_id': tx['id'],
                },
                'owners_before': output['owners_after'],
            }

        Displaying the input on the prompt would look like::

            >>> input_
            {'fulfillment': {
              'public_key': '3Cxh1eKZk3Wp9KGBWFS7iVde465UvqUKnEqTg2MW4wNf',
              'type': 'ed25519-sha-256'},
             'input': {'output_index': 0,
              'transaction_id': '9650055df2539223586d33d273cb8fd05bd6d485b1fef1caf7c8901a49464c87'},
             'owners_before': ['3Cxh1eKZk3Wp9KGBWFS7iVde465UvqUKnEqTg2MW4wNf']}


        To prepare the transfer:

        >>> prepare_transfer_transaction(
        ...     inputs=input_,
        ...     recipients='EcRawy3Y22eAUSS94vLF8BVJi62wbqbD9iSUSUNU9wAA',
        ...     asset=tx['transaction']['asset'],
        ... )

    """
    if not isinstance(inputs, (list, tuple)):
        inputs = (inputs, )
    if not isinstance(recipients, (list, tuple)):
        recipients = [([recipients], 1)]

    # NOTE: Needed for the time being. See
    # https://github.com/bigchaindb/bigchaindb/issues/797
    if isinstance(recipients, tuple):
        recipients = [(list(recipients), 1)]

    fulfillments = [
        Input(_fulfillment_from_details(input_['fulfillment']),
              input_['owners_before'],
              fulfills=TransactionLink(
                  txid=input_['fulfills']['transaction_id'],
                  output=input_['fulfills']['output_index']))
        for input_ in inputs
    ]

    transaction = Transaction.transfer(
        fulfillments,
        recipients,
        asset_id=asset['id'],
        metadata=metadata,
    )
    return transaction.to_dict()
예제 #20
0
def prepare_transfer_transaction(*,
                                 inputs,
                                 recipients,
                                 asset,
                                 metadata=None):
    """
    Prepares a ``"TRANSFER"`` transaction payload, ready to be
    fulfilled.

    Args:
        inputs (:obj:`dict` | :obj:`list` | :obj:`tuple`): One or more
            inputs holding the condition(s) that this transaction
            intends to fulfill. Each input is expected to be a
            :obj:`dict`.
        recipients (:obj:`str` | :obj:`list` | :obj:`tuple`): One or
            more public keys representing the new recipients(s) of the
            asset being transferred.
        asset (:obj:`dict`): A single-key dictionary holding the ``id``
            of the asset being transferred with this transaction.
        metadata (:obj:`dict`): Metadata associated with the
            transaction. Defaults to ``None``.

    Returns:
        dict: The prepared ``"TRANSFER"`` transaction.

    .. important::

        * ``asset`` MUST be in the form of::

            {
                'id': '<Asset ID (i.e. TX ID of its CREATE transaction)>'
            }

    Example:

        .. todo:: Replace this section with docs.

        In case it may not be clear what an input should look like, say
        Alice (public key: ``'3Cxh1eKZk3Wp9KGBWFS7iVde465UvqUKnEqTg2MW4wNf'``)
        wishes to transfer an asset over to Bob
        (public key: ``'EcRawy3Y22eAUSS94vLF8BVJi62wbqbD9iSUSUNU9wAA'``).
        Let the asset creation transaction payload be denoted by
        ``tx``::

            # noqa E501
            >>> tx
            {'id': '57cff2b9490468bdb6d4767a1b07905fdbe18d638d9c7783f639b4b2bc165c39',
             'transaction': {'asset': {'data': {'msg': 'Hello BigchainDB!'},
               'id': '57cff2b9490468bdb6d4767a1b07905fdbe18d638d9c7783f639b4b2bc165c39'},
              'conditions': [{'amount': 1,
                'cid': 0,
                'condition': {'details': {'bitmask': 32,
                  'public_key': '3Cxh1eKZk3Wp9KGBWFS7iVde465UvqUKnEqTg2MW4wNf',
                  'signature': None,
                  'type': 'fulfillment',
                  'type_id': 4},
                 'uri': 'cc:4:20:IMe7QSL5xRAYIlXon76ZonWktR0NI02M8rAG1bN-ugg:96'},
                'owners_after': ['3Cxh1eKZk3Wp9KGBWFS7iVde465UvqUKnEqTg2MW4wNf']}],
              'fulfillments': [{'fid': 0,
                'fulfillment': 'cf:4:IMe7QSL5xRAYIlXon76ZonWktR0NI02M8rAG1bN-ughA8-9lUJYc_LGAB_NtyTPCCV58LfMcNZ9-0PUB6m1y_6pgTbCOQFBEeDtm_nC293CbpZjziwq7j3skrzS-OiAI',
                'input': None,
                'owners_before': ['3Cxh1eKZk3Wp9KGBWFS7iVde465UvqUKnEqTg2MW4wNf']}],
              'metadata': None,
              'operation': 'CREATE',
              'timestamp': '1479393278'},
             'version': 1}


        Then, the input may be constructed in this way::

            cid = 0
            condition = tx['transaction']['conditions'][cid]
            input_ = {
                'fulfillment': condition['condition']['details'],
                'input': {
                    'cid': cid,
                    'txid': tx['id'],
                },
                'owners_before': condition['owners_after'],
            }

        Displaying the input on the prompt would look like::

            >>> input_
            {'fulfillment': {'bitmask': 32,
              'public_key': '3Cxh1eKZk3Wp9KGBWFS7iVde465UvqUKnEqTg2MW4wNf',
              'signature': None,
              'type': 'fulfillment',
              'type_id': 4},
             'input': {'cid': 0,
              'txid': '57cff2b9490468bdb6d4767a1b07905fdbe18d638d9c7783f639b4b2bc165c39'},
             'owners_before': ['3Cxh1eKZk3Wp9KGBWFS7iVde465UvqUKnEqTg2MW4wNf']}


        To prepare the transfer:

        >>> prepare_transfer_transaction(
        ...     inputs=input_,
        ...     recipients='EcRawy3Y22eAUSS94vLF8BVJi62wbqbD9iSUSUNU9wAA',
        ...     asset=tx['transaction']['asset'],
        ... )

    """
    if not isinstance(inputs, (list, tuple)):
        inputs = (inputs, )
    if not isinstance(recipients, (list, tuple)):
        recipients = [([recipients], 1)]

    # NOTE: Needed for the time being. See
    # https://github.com/bigchaindb/bigchaindb/issues/797
    if isinstance(recipients, tuple):
        recipients = [(list(recipients), 1)]

    fulfillments = [
        Input(Fulfillment.from_dict(input_['fulfillment']),
              input_['owners_before'],
              fulfills=TransactionLink(**input_['fulfills']))
        for input_ in inputs
    ]

    transaction = Transaction.transfer(
        fulfillments,
        recipients,
        asset_id=asset['id'],
        metadata=metadata,
    )
    return transaction.to_dict()