Basic Usage Examples

For the examples on this page, we assume you’re using a Python 3 version of IPython (or similar), you’ve installed the bigchaindb_driver Python package, and you have determined the BigchainDB Root URL of the node or cluster you want to connect to.

Getting Started

We begin by creating an object of class BigchainDB:

In [1]: from bigchaindb_driver import BigchainDB

In [2]: bdb_root_url = 'https://example.com:9984'  # Use YOUR BigchainDB Root URL here

If the BigchainDB node or cluster doesn’t require authentication tokens, you can do:

In [3]: bdb = BigchainDB(bdb_root_url)

If it does require authentication tokens, you can do put them in a dict like so:

In [4]: tokens = {'app_id': 'your_app_id', 'app_key': 'your_app_key'}

In [5]: bdb = BigchainDB(bdb_root_url, headers=tokens)

Digital Asset Definition

As an example, let’s consider the creation and transfer of a digital asset that represents a bicycle:

In [6]: bicycle = {
   ...:     'data': {
   ...:         'bicycle': {
   ...:             'serial_number': 'abcd1234',
   ...:             'manufacturer': 'bkfab',
   ...:         },
   ...:     },
   ...: }
   ...: 

We’ll suppose that the bike belongs to Alice, and that it will be transferred to Bob.

In general, you may use any dictionary for the 'data' property.

Metadata Definition (optional)

You can optionally add metadata to a transaction. Any dictionary is accepted.

For example:

In [7]: metadata = {'planet': 'earth'}

Cryptographic Identities Generation

Alice and Bob are represented by public/private key pairs. The private key is used to sign transactions, meanwhile the public key is used to verify that a signed transaction was indeed signed by the one who claims to be the signee.

In [8]: from bigchaindb_driver.crypto import generate_keypair

In [9]: alice, bob = generate_keypair(), generate_keypair()

Asset Creation

We’re now ready to create the digital asset. First, let’s prepare the transaction:

In [10]: prepared_creation_tx = bdb.transactions.prepare(
   ....:     operation='CREATE',
   ....:     signers=alice.public_key,
   ....:     asset=bicycle,
   ....:     metadata=metadata,
   ....: )
   ....: 

The prepared_creation_tx dictionary should be similar to:

In [11]: prepared_creation_tx
Out[11]: 
{'asset': {'data': {'bicycle': {'manufacturer': 'bkfab',
    'serial_number': 'abcd1234'}}},
 'id': None,
 'inputs': [{'fulfillment': {'public_key': '7rr59L64LvvwMKr8dtieotdugk13oHkosFFoTuXCjzz6',
    'type': 'ed25519-sha-256'},
   'fulfills': None,
   'owners_before': ['7rr59L64LvvwMKr8dtieotdugk13oHkosFFoTuXCjzz6']}],
 'metadata': {'planet': 'earth'},
 'operation': 'CREATE',
 'outputs': [{'amount': '1',
   'condition': {'details': {'public_key': '7rr59L64LvvwMKr8dtieotdugk13oHkosFFoTuXCjzz6',
     'type': 'ed25519-sha-256'},
    'uri': 'ni:///sha-256;e2C00fzLhNG_nLwWVmZOyGbIQ6lqDCduYZy7HKPr23c?fpt=ed25519-sha-256&cost=131072'},
   'public_keys': ['7rr59L64LvvwMKr8dtieotdugk13oHkosFFoTuXCjzz6']}],
 'version': '2.0'}

The transaction now needs to be fulfilled by signing it with Alice’s private key:

In [12]: fulfilled_creation_tx = bdb.transactions.fulfill(
   ....:     prepared_creation_tx, private_keys=alice.private_key)
   ....: 
In [13]: fulfilled_creation_tx
Out[13]: 
{'asset': {'data': {'bicycle': {'manufacturer': 'bkfab',
    'serial_number': 'abcd1234'}}},
 'id': 'bfe679e84f528410270fe67d309f19d03afe09970650140621daedfe6f546598',
 'inputs': [{'fulfillment': 'pGSAIGXrEQNtYgyzOBswGHnoWgbUWFWVE89Kez25zti91PTzgUDY8sy8E9FtHwO9-nab89wBspemhBCshbbRRJqLlqilTQ7HbJZYMfr8_mawfTDre31pJEgLSrqFU-clmJjkrwUO',
   'fulfills': None,
   'owners_before': ['7rr59L64LvvwMKr8dtieotdugk13oHkosFFoTuXCjzz6']}],
 'metadata': {'planet': 'earth'},
 'operation': 'CREATE',
 'outputs': [{'amount': '1',
   'condition': {'details': {'public_key': '7rr59L64LvvwMKr8dtieotdugk13oHkosFFoTuXCjzz6',
     'type': 'ed25519-sha-256'},
    'uri': 'ni:///sha-256;e2C00fzLhNG_nLwWVmZOyGbIQ6lqDCduYZy7HKPr23c?fpt=ed25519-sha-256&cost=131072'},
   'public_keys': ['7rr59L64LvvwMKr8dtieotdugk13oHkosFFoTuXCjzz6']}],
 'version': '2.0'}

And sent over to a BigchainDB node:

>>> sent_creation_tx = bdb.transactions.send_commit(fulfilled_creation_tx)

Warning

The method .send will be deprecated in the next release of the driver, please use .send_commit, .send_sync, or .send_async instead. More info

Note that the response from the node should be the same as that which was sent:

>>> sent_creation_tx == fulfilled_creation_tx
True

Notice the transaction id:

In [14]: txid = fulfilled_creation_tx['id']

In [15]: txid
Out[15]: 'bfe679e84f528410270fe67d309f19d03afe09970650140621daedfe6f546598'

Check if the Transaction was sent successfully

After a couple of seconds, we can check if the transaction was included in a block.

# Retrieve the block height
>>> block_height = bdb.blocks.get(txid=signed_tx['id'])

This will return the block height containing the transaction. If the transaction is not in any block then None is returned. If it is None it can have different reasons for example the transaction was not valid or is still in the queue and you can try again later. If the transaction was invalid or could not be sent an exception is raised.

If we want to see the whole block we can use the block height to retrieve the block itself.

# Retrieve the block that contains the transaction
>>> block = bdb.blocks.retrieve(str(block_height))

Asset Transfer

Imagine some time goes by, during which Alice is happy with her bicycle, and one day, she meets Bob, who is interested in acquiring her bicycle. The timing is good for Alice as she had been wanting to get a new bicycle.

To transfer the bicycle (asset) to Bob, Alice must consume the transaction in which the Bicycle asset was created.

Alice could retrieve the transaction:

>>>  creation_tx = bdb.transactions.retrieve(txid)

or simply use fulfilled_creation_tx:

In [16]: creation_tx = fulfilled_creation_tx

In order to prepare the transfer transaction, we first need to know the id of the asset we’ll be transferring. Here, because Alice is consuming a CREATE transaction, we have a special case in that the asset id is NOT found on the asset itself, but is simply the CREATE transaction’s id:

In [17]: asset_id = creation_tx['id']

In [18]: transfer_asset = {
   ....:     'id': asset_id,
   ....: }
   ....: 

Let’s now prepare the transfer transaction:

In [19]: output_index = 0

In [20]: output = creation_tx['outputs'][output_index]

In [21]: transfer_input = {
   ....:     'fulfillment': output['condition']['details'],
   ....:     'fulfills': {
   ....:          'output_index': output_index,
   ....:          'transaction_id': creation_tx['id'],
   ....:      },
   ....:      'owners_before': output['public_keys'],
   ....: }
   ....: 

In [22]: prepared_transfer_tx = bdb.transactions.prepare(
   ....:     operation='TRANSFER',
   ....:     asset=transfer_asset,
   ....:     inputs=transfer_input,
   ....:     recipients=bob.public_key,
   ....: )
   ....: 

fulfill it:

In [23]: fulfilled_transfer_tx = bdb.transactions.fulfill(
   ....:     prepared_transfer_tx,
   ....:     private_keys=alice.private_key,
   ....: )
   ....: 

The fulfilled_transfer_tx dictionary should look something like:

In [24]: fulfilled_transfer_tx
Out[24]: 
{'asset': {'id': 'bfe679e84f528410270fe67d309f19d03afe09970650140621daedfe6f546598'},
 'id': 'fb745cf6b645f5a20a82a41adef835ce66913cc61dd01b2830085d7776855520',
 'inputs': [{'fulfillment': 'pGSAIGXrEQNtYgyzOBswGHnoWgbUWFWVE89Kez25zti91PTzgUBuHqMbJ06C2vm9aBcaz90CBXpgPZ-FQPrFLeGURN77an7EjYXGvLGeUhf-fTB9uZvpYs6utzhZPt24rdSJJXQC',
   'fulfills': {'output_index': 0,
    'transaction_id': 'bfe679e84f528410270fe67d309f19d03afe09970650140621daedfe6f546598'},
   'owners_before': ['7rr59L64LvvwMKr8dtieotdugk13oHkosFFoTuXCjzz6']}],
 'metadata': None,
 'operation': 'TRANSFER',
 'outputs': [{'amount': '1',
   'condition': {'details': {'public_key': '5RaeQAZEEQMFCLBEDrKtk5pLue4SuVkdw9Xb55ucpvQ6',
     'type': 'ed25519-sha-256'},
    'uri': 'ni:///sha-256;UKI3FbYGLQhOeu3QkZNuoWrjxGugzG4q7LxnhVqevHU?fpt=ed25519-sha-256&cost=131072'},
   'public_keys': ['5RaeQAZEEQMFCLBEDrKtk5pLue4SuVkdw9Xb55ucpvQ6']}],
 'version': '2.0'}

and finally send it to the connected BigchainDB node:

>>> sent_transfer_tx = bdb.transactions.send_commit(fulfilled_transfer_tx)

>>> sent_transfer_tx == fulfilled_transfer_tx
True

Warning

The method .send will be deprecated in the next release of the driver, please use .send_commit, .send_sync, or .send_async instead. More info

Bob is the new owner:

In [25]: fulfilled_transfer_tx['outputs'][0]['public_keys'][0] == bob.public_key
Out[25]: True

Alice is the former owner:

In [26]: fulfilled_transfer_tx['inputs'][0]['owners_before'][0] == alice.public_key
Out[26]: True

Note

Obtaining asset ids:

You might have noticed that we considered Alice’s case of consuming a CREATE transaction as a special case. In order to obtain the asset id of a CREATE transaction, we had to use the CREATE transaction’s id:

transfer_asset_id = create_tx['id']

If you instead wanted to consume TRANSFER transactions (for example, fulfilled_transfer_tx), you could obtain the asset id to transfer from the asset['id'] property:

transfer_asset_id = transfer_tx['asset']['id']

Recap: Asset Creation & Transfer

from bigchaindb_driver import BigchainDB
from bigchaindb_driver.crypto import generate_keypair
from time import sleep
from sys import exit

alice, bob = generate_keypair(), generate_keypair()

bdb_root_url = 'https://example.com:9984'  # Use YOUR BigchainDB Root URL here

bdb = BigchainDB(bdb_root_url)

bicycle_asset = {
    'data': {
        'bicycle': {
            'serial_number': 'abcd1234',
            'manufacturer': 'bkfab'
        },
    },
}

bicycle_asset_metadata = {
    'planet': 'earth'
}

prepared_creation_tx = bdb.transactions.prepare(
    operation='CREATE',
    signers=alice.public_key,
    asset=bicycle_asset,
    metadata=bicycle_asset_metadata
)

fulfilled_creation_tx = bdb.transactions.fulfill(
    prepared_creation_tx,
    private_keys=alice.private_key
)

sent_creation_tx = bdb.transactions.send_commit(fulfilled_creation_tx)

txid = fulfilled_creation_tx['id']

asset_id = txid

transfer_asset = {
    'id': asset_id
}

output_index = 0
output = fulfilled_creation_tx['outputs'][output_index]

transfer_input = {
    'fulfillment': output['condition']['details'],
    'fulfills': {
        'output_index': output_index,
        'transaction_id': fulfilled_creation_tx['id']
    },
    'owners_before': output['public_keys']
}

prepared_transfer_tx = bdb.transactions.prepare(
    operation='TRANSFER',
    asset=transfer_asset,
    inputs=transfer_input,
    recipients=bob.public_key,
)

fulfilled_transfer_tx = bdb.transactions.fulfill(
    prepared_transfer_tx,
    private_keys=alice.private_key,
)

sent_transfer_tx = bdb.transactions.send_commit(fulfilled_transfer_tx)

print("Is Bob the owner?",
    sent_transfer_tx['outputs'][0]['public_keys'][0] == bob.public_key)

print("Was Alice the previous owner?",
    fulfilled_transfer_tx['inputs'][0]['owners_before'][0] == alice.public_key)

Divisible Assets

All assets in BigchainDB become implicitly divisible if a transaction contains more than one of that asset (we’ll see how this happens shortly).

Let’s continue with the bicycle example. Bob is now the proud owner of the bicycle and he decides he wants to rent the bicycle. Bob starts by creating a time sharing token in which one token corresponds to one hour of riding time:

In [27]: bicycle_token = {
   ....:     'data': {
   ....:         'token_for': {
   ....:             'bicycle': {
   ....:                 'serial_number': 'abcd1234',
   ....:                 'manufacturer': 'bkfab'
   ....:             }
   ....:         },
   ....:         'description': 'Time share token. Each token equals one hour of riding.',
   ....:     },
   ....: }
   ....: 

Bob has now decided to issue 10 tokens and assigns them to Carly. Notice how we denote Carly as receiving 10 tokens by using a tuple: ([carly.public_key], 10).

In [28]: bob, carly = generate_keypair(), generate_keypair()

In [29]: prepared_token_tx = bdb.transactions.prepare(
   ....:     operation='CREATE',
   ....:     signers=bob.public_key,
   ....:     recipients=[([carly.public_key], 10)],
   ....:     asset=bicycle_token,
   ....: )
   ....: 

In [30]: fulfilled_token_tx = bdb.transactions.fulfill(
   ....:     prepared_token_tx, private_keys=bob.private_key)
   ....: 

The fulfilled_token_tx dictionary should look something like:

In [31]: fulfilled_token_tx
Out[31]: 
{'asset': {'data': {'description': 'Time share token. Each token equals one hour of riding.',
   'token_for': {'bicycle': {'manufacturer': 'bkfab',
     'serial_number': 'abcd1234'}}}},
 'id': 'b9eb7377b8262136ddcb9c8409aab221513b880f1ea943ff1896410f7faf1401',
 'inputs': [{'fulfillment': 'pGSAIPFc_79sdV7uwYD0AL188cC3R1y2-s8Jd7g-50A7DvmKgUBDP0caw7OQJzqewU6Eizutt2EKqV9Okt2lFZMJS9ILxpa3-dFdceOlg55GMNDHK0qEfKI69QJHAeqPmBrayxoN',
   'fulfills': None,
   'owners_before': ['HFBWEKjWtdm815RZuSq4GU7rfgbGkxNB7AMYcVbRPycD']}],
 'metadata': None,
 'operation': 'CREATE',
 'outputs': [{'amount': '10',
   'condition': {'details': {'public_key': 'Ppwfcspe7As1YYKLomBfqGj9teB8ApscQccSeLAw8mZ',
     'type': 'ed25519-sha-256'},
    'uri': 'ni:///sha-256;AE3iOQOEBVnA5ABsVqUpU0ixcXQJMUAW5-_KwrYwkiA?fpt=ed25519-sha-256&cost=131072'},
   'public_keys': ['Ppwfcspe7As1YYKLomBfqGj9teB8ApscQccSeLAw8mZ']}],
 'version': '2.0'}

Sending the transaction:

>>> sent_token_tx = bdb.transactions.send_commit(fulfilled_token_tx)

>>> sent_token_tx == fulfilled_token_tx
True

Warning

The method .send will be deprecated in the next release of the driver, please use .send_commit, .send_sync, or .send_async instead. More info

Note

Defining recipients:

To create divisible assets, we need to specify an amount >1 together with the public keys. The way we do this is by passing a list of tuples in recipients where each tuple corresponds to an output.

For instance, instead of creating a transaction with one output containing amount=10 we could have created a transaction with two outputs each holding amount=5:

recipients=[([carly.public_key], 5), ([carly.public_key], 5)]

The reason why the addresses are contained in lists is because each output can have multiple recipients. For instance, we can create an output with amount=10 in which both Carly and Alice are recipients (of the same asset):

recipients=[([carly.public_key, alice.public_key], 10)]

Bob is the issuer:

In [32]: fulfilled_token_tx['inputs'][0]['owners_before'][0] == bob.public_key
Out[32]: True

Carly is the owner of 10 tokens:

In [33]: fulfilled_token_tx['outputs'][0]['public_keys'][0] == carly.public_key
Out[33]: True

In [34]: fulfilled_token_tx['outputs'][0]['amount'] == '10'
Out[34]: True

Now in possession of the tokens, Carly wants to ride the bicycle for two hours. To do so, she needs to send two tokens to Bob:

In [35]: output_index = 0

In [36]: output = fulfilled_token_tx['outputs'][output_index]

In [37]: transfer_input = {
   ....:     'fulfillment': output['condition']['details'],
   ....:     'fulfills': {
   ....:         'output_index': output_index,
   ....:         'transaction_id': fulfilled_token_tx['id'],
   ....:     },
   ....:     'owners_before': output['public_keys'],
   ....: }
   ....: 

In [38]: transfer_asset = {
   ....:     'id': fulfilled_token_tx['id'],
   ....: }
   ....: 

In [39]: prepared_transfer_tx = bdb.transactions.prepare(
   ....:     operation='TRANSFER',
   ....:     asset=transfer_asset,
   ....:     inputs=transfer_input,
   ....:     recipients=[([bob.public_key], 2), ([carly.public_key], 8)]
   ....: )
   ....: 

In [40]: fulfilled_transfer_tx = bdb.transactions.fulfill(
   ....:     prepared_transfer_tx, private_keys=carly.private_key)
   ....: 

Notice how Carly needs to reassign the remaining eight tokens to herself if she wants to only transfer two tokens (out of the available 10) to Bob. BigchainDB ensures that the amount being consumed in each transaction (with divisible assets) is the same as the amount being output. This ensures that no amounts are lost.

The fulfilled_transfer_tx dictionary should have two outputs, one with amount='2' and the other with amount='8':

In [41]: fulfilled_transfer_tx
Out[41]: 
{'asset': {'id': 'b9eb7377b8262136ddcb9c8409aab221513b880f1ea943ff1896410f7faf1401'},
 'id': '3257176adeb8add5d79bf75f1adafd381b3778ccbd8f8c444e6bb886f4f26e0b',
 'inputs': [{'fulfillment': 'pGSAIAXY_JAVaNY5qv0Dzc2VqTEPbK_Ock60xscSbS3Fco20gUBhmygrhPpDocHt4SZn3uX5b9PJk1nK58B5FAZDt2k8EwA8mepFuNN7kj-XDk7chGETbf5lYXI3RdrNk0sjPmQA',
   'fulfills': {'output_index': 0,
    'transaction_id': 'b9eb7377b8262136ddcb9c8409aab221513b880f1ea943ff1896410f7faf1401'},
   'owners_before': ['Ppwfcspe7As1YYKLomBfqGj9teB8ApscQccSeLAw8mZ']}],
 'metadata': None,
 'operation': 'TRANSFER',
 'outputs': [{'amount': '2',
   'condition': {'details': {'public_key': 'HFBWEKjWtdm815RZuSq4GU7rfgbGkxNB7AMYcVbRPycD',
     'type': 'ed25519-sha-256'},
    'uri': 'ni:///sha-256;NfhI1EXj6ZJ784Bm4s3LWRZx_V3IdW2rxMeRLsR7OkA?fpt=ed25519-sha-256&cost=131072'},
   'public_keys': ['HFBWEKjWtdm815RZuSq4GU7rfgbGkxNB7AMYcVbRPycD']},
  {'amount': '8',
   'condition': {'details': {'public_key': 'Ppwfcspe7As1YYKLomBfqGj9teB8ApscQccSeLAw8mZ',
     'type': 'ed25519-sha-256'},
    'uri': 'ni:///sha-256;AE3iOQOEBVnA5ABsVqUpU0ixcXQJMUAW5-_KwrYwkiA?fpt=ed25519-sha-256&cost=131072'},
   'public_keys': ['Ppwfcspe7As1YYKLomBfqGj9teB8ApscQccSeLAw8mZ']}],
 'version': '2.0'}
>>> sent_transfer_tx = bdb.transactions.send_commit(fulfilled_transfer_tx)

>>> sent_transfer_tx == fulfilled_transfer_tx
True

Warning

The method .send will be deprecated in the next release of the driver, please use .send_commit, .send_sync, or .send_async instead. More info

Querying for Assets

BigchainDB allows you to query for assets using simple text search. This search is applied to all the strings inside the asset payload and returns all the assets that match a given text search string.

Let’s create 3 assets:

from bigchaindb_driver import BigchainDB
from bigchaindb_driver.crypto import generate_keypair

bdb_root_url = 'https://example.com:9984'

bdb = BigchainDB(bdb_root_url)

alice = generate_keypair()

hello_1 = {'data': {'msg': 'Hello BigchainDB 1!'},}
hello_2 = {'data': {'msg': 'Hello BigchainDB 2!'},}
hello_3 = {'data': {'msg': 'Hello BigchainDB 3!'},}

# set the metadata to query for it in an example below
metadata={'planet': 'earth'}

prepared_creation_tx = bdb.transactions.prepare(
    operation='CREATE',
    signers=alice.public_key,
    asset=hello_1
)
fulfilled_creation_tx = bdb.transactions.fulfill(
    prepared_creation_tx, private_keys=alice.private_key)
bdb.transactions.send_commit(fulfilled_creation_tx)

prepared_creation_tx = bdb.transactions.prepare(
    operation='CREATE',
    signers=alice.public_key,
    asset=hello_2
)
fulfilled_creation_tx = bdb.transactions.fulfill(
    prepared_creation_tx, private_keys=alice.private_key)
bdb.transactions.send_commit(fulfilled_creation_tx)

prepared_creation_tx = bdb.transactions.prepare(
    operation='CREATE',
    signers=alice.public_key,
    asset=hello_3
)
fulfilled_creation_tx = bdb.transactions.fulfill(
    prepared_creation_tx, private_keys=alice.private_key)
bdb.transactions.send_commit(fulfilled_creation_tx)

Let’s perform a text search for all assets that contain the word bigchaindb:

>> bdb.assets.get(search='bigchaindb')
[
    {
        'data': {'msg': 'Hello BigchainDB 1!'},
        'id': '7582d7a81652d0230fefb47dafc360ff09b2c2566b68f05c3a004d57e7fe7610'
    },
    {
        'data': {'msg': 'Hello BigchainDB 2!'},
        'id': 'e40f4b6ac70b9c1b3b237ec13f4174384fd4d54d36dfde25520171577c49caa4'
    },
    {
        'data': {'msg': 'Hello BigchainDB 3!'},
        'id': '748f6c30daaf771c9020d84db9ad8ac4d1f7c8de7013db55e16f10ba090f7013'
    }
]

This call returns all the assets that match the string bigchaindb, sorted by text score, as well as the asset id. This is the same id of the transaction that created the asset.

It’s also possible to limit the amount of returned results using the limit argument:

>> bdb.assets.get(search='bigchaindb', limit=2)
[
    {
        'data': {'msg': 'Hello BigchainDB 1!'},
        'id': '7582d7a81652d0230fefb47dafc360ff09b2c2566b68f05c3a004d57e7fe7610'
    },
    {
        'data': {'msg': 'Hello BigchainDB 2!'},
        'id': 'e40f4b6ac70b9c1b3b237ec13f4174384fd4d54d36dfde25520171577c49caa4'
    }
]

Querying for Transactions

For this query we need to provide an asset_id and we will get back a list of transactions that use the asset with the ID asset_id.

Note

Please note that the id of an asset in BigchainDB is actually the id of the transaction which created the asset. In other words, when querying for an asset id with the operation set to CREATE, only one transaction should be expected. This transaction will be the transaction in which the asset was created, and the transaction id will be equal to the given asset id.

We will use the id of our last example Divisible Assets. Let’s try it:

>>> bdb.transactions.get(asset_id=sent_token_tx['id'])
[{'asset': {'data': {'description': 'Time share token. Each token equals one '
                                'hour of riding.',
                 'token_for': {'bicycle': {'manufacturer': 'bkfab',
                                           'serial_number': 'abcd1234'}}}},
'id': 'b2403bb6bb7f9c0af2bc2b5b03b291a378fd8499f44cade4aa14dd5419e5b7c7',
'inputs': [{'fulfillment': 'pGSAIFetX0Fz6ZUN20tJp_dWJKs0_nDDz7oOmTaToGrzzw5zgUBPJsUGHcm8R-ntQSHvK3tgoyHIvCrrNrI6lJkud81cZKWFb9XehNAvWswPWSx1_6EwFKVYV-fjlxPvExm8XZIH',
          'fulfills': None,
          'owners_before': ['6uFoT6vd38qGqo2dRMBQsSojytUadyijBH4wgZGrPhZt']}],
'metadata': None,
'operation': 'CREATE',
'outputs': [{'amount': '10',
           'condition': {'details': {'public_key': '8sKzvruHPhH3LKoGZDJE9MRzpgfFQJGZhzHTghebbFne',
                                     'type': 'ed25519-sha-256'},
                         'uri': 'ni:///sha-256;PN3UO9GztlEBitIZf5m4iYNgyexvOk6Sdjq3PANsxko?fpt=ed25519-sha-256&cost=131072'},
           'public_keys': ['8sKzvruHPhH3LKoGZDJE9MRzpgfFQJGZhzHTghebbFne']}],
'version': '2.0'},
{'asset': {'id': 'b2403bb6bb7f9c0af2bc2b5b03b291a378fd8499f44cade4aa14dd5419e5b7c7'},
'id': '3ce3a5d4d984ca92f4a34967a2c181dbe8da8d6e4477220d7869ada9379dc410',
'inputs': [{'fulfillment': 'pGSAIHTmVLbdfDFHTBx6gVr4NczRN-D1MhHltB0nn79luYlfgUCrppCotKAZoVW7nKye4I2HzGxlgwjmx47w_HxGXOFVbvCppNTLeVX4NrHYFRJlv8QKgj_ZaLctHpT6HPLLYIIG',
          'fulfills': {'output_index': 0,
                       'transaction_id': 'b2403bb6bb7f9c0af2bc2b5b03b291a378fd8499f44cade4aa14dd5419e5b7c7'},
          'owners_before': ['8sKzvruHPhH3LKoGZDJE9MRzpgfFQJGZhzHTghebbFne']}],
'metadata': None,
'operation': 'TRANSFER',
'outputs': [{'amount': '2',
           'condition': {'details': {'public_key': '6uFoT6vd38qGqo2dRMBQsSojytUadyijBH4wgZGrPhZt',
                                     'type': 'ed25519-sha-256'},
                         'uri': 'ni:///sha-256;HapGwR7oqOS3oZSICryoGJL0SfQF2LcSJe98jBKmdqo?fpt=ed25519-sha-256&cost=131072'},
           'public_keys': ['6uFoT6vd38qGqo2dRMBQsSojytUadyijBH4wgZGrPhZt']},
          {'amount': '8',
           'condition': {'details': {'public_key': '8sKzvruHPhH3LKoGZDJE9MRzpgfFQJGZhzHTghebbFne',
                                     'type': 'ed25519-sha-256'},
                         'uri': 'ni:///sha-256;PN3UO9GztlEBitIZf5m4iYNgyexvOk6Sdjq3PANsxko?fpt=ed25519-sha-256&cost=131072'},
           'public_keys': ['8sKzvruHPhH3LKoGZDJE9MRzpgfFQJGZhzHTghebbFne']}],
'version': '2.0'}]

If you were busy sharing your bicycle with the whole city you might have a really long list. So let’s limit the results and just see the CREATE transaction.

>>> bdb.transactions.get(asset_id=sent_token_tx['id'], operation='CREATE')
[{'asset': {'data': {'description': 'Time share token. Each token equals one '
                                'hour of riding.',
                 'token_for': {'bicycle': {'manufacturer': 'bkfab',
                                           'serial_number': 'abcd1234'}}}},
'id': 'b2403bb6bb7f9c0af2bc2b5b03b291a378fd8499f44cade4aa14dd5419e5b7c7',
'inputs': [{'fulfillment': 'pGSAIFetX0Fz6ZUN20tJp_dWJKs0_nDDz7oOmTaToGrzzw5zgUBPJsUGHcm8R-ntQSHvK3tgoyHIvCrrNrI6lJkud81cZKWFb9XehNAvWswPWSx1_6EwFKVYV-fjlxPvExm8XZIH',
          'fulfills': None,
          'owners_before': ['6uFoT6vd38qGqo2dRMBQsSojytUadyijBH4wgZGrPhZt']}],
'metadata': None,
'operation': 'CREATE',
'outputs': [{'amount': '10',
           'condition': {'details': {'public_key': '8sKzvruHPhH3LKoGZDJE9MRzpgfFQJGZhzHTghebbFne',
                                     'type': 'ed25519-sha-256'},
                         'uri': 'ni:///sha-256;PN3UO9GztlEBitIZf5m4iYNgyexvOk6Sdjq3PANsxko?fpt=ed25519-sha-256&cost=131072'},
           'public_keys': ['8sKzvruHPhH3LKoGZDJE9MRzpgfFQJGZhzHTghebbFne']}],
'version': '2.0'}]

Querying for Metadata

This query is similar to the asset query. The search is applied to all the strings inside the metadata and returns all the metadata that match a given text search string. The only difference is the returned id. The id of the asset query is the same id of the transaction that created the asset. Whereas the id of the metadata is the same id of the transaction where it was defined.

In the Querying for Assets example we already set the metadata for the three transactions. Let’s perform a text search for all metadata that contain the word earth:

>> bdb.metadata.get(search='earth')
[
    {
        'id': '3677de9c637e8e7848dd415058525306693d44cc3578d0ae4812e3570e9e6f9b',
        'metadata': {'planet': 'earth'}
    },
    {
        'id': 'd818741e0b9550dfe4b9ff0745c036664ab2b2e6e7d82a7508f2e79d587595ff',
        'metadata': {'planet': 'earth'}
    },
    {
        'id': '85a82b6fbceb08f79796cb0c286156aac25e92729d377220d65b14be90334c25',
        'metadata': {'planet': 'earth'}
    }
]

This call returns all the metadata that match the string earth, sorted by text score, as well as the transaction id.

It’s also possible to limit the amount of returned results using the limit argument:

>> bdb.metadata.get(search='earth', limit=2)
[
    {
        'id': '3677de9c637e8e7848dd415058525306693d44cc3578d0ae4812e3570e9e6f9b',
        'metadata': {'planet': 'earth'}
    },
    {
        'id': 'd818741e0b9550dfe4b9ff0745c036664ab2b2e6e7d82a7508f2e79d587595ff',
        'metadata': {'planet': 'earth'}
    }
]