Input

Conceptually, an input is a pointer to an output of a previous transaction. It specifies to whom an asset belonged before and it provides a proof that the conditions required to transfer the ownership of that asset (e.g., a person needs to sign) are fulfilled. In a CREATE transaction, there is no previous owner, so an input in a CREATE transaction simply specifies who the person is that is registering the object (this is usually the same as the initial owner of the asset). In a TRANSFER transaction, an input contains a proof that the user is authorized to spend (transfer or update) this particular output. In practical terms, this means that with the input, a user is stating which asset (e.g., the bike) should be transferred. He also demonstrates that he or she is authorized to do the transfer of that asset.

Output

A transaction output specifies the conditions that need to be fulfilled to change the ownership of a specific asset. For instance: to transfer a bicycle, a person needs to sign the transaction with his or her private key. This also implicitly contains the information that the public key associated with that private key is the current owner of the asset.

The transaction can also have multiple outputs. These are called divisible assets. The output can also contain complex conditions (e.g., multiple signatures of multiple people) to acquire ownership.

Metadata

The metadata field allows users to add additional data to a transaction. This can be any type of data, like the age of a bicycle or the kilometers driven [11]. The good thing about the metadata is that it can be updated with every transaction. In contrast to the data in the asset field, the metadata field allows to add new information to every transaction.

Transaction ID

The ID of a transaction is a unique hash that identifies a transaction. It contains all the information about the transaction in a hashed way.

Getting Started

Begin by creating an object of class BigchainDB:

In [1]: frombigchaindb_driverimportBigchainDB

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 diet 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={

...: 1 data':{

...: 1 bicycle':{

...: 1serial_number':'abcdl234',

...: 'manufacturer':'bkfab',

Suppose a bike belongs to Alice and that it will be transferred to Bob. In general, 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={'planetearth'}

Asset Creation

Create the digital asset. First, prepare the transaction:

In [10]: prepared_creation_tx=bdb.transactions.prepare(

....: operation=1 CREATE 1,

....: 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': 'abcdl234'}}},

'id': None,

'inputs': [{'fulfillment': {'public_key':

' 7rr59L64LwwMKr8dtieotdugkl3oHkosFFoTuXCj zz6 ',

'type': 'ed255l9-sha-256'},

'fulfills': None,

'owners_before': ['7rr59L64LvvwMKr8dtieotdugkl3oHkosFFoTuXCj

zz6 ' ] }] ,

'metadata': {'planet': 'earth'},

'operation': 'CREATE',

'outputs': [{'amount': '1',

'condition': {'details': {'public_key': '7rr59L64LwwMKr8

dtieotdugkl3oHkosFFoTuXCjzz6' ,

'type': 'ed255l9-sha-256'},

'uri' : 'ni:///sha-56;e2COOfzLhNG_nLwWVmZOyGbIQ61qDCduYZy7HKPr2 3c?fpt=ed255l9-sha-256&cost=13l072'},

'public_keys': ['7rr59L64LwwMKr8dtieotdugkl3oHkosFFoTuXCj

ZZ6'1 }] ,

'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': 'abcdl234'}}},

'id': 'bfe679e84f528410270fe67d309fl9d03afe09970650140621d

aedfe6f546598',

1 inputs 1: [{1 fulfillment1: 1pGSAIGXrEQNtYgyzOBswGHnoWgbU

WFWVE89Kez 25zti91PTzgUDY8sy8E9FtHw09-nab89wBspemhBCshbbRR JqLlqilTQ7Hb JZYMfr8_mawfTDre3lpJEgLSrqFU-clmJjkrwUO1,

  • 1 fulfills 1: None,
  • 1owners_before1: [17rr59L64LwwMKr8dtieotdugkl3oHkosFFoTuXCj zz6 1 ] }] ,

'metadata': {'planet': 'earth'},

'operation' : 'CREATE',

'outputs': [{'amount': '1',

'condition': {'details': {'public_key':

' 7rr59L64LwwMKr8dtieotdugkl3oHkosFFoTuXCj zz6 ',

'type': 'ed255l9-sha-256'},

'uri' : 'ni:///sha-2 56;e2C00f zLhNG_nLwWVmZOyGbIQ61qDCduYZy7HK

Pr23c?fpt=ed25519-sha-256&cost=131072'},

'public_keys': ['7rr59L64LwwMKr8dtieotdugkl3oHkosFFo

Tuxcjzz6' ] }] ,

'version': '2.0'}

And sent over to a BigchainDB node:

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

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

>>>sent_creation_tx==fulf illed_creation_tx True

Notice the transaction id:

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

In [15] : txid

Out [15] : 'bfe679e84f528410270fe67d3 0 9fl9d03afe09970650140621

daedfe6f546598'

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 wanted to get a new bicycle [12].

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={

....: 'id1: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 1],

. . . . : 'fulfills' : {

....: 1output_index1:output_index,

....: 1transaction_id1: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': 'bfe679e84f5284l0270fe67d309fI9d03afe09

97065014062ldaedfe6f546598'} ,

'id': 'fb745cf6b645f5a20a82a4ladef835ce66913cc6ldd0lb2830085d

7776855520',

'inputs': [{'fulfillment': 'pGSAIGXrEQNtYgyzOBswGHno

WgbUWFWVE 89Kez25zti9lPTzgUBuHqMbJO 6C2vm9aBcaz90 CBXpg PZ-FQPrFLeGURN77an7Ej YXGvLGeUhf-fTB9uZvpYs6utzhZPt 24rdSJJXQC',

'fulfills': {'output_index': 0,

'transaction_id1:

'bfe679e84f528410270fe67d309fl9d03afe09970 650140621 daedfe6f546598 '},

1owners_before': ['7rr59L64LwwMKr8dtieotdugkl3oHkos

FFoTuXCj ZZ6'1 }] ,

'metadata': None,

'operation': 'TRANSFER',

'outputs': [{'amount': '1',

'condition': {'details': {'public_key': 'SRaeQAZEEQMFCLBEDr Ktk5p Lue4SuVkdw9Xb55ucpvQ6',

'type': 'ed255l9-sha-2561},

'uri': 'ni:///sha-256;UKI3FbYGLQhOeu3QkZNuoWrjxGugzG4q7LxnhV qevHU? fpt=ed255l9-sha-256&cost=13l072' },

1public_keys1: ['5RaeQAZEEQMFCLBEDrKtk5pLue4SuVkdw9Xb55

ucpvQ6']}],

'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

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 (e.g., fulfilled_transfer_tx|), you could obtain the asset id to transfer from the asset[‘id’] property:

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

 
Source
< Prev   CONTENTS   Source   Next >