Advanced Usage Examples¶
This page has examples of using the Python Driver for more advanced use cases such as escrow.
Todo
This is work in progress. More examples will gradually appear as issues like
are taken care of.
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.
Connect to Multiple Nodes¶
You can optionally configure multiple nodes to connect to.
In [1]: from bigchaindb_driver import BigchainDB
In [2]: first_node = 'https://first.example.com:9984'
In [3]: second_node = 'https://second.example.com:9984'
In [4]: headers = {'app_id': 'your_app_id', 'app_key': 'your_app_key'}
In [5]: bdb = BigchainDB(first_node, second_node, headers=headers)
Each node can have its specific headers in addition to headers specified for all nodes, if any.
In [6]: first_node = 'https://first.example.com:9984'
In [7]: second_node = 'https://second.example.com:9984'
In [8]: common_headers = {'app_id': 'your_app_id', 'app_key': 'your_app_key'}
In [9]: second_node_headers = {'node_header': 'node_header_value'}
In [10]: bdb = BigchainDB(first_node,
....: {'endpoint': second_node, 'headers': second_node_headers},
....: headers=common_headers)
....:
The driver switches nodes on connection failures in a round robin fashion. Connection failures are intermittent network issues like DNS failures or “refused connection” errors.
The driver switches nodes and repeats requests until the specified timeout is expired. The default timeout is 20
seconds. When timeout expires, an instance of bigchaindb_driver.exceptions.TimeoutError
is raised. Specify
timeout=None
to repeat connection errors indefinitely.
In [11]: bdb = BigchainDB(first_node, second_node, headers=headers, timeout=None)
Also, the driver takes care of the exponential backoff. If a connection error occurs, the driver ensures at least half of a second is passed before the request to the same node is repeated. The intervals increase exponentially when multiple connection errors occur in a row. The user-specified timeout is always respected.
Warning
Every node the driver communicates with is supposed to be trusted. The driver does not currently implement any light client protocols.
Create a Digital Asset¶
At a high level, a “digital asset” is something which can be represented digitally and can be assigned to a user. In BigchainDB, users are identified by their public key, and the data payload in a digital asset is represented using a generic Python dict.
In BigchainDB, digital assets can be created by doing a special kind of
transaction: a CREATE
transaction.
In [12]: from bigchaindb_driver.crypto import generate_keypair
Create a test user: alice
In [13]: alice = generate_keypair()
Define a digital asset data payload
In [14]: digital_asset_payload = {'data': {'msg': 'Hello BigchainDB!'}}
In [15]: tx = bdb.transactions.prepare(operation='CREATE',
....: signers=alice.public_key,
....: asset=digital_asset_payload)
....:
All transactions need to be signed by the user creating the transaction.
In [16]: signed_tx = bdb.transactions.fulfill(tx, private_keys=alice.private_key)
In [17]: signed_tx
Out[17]:
{'inputs': [{'owners_before': ['8oRfgrccknQMqZ3CGr2Q4sKokYJ7je7xAP9jhEjLta1n'],
'fulfills': None,
'fulfillment': 'pGSAIHPmarLGgN5kodhSw3yUKUT7wqdIYYxa2iKQSLpNYOt5gUCXYhYeelYcpsO9900s1JkDOeIkPkORrry-_9BE1d_0b9enxoCL4uE2m6fvlKfycgp6t33WIBUjBVnwD9xwZ28O'}],
'outputs': [{'public_keys': ['8oRfgrccknQMqZ3CGr2Q4sKokYJ7je7xAP9jhEjLta1n'],
'condition': {'details': {'type': 'ed25519-sha-256',
'public_key': '8oRfgrccknQMqZ3CGr2Q4sKokYJ7je7xAP9jhEjLta1n'},
'uri': 'ni:///sha-256;LphjoHX31pic9AE9Erv25H6dFGKvrcIaW-bxurM2Mbk?fpt=ed25519-sha-256&cost=131072'},
'amount': '1'}],
'operation': 'CREATE',
'metadata': None,
'asset': {'data': {'msg': 'Hello BigchainDB!'}},
'version': '2.0',
'id': 'd474a22dc21540254fa97543a0fda6dcbcd5593a3b9230030b0fa0e4e1523f31'}
Write the transaction to BigchainDB. The transaction will be stored in a backlog where it will be validated before being included in a block.
>>> sent_tx = bdb.transactions.send_commit(signed_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 transaction payload returned by the BigchainDB node is equivalent to the signed transaction payload.
>>> sent_tx == signed_tx
True
Recap: Asset Creation¶
from bigchaindb_driver import BigchainDB
from bigchaindb_driver.crypto import generate_keypair
bdb_root_url = 'https://example.com:9984' # Use YOUR BigchainDB Root URL here
bdb = BigchainDB(bdb_root_url)
alice = generate_keypair()
digital_asset_payload = {'data': {'msg': 'Hello BigchainDB!'}}
tx = bdb.transactions.prepare(operation='CREATE',
signers=alice.public_key,
asset=digital_asset_payload)
signed_tx = bdb.transactions.fulfill(tx, private_keys=alice.private_key)
sent_tx = bdb.transactions.send_commit(signed_tx)
sent_tx == signed_tx
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 invalid 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))
The new owner of the digital asset is now Alice (or more correctly, her public key):
In [18]: alice.public_key
Out[18]: '8oRfgrccknQMqZ3CGr2Q4sKokYJ7je7xAP9jhEjLta1n'
Transfer the Digital Asset¶
Now that alice
has a digital asset assigned to her, she can transfer it to
another person. Transfer transactions require an input. The input will be the
transaction id of a digital asset that was assigned to alice
, which in our
case is
In [19]: signed_tx['id']
Out[19]: 'd474a22dc21540254fa97543a0fda6dcbcd5593a3b9230030b0fa0e4e1523f31'
BigchainDB makes use of the crypto-conditions library
to cryptographically lock and unlock transactions. The locking script is
referred to as a condition
(put inside an “output”) and a corresponding
fulfillment
(put inside an “input”) unlocks the output condition of an
input_tx
.
Since a transaction can have multiple outputs each with their own
(crypto)condition, each transaction input is required to refer to the output
condition that they fulfill via fulfills['output_index']
.
In order to prepare a transfer transaction, Alice needs to provide at least three things:
inputs
– one or more fulfillments that fulfill a prior transaction’s output conditions.asset['id']
– the id of the asset being transferred.- Recipient
public_keys
– one or more public keys representing the new recipients(s).
To construct the input:
In [20]: output_index = 0
In [21]: output = signed_tx['outputs'][output_index]
In [22]: input_ = {
....: 'fulfillment': output['condition']['details'],
....: 'fulfills': {
....: 'output_index': output_index,
....: 'transaction_id': signed_tx['id'],
....: },
....: 'owners_before': output['public_keys'],
....: }
....:
The asset in a TRANSFER
transaction must be a dictionary with an id
key
denoting the asset to transfer. This asset id is either the id of the
CREATE
transaction of the asset (as it is in this case), or is the
asset['id']
property in a TRANSFER
transaction (note that this value
simply points to the id of the asset’s CREATE
transaction):
In [23]: transfer_asset_id = signed_tx['id']
In [24]: transfer_asset = {
....: 'id': transfer_asset_id,
....: }
....:
Create a second test user, bob
:
In [25]: bob = generate_keypair()
In [26]: bob.public_key
Out[26]: '4VFyqkTBJmAyKYuToChU4KE6VVGdhTgZeExtYiG5T9QN'
And prepare the transfer transaction:
In [27]: tx_transfer = bdb.transactions.prepare(
....: operation='TRANSFER',
....: inputs=input_,
....: asset=transfer_asset,
....: recipients=bob.public_key,
....: )
....:
The tx_transfer
dictionary should look something like:
In [28]: tx_transfer
Out[28]:
{'inputs': [{'owners_before': ['8oRfgrccknQMqZ3CGr2Q4sKokYJ7je7xAP9jhEjLta1n'],
'fulfills': {'transaction_id': 'd474a22dc21540254fa97543a0fda6dcbcd5593a3b9230030b0fa0e4e1523f31',
'output_index': 0},
'fulfillment': {'type': 'ed25519-sha-256',
'public_key': '8oRfgrccknQMqZ3CGr2Q4sKokYJ7je7xAP9jhEjLta1n'}}],
'outputs': [{'public_keys': ['4VFyqkTBJmAyKYuToChU4KE6VVGdhTgZeExtYiG5T9QN'],
'condition': {'details': {'type': 'ed25519-sha-256',
'public_key': '4VFyqkTBJmAyKYuToChU4KE6VVGdhTgZeExtYiG5T9QN'},
'uri': 'ni:///sha-256;0231VqKfv9JljuJRSs93cBOPxp7klMMzCML-WKGXkzI?fpt=ed25519-sha-256&cost=131072'},
'amount': '1'}],
'operation': 'TRANSFER',
'metadata': None,
'asset': {'id': 'd474a22dc21540254fa97543a0fda6dcbcd5593a3b9230030b0fa0e4e1523f31'},
'version': '2.0',
'id': None}
Notice, bob
’s public key, appearing in the above dict
.
In [29]: tx_transfer['outputs'][0]['public_keys'][0]
Out[29]: '4VFyqkTBJmAyKYuToChU4KE6VVGdhTgZeExtYiG5T9QN'
In [30]: bob.public_key
Out[30]: '4VFyqkTBJmAyKYuToChU4KE6VVGdhTgZeExtYiG5T9QN'
The transaction now needs to be fulfilled by alice
:
In [31]: signed_tx_transfer = bdb.transactions.fulfill(
....: tx_transfer,
....: private_keys=alice.private_key,
....: )
....:
If you look at the content of signed_tx_transfer
you should see the added
fulfilment uri, holding the signature:
In [32]: signed_tx_transfer
Out[32]:
{'inputs': [{'owners_before': ['8oRfgrccknQMqZ3CGr2Q4sKokYJ7je7xAP9jhEjLta1n'],
'fulfills': {'transaction_id': 'd474a22dc21540254fa97543a0fda6dcbcd5593a3b9230030b0fa0e4e1523f31',
'output_index': 0},
'fulfillment': 'pGSAIHPmarLGgN5kodhSw3yUKUT7wqdIYYxa2iKQSLpNYOt5gUC2-jPpQttCiL7TiOm5CIKABCpY_Mn0wJbsu10hyAzyxol3lCW3mz5rHs2uCmqj9H7Ngxc5jdUbbBFX2vtRmn8C'}],
'outputs': [{'public_keys': ['4VFyqkTBJmAyKYuToChU4KE6VVGdhTgZeExtYiG5T9QN'],
'condition': {'details': {'type': 'ed25519-sha-256',
'public_key': '4VFyqkTBJmAyKYuToChU4KE6VVGdhTgZeExtYiG5T9QN'},
'uri': 'ni:///sha-256;0231VqKfv9JljuJRSs93cBOPxp7klMMzCML-WKGXkzI?fpt=ed25519-sha-256&cost=131072'},
'amount': '1'}],
'operation': 'TRANSFER',
'metadata': None,
'asset': {'id': 'd474a22dc21540254fa97543a0fda6dcbcd5593a3b9230030b0fa0e4e1523f31'},
'version': '2.0',
'id': '5002358813d577bdafa356d4b5467847b3238031ce98c99aa737eae10b1797de'}
More precisely:
In [33]: signed_tx_transfer['inputs'][0]['fulfillment']
Out[33]: 'pGSAIHPmarLGgN5kodhSw3yUKUT7wqdIYYxa2iKQSLpNYOt5gUC2-jPpQttCiL7TiOm5CIKABCpY_Mn0wJbsu10hyAzyxol3lCW3mz5rHs2uCmqj9H7Ngxc5jdUbbBFX2vtRmn8C'
We have yet to send the transaction over to a BigchainDB node, as both preparing and fulfilling a transaction are done “offchain,” that is, without the need to have a connection to a BigchainDB federation.
>>> sent_tx_transfer = bdb.transactions.send_commit(signed_tx_transfer)
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
Again, as with the 'CREATE'
transaction, notice how the payload returned
by the server is equal to the signed one.
>>> sent_tx_transfer == signed_tx_transfer
True
Recap: Asset Transfer¶
output_index = 0
output = signed_tx['outputs'][output_index]
input_ = {
'fulfillment': output['condition']['details'],
'fulfills': {
'output_index': output_index,
'transaction_id': signed_tx['id'],
},
'owners_before': output['public_keys'],
}
transfer_asset_id = signed_tx['id']
transfer_asset = {
'id': transfer_asset_id,
}
bob = generate_keypair()
tx_transfer = bdb.transactions.prepare(
operation='TRANSFER',
inputs=input_,
asset=transfer_asset,
recipients=bob.public_key,
)
signed_tx_transfer = bdb.transactions.fulfill(
tx_transfer,
private_keys=alice.private_key,
)
sent_tx_transfer = bdb.transactions.send_commit(signed_tx_transfer)
Double Spends¶
BigchainDB makes sure that a user can’t transfer the same digital asset two or more times (i.e. it prevents double spends).
If we try to create another transaction with the same input as before, the transaction will be marked invalid and the validation will throw a double spend exception.
Let’s suppose that Alice tries to re-send the asset back to her “secret” account.
In [34]: alice_secret_stash = generate_keypair()
Create another transfer transaction with the same input
In [35]: tx_transfer_2 = bdb.transactions.prepare(
....: operation='TRANSFER',
....: inputs=input_,
....: asset=transfer_asset,
....: recipients=alice_secret_stash.public_key,
....: )
....:
Fulfill the transaction
In [36]: fulfilled_tx_transfer_2 = bdb.transactions.fulfill(
....: tx_transfer_2,
....: private_keys=alice.private_key,
....: )
....:
Send the transaction over to the node and an error will occur, informing the user of the double spend and specifying the matching asset_id.
>>> from bigchaindb_driver.exceptions import BigchaindbException
>>> try:
... bdb.transactions.send_commit(fulfilled_tx_transfer_2)
... except BigchaindbException as e:
... print(e.info)
{'message': 'Invalid transaction (DoubleSpend): input `20401005e1ad1745cdb3716715749475dce3c8358189af37d1a6676a52733e16` was already spent', 'status': 400}
Multiple Owners¶
Say alice
and bob
own a car together:
from bigchaindb_driver import BigchainDB
from bigchaindb_driver.crypto import generate_keypair
bdb_root_url = 'https://example.com:9984' # Use YOUR BigchainDB Root URL here
bdb = BigchainDB(bdb_root_url)
alice, bob = generate_keypair(), generate_keypair()
In [37]: car_asset = {
....: 'data': {
....: 'car': {
....: 'vin': '5YJRE11B781000196'
....: }
....: }
....: }
....:
and they agree that alice
will be the one issuing the asset. To create a
new digital asset with multiple owners, one can simply provide a
list or tuple of recipients
:
In [38]: car_creation_tx = bdb.transactions.prepare(
....: operation='CREATE',
....: signers=alice.public_key,
....: recipients=(alice.public_key, bob.public_key),
....: asset=car_asset,
....: )
....:
In [39]: signed_car_creation_tx = bdb.transactions.fulfill(
....: car_creation_tx,
....: private_keys=alice.private_key,
....: )
....:
>>> sent_car_tx = bdb.transactions.send_commit(signed_car_creation_tx)
>>> sent_car_tx == signed_car_creation_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
Let’s see how the example looks like when alice
and bob
are the issuers:
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, bob = generate_keypair(), generate_keypair()
car_asset = {
'data': {
'car': {
'vin': '5YJRE11B781000196'
}
}
}
car_creation_tx = bdb.transactions.prepare(
operation='CREATE',
signers=(alice.public_key, bob.public_key),
recipients=(alice.public_key, bob.public_key),
asset=car_asset,
)
signed_car_creation_tx = bdb.transactions.fulfill(
car_creation_tx,
private_keys=[alice.private_key, bob.private_key],
)
sent_car_tx = bdb.transactions.send_commit(signed_car_creation_tx)
One day, alice
and bob
, having figured out how to teleport themselves,
and realizing they no longer need their car, wish to transfer the ownership of
their car over to carol
:
In [40]: carol = generate_keypair()
In order to prepare the transfer transaction, alice
and bob
need the
input:
In [41]: output_index = 0
In [42]: output = signed_car_creation_tx['outputs'][output_index]
In [43]: input_ = {
....: 'fulfillment': output['condition']['details'],
....: 'fulfills': {
....: 'output_index': output_index,
....: 'transaction_id': signed_car_creation_tx['id'],
....: },
....: 'owners_before': output['public_keys'],
....: }
....:
Let’s take a moment to contemplate what this input_
is:
In [44]: input_
Out[44]:
{'fulfillment': {'type': 'threshold-sha-256',
'threshold': 2,
'subconditions': [{'type': 'ed25519-sha-256',
'public_key': '8oRfgrccknQMqZ3CGr2Q4sKokYJ7je7xAP9jhEjLta1n'},
{'type': 'ed25519-sha-256',
'public_key': '4VFyqkTBJmAyKYuToChU4KE6VVGdhTgZeExtYiG5T9QN'}]},
'fulfills': {'output_index': 0,
'transaction_id': '5e23860228b2cb0825c53d6cb9707c050bdde1fcdebffd432e636f980940ec29'},
'owners_before': ['8oRfgrccknQMqZ3CGr2Q4sKokYJ7je7xAP9jhEjLta1n',
'4VFyqkTBJmAyKYuToChU4KE6VVGdhTgZeExtYiG5T9QN']}
and the asset (because it’s a CREATE
transaction):
In [45]: transfer_asset = {
....: 'id': signed_car_creation_tx['id'],
....: }
....:
then alice
can prepare the transfer:
In [46]: car_transfer_tx = bdb.transactions.prepare(
....: operation='TRANSFER',
....: recipients=carol.public_key,
....: asset=transfer_asset,
....: inputs=input_,
....: )
....:
The asset can be transfered as soon as each of the original transaction’s
signers
fulfills the transaction, that is alice
and bob
.
To do so, simply provide a list of all private keys to the fulfill method.
In [47]: signed_car_transfer_tx = bdb.transactions.fulfill(
....: car_transfer_tx, private_keys=[alice.private_key, bob.private_key]
....: )
....:
Danger
We are currently working to support partial fulfillments, such that not all keys of all parties involved need to be supplied at once. The issue bigchaindb/bigchaindb/issues/729 addresses the current limitation. Your feedback is welcome!
Note, that if one of the private keys is missing, the fulfillment will fail. If
we omit bob
:
In [48]: from bigchaindb_driver.exceptions import MissingPrivateKeyError
In [49]: try:
....: signed_car_transfer_tx = bdb.transactions.fulfill(
....: car_transfer_tx,
....: private_keys=alice.private_key,
....: )
....: except MissingPrivateKeyError as e:
....: print(e, e.__cause__, sep='\n')
....:
A private key is missing!
Public key 4VFyqkTBJmAyKYuToChU4KE6VVGdhTgZeExtYiG5T9QN is not a pair to any of the private keys
Notice bob
’s public key in the above message:
In [50]: bob.public_key
Out[50]: '4VFyqkTBJmAyKYuToChU4KE6VVGdhTgZeExtYiG5T9QN'
And the same goes for alice
. Try it!
Sending the transaction over to a BigchainDB node:
sent_car_transfer_tx = bdb.transactions.send_commit(signed_car_transfer_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
Done!
Happy, alice
and bob
have successfully transferred the ownership of
their car to carol
, and can go on exploring the countless galaxies of the
universe using their new teleportation skills.
Crypto-Conditions (Advanced)¶
Introduction¶
Crypto-conditions provide a mechanism to describe a signed message such that multiple actors in a distributed system can all verify the same signed message and agree on whether it matches the description.
This provides a useful primitive for event-based systems that are distributed on the Internet since we can describe events in a standard deterministic manner (represented by signed messages) and therefore define generic authenticated event handlers.
Crypto-conditions are part of the Interledger protocol and the full specification can be found here.
Implementations of the crypto-conditions are available in Python, JavaScript, and Java.
Threshold Conditions¶
Threshold conditions introduce multi-signatures, m-of-n signatures, or even more complex binary Merkle trees to BigchainDB.
Setting up a generic threshold condition is a bit more elaborate than regular transaction signing but allows for flexible signing between multiple parties or groups.
The basic workflow for creating a more complex cryptocondition is the following:
- Create a transaction template that includes the public key of all (nested)
parties (
signers
) in theoutput
’spublic_keys
- Set up the threshold condition using the cryptocondition library
- Update the output’s condition and hash in the transaction template
We’ll illustrate this with a threshold condition where 2 out of 3 of the
signers
need to sign the transaction:
Todo
Stay tuned. Will soon be documented once
is taken care of.
The transaction can now be transfered by fulfilling the threshold condition.
The fulfillment involves:
- Create a transaction template that includes the public key of all (nested)
parties (
signers
) in theinputs
’sowners_before
- Parsing the threshold condition into a fulfillment using the cryptocondition library
- Signing all necessary subfulfillments and updating the
inputs
of the transaction
Todo
Stay tuned. Will soon be documented once
are taken care of.
Hash-locked Conditions¶
A hash-lock condition on an asset is like a password condition: anyone with the secret preimage (i.e. a password) can fulfill the hash-lock condition and transfer the asset to themselves.
Under the hood, fulfilling a hash-lock condition amounts to finding a string (a “preimage”) which, when hashed, results in a given value. It’s easy to verify that a given preimage hashes to the given value, but it’s computationally difficult to find a string which hashes to the given value. The only practical way to get a valid preimage is to get it from the original creator (possibly via intermediaries).
One possible use case is to distribute preimages as “digital vouchers.” The first person to redeem a voucher will get the associated asset.
A federation node can create an asset with a hash-lock condition and no
owners_after
. Anyone who can fullfill the hash-lock condition can transfer
the asset to themselves.
Todo
Stay tuned. Will soon be documented once
are taken care of.
In order to redeem the asset, one needs to create a fulfillment with the correct secret:
Todo
Stay tuned. Will soon be documented once
are taken care of.
Timeout Conditions¶
Timeout conditions allow assets to expire after a certain time. The primary use case of timeout conditions is to enable Escrow.
The condition can only be fulfilled before the expiry time. Once expired, the asset is lost and cannot be fulfilled by anyone.
Note
The timeout conditions are BigchainDB-specific and not (yet) supported by the ILP standard.
Important
Caveat: The times between nodes in a BigchainDB federation may (and will) differ slightly. In this case, the majority of the nodes will decide.
Todo
Stay tuned. Will soon be documented once
are taken care of.
The following demonstrates that the transaction invalidates once the timeout occurs:
Todo
Stay tuned. Will soon be documented once
are taken care of.
If you were fast enough, you should see the following output:
Todo
Stay tuned. Will soon be documented once
are taken care of.
Escrow¶
Escrow is a mechanism for conditional release of assets.
This means that the assets are locked up by a trusted party until an
execute
condition is presented. In order not to tie up the assets forever,
the escrow foresees an abort
condition, which is typically an expiry time.
BigchainDB and cryptoconditions provides escrow out-of-the-box, without the need of a trusted party.
A threshold condition is used to represent the escrow, since BigchainDB transactions cannot have a pending state.
The logic for switching between execute
and abort
conditions is
conceptually simple:
if timeout_condition.validate(utcnow()):
execute_fulfillment.validate(msg) == True
abort_fulfillment.validate(msg) == False
else:
execute_fulfillment.validate(msg) == False
abort_fulfillment.validate(msg) == True
The above switch can be implemented as follows using threshold cryptoconditions:
The inverted timeout is denoted by a -1 threshold, which negates the output of the fulfillment.
inverted_fulfillment.validate(msg) == not fulfillment.validate(msg)
Note
inverted thresholds are BigchainDB-specific and not supported by the ILP standard. The main reason is that it’s difficult to tell whether the fulfillment was negated, or just omitted.
The following code snippet shows how to create an escrow condition:
Todo
Stay tuned. Will soon be documented once
- https://github.com/bigchaindb/bigchaindb-driver/issues/108
- https://github.com/bigchaindb/bigchaindb-driver/issues/110
are taken care of.
Todo
Stay tuned. Will soon be documented once
- https://github.com/bigchaindb/bigchaindb-driver/issues/108
- https://github.com/bigchaindb/bigchaindb-driver/issues/110
are taken care of.
In the case of bob
, we create the abort
fulfillment:
Todo
Stay tuned. Will soon be documented once
- https://github.com/bigchaindb/bigchaindb-driver/issues/108
- https://github.com/bigchaindb/bigchaindb-driver/issues/110
are taken care of.
The following demonstrates that the transaction validation switches once the timeout occurs:
Todo
Stay tuned. Will soon be documented once
- https://github.com/bigchaindb/bigchaindb-driver/issues/108
- https://github.com/bigchaindb/bigchaindb-driver/issues/110
are taken care of.
If you execute in a timely fashion, you should see the following:
Todo
Stay tuned. Will soon be documented once
- https://github.com/bigchaindb/bigchaindb-driver/issues/108
- https://github.com/bigchaindb/bigchaindb-driver/issues/110
are taken care of.
Of course, when the execute
transaction was accepted in-time by bigchaindb,
then writing the abort
transaction after expiry will yield a
Doublespend
error.