diff --git a/docs/source/python-server-api-examples.md b/docs/source/python-server-api-examples.md index 3275046f..9c2f7a16 100644 --- a/docs/source/python-server-api-examples.md +++ b/docs/source/python-server-api-examples.md @@ -356,13 +356,129 @@ tx_multisig_retrieved = b.get_transaction(tx_multisig_transfer_signed['id']) ## Multiple Inputs and Outputs +With BigchainDB it is possible to send multiple assets to someone in a single transfer. + +The transaction will create a `fulfillment` - `condition` pair for each input, which can be refered to by `fid` and `cid` respectively. ![BigchainDB transactions connecting multiple fulfillments with multiple conditions](./_static/tx_multi_condition_multi_fulfillment_v1.png) ```python -``` +# Create some assets for bulk transfer +for i in range(3): + tx_mimo_asset = b.create_transaction(b.me, testuser1_pub, None, 'CREATE') + tx_mimo_asset_signed = b.sign_transaction(tx_mimo_asset, b.me_private) + b.write_transaction(tx_mimo_asset_signed) -```python +# Wait until they appear on the bigchain and get the inputs +owned_mimo_inputs = b.get_owned_ids(testuser1_pub) + +# Check the number of assets +print(len(owned_mimo_inputs)) + +# Create a TRANSFER transaction with all the assets +tx_mimo = b.create_transaction(testuser1_pub, testuser2_pub, owned_mimo_inputs, 'TRANSFER') +tx_mimo_signed = b.sign_transaction(tx_mimo, testuser1_priv) + +# Write the transaction +b.write_transaction(tx_mimo_signed) + +# Check if the transaction is already in the bigchain +tx_mimo_retrieved = b.get_transaction(tx_mimo_signed['id']) + +{ + "id":"8b63689691a3c2e8faba89c6efe3caa0661f862c14d88d1e63ebd65d49484de2", + "transaction":{ + "conditions":[ + { + "cid":0, + "condition":{ + "details":{ + "bitmask":32, + "public_key":"qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor", + "signature":null, + "type":"fulfillment", + "type_id":4 + }, + "uri":"cc:4:20:2AXg2JJ7mQ8o2Q9-hafP-XmFh3YR7I2_Sz55AubfxIc:96" + }, + "new_owners":[ + "qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor" + ] + }, + { + "cid":1, + "condition":{ + "details":{ + "bitmask":32, + "public_key":"qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor", + "signature":null, + "type":"fulfillment", + "type_id":4 + }, + "uri":"cc:4:20:2AXg2JJ7mQ8o2Q9-hafP-XmFh3YR7I2_Sz55AubfxIc:96" + }, + "new_owners":[ + "qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor" + ] + }, + { + "cid":2, + "condition":{ + "details":{ + "bitmask":32, + "public_key":"qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor", + "signature":null, + "type":"fulfillment", + "type_id":4 + }, + "uri":"cc:4:20:2AXg2JJ7mQ8o2Q9-hafP-XmFh3YR7I2_Sz55AubfxIc:96" + }, + "new_owners":[ + "qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor" + ] + } + ], + "data":null, + "fulfillments":[ + { + "current_owners":[ + "BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs" + ], + "fid":0, + "fulfillment":"cf:4:sTzo4fvm8U8XrlXcgcGkNZgkfS9QHg2grgrJiX-c0LT_a83V0wbNRVbmb0eOy6tLyRw0kW1FtsN29yTcTAILX5-fyBITrPUqPzIzF85l8yIAMSjVfH-h6YNcUQBj0o4B", + "input":{ + "cid":0, + "txid":"9a99f3c82aea23fb344acb1505926365e2c6b722761c4be6ab8916702c94c024" + } + }, + { + "current_owners":[ + "BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs" + ], + "fid":1, + "fulfillment":"cf:4:sTzo4fvm8U8XrlXcgcGkNZgkfS9QHg2grgrJiX-c0LSJe3B_yjgXd1JHPBJhAdywCzR_ykEezi3bPNucGHl5mgPvpsLpHWrdIvZa3arFD91AepXILaNCF0y8cxIBOyEE", + "input":{ + "cid":0, + "txid":"783014b92f35da0c2526e1db6f81452c61853d29eda50d057fd043d507d03ef9" + } + }, + { + "current_owners":[ + "BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs" + ], + "fid":2, + "fulfillment":"cf:4:sTzo4fvm8U8XrlXcgcGkNZgkfS9QHg2grgrJiX-c0LReUQd-vDMseuVi03qY5Fxetv81fYpy3z1ncHIGc2bX7R69aS-yH5_deV9qaKjc1ZZFN5xXsB9WFpQkf9VQ-T8B", + "input":{ + "cid":0, + "txid":"9ab6151334b06f3f3aab282597ee8a7c12b9d7a0c43f356713f7ef9663375f50" + } + } + ], + "operation":"TRANSFER", + "timestamp":"1461049149.568927" + }, + "version":1 +} ``` @@ -601,6 +717,4 @@ b.write_transaction(threshold_tx_transfer) }, "version":1 } - - ``` diff --git a/tests/db/test_bigchain_api.py b/tests/db/test_bigchain_api.py index 5291f7ac..71ad97a2 100644 --- a/tests/db/test_bigchain_api.py +++ b/tests/db/test_bigchain_api.py @@ -930,7 +930,6 @@ class TestMultipleInputs(object): user3_sk, user3_vk = crypto.generate_key_pair() user4_sk, user4_vk = crypto.generate_key_pair() - # create input to spend tx = b.create_transaction(b.me, [user_vk, user2_vk], None, 'CREATE') tx_signed = b.sign_transaction(tx, b.me_private) diff --git a/tests/doc/run_doc_python_server_api_examples.py b/tests/doc/run_doc_python_server_api_examples.py index 79552911..3500d6ab 100644 --- a/tests/doc/run_doc_python_server_api_examples.py +++ b/tests/doc/run_doc_python_server_api_examples.py @@ -1,15 +1,17 @@ -import copy import json from time import sleep -from cryptoconditions import Ed25519Fulfillment, ThresholdSha256Fulfillment -from cryptoconditions.fulfillment import Fulfillment +import cryptoconditions as cc from bigchaindb import Bigchain, util, crypto, exceptions b = Bigchain() +""" +Create a Digital Asset +""" + # create a test user testuser1_priv, testuser1_pub = crypto.generate_key_pair() @@ -29,6 +31,10 @@ b.write_transaction(tx_signed) sleep(10) +""" +Read the Creation Transaction from the DB +""" + tx_retrieved = b.get_transaction(tx_signed['id']) print(json.dumps(tx_retrieved, sort_keys=True, indent=4, separators=(',', ':'))) @@ -37,6 +43,11 @@ print(testuser1_pub) print(b.me) print(tx_retrieved['id']) + +""" +Transfer the Digital Asset +""" + # create a second testuser testuser2_priv, testuser2_pub = crypto.generate_key_pair() @@ -59,6 +70,9 @@ sleep(10) tx_transfer_retrieved = b.get_transaction(tx_transfer_signed['id']) print(json.dumps(tx_transfer_retrieved, sort_keys=True, indent=4, separators=(',', ':'))) +""" +Double Spends +""" # create another transfer transaction with the same input tx_transfer2 = b.create_transaction(testuser1_pub, testuser2_pub, tx_retrieved_id, 'TRANSFER') @@ -72,6 +86,10 @@ try: except exceptions.DoubleSpend as e: print(e) +""" +Multiple Owners +""" + # Create a new asset and assign it to multiple owners tx_multisig = b.create_transaction(b.me, [testuser1_pub, testuser2_pub], None, 'CREATE') @@ -103,6 +121,33 @@ tx_multisig_retrieved = b.get_transaction(tx_multisig_transfer_signed['id']) print(json.dumps(tx_multisig_transfer_signed, sort_keys=True, indent=4, separators=(',', ':'))) +""" +Multiple Inputs and Outputs +""" +for i in range(3): + tx_mimo_asset = b.create_transaction(b.me, testuser1_pub, None, 'CREATE') + tx_mimo_asset_signed = b.sign_transaction(tx_mimo_asset, b.me_private) + b.write_transaction(tx_mimo_asset_signed) + +sleep(10) + +# get inputs +owned_mimo_inputs = b.get_owned_ids(testuser1_pub) +print(len(owned_mimo_inputs)) + +# create a transaction +tx_mimo = b.create_transaction(testuser1_pub, testuser2_pub, owned_mimo_inputs, 'TRANSFER') +tx_mimo_signed = b.sign_transaction(tx_mimo, testuser1_priv) + +# write the transaction +b.write_transaction(tx_mimo_signed) + +print(json.dumps(tx_mimo_signed, sort_keys=True, indent=4, separators=(',', ':'))) + +""" +Threshold Conditions +""" + # create some new testusers thresholduser1_priv, thresholduser1_pub = crypto.generate_key_pair() thresholduser2_priv, thresholduser2_pub = crypto.generate_key_pair() @@ -116,10 +161,10 @@ threshold_tx = b.create_transaction(testuser2_pub, [thresholduser1_pub, threshol tx_retrieved_id, 'TRANSFER') # create a 2-out-of-3 Threshold Cryptocondition -threshold_condition = ThresholdSha256Fulfillment(threshold=2) -threshold_condition.add_subfulfillment(Ed25519Fulfillment(public_key=thresholduser1_pub)) -threshold_condition.add_subfulfillment(Ed25519Fulfillment(public_key=thresholduser2_pub)) -threshold_condition.add_subfulfillment(Ed25519Fulfillment(public_key=thresholduser3_pub)) +threshold_condition = cc.ThresholdSha256Fulfillment(threshold=2) +threshold_condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=thresholduser1_pub)) +threshold_condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=thresholduser2_pub)) +threshold_condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=thresholduser3_pub)) # update the condition in the newly created transaction threshold_tx['transaction']['conditions'][0]['condition'] = { @@ -152,7 +197,7 @@ threshold_tx_transfer = b.create_transaction([thresholduser1_pub, thresholduser2 thresholduser4_pub, tx_retrieved_id, 'TRANSFER') # parse the threshold cryptocondition -threshold_fulfillment = Fulfillment.from_json(threshold_tx['transaction']['conditions'][0]['condition']['details']) +threshold_fulfillment = cc.Fulfillment.from_json(threshold_tx['transaction']['conditions'][0]['condition']['details']) subfulfillment1 = threshold_fulfillment.get_subcondition_from_vk(thresholduser1_pub)[0] subfulfillment2 = threshold_fulfillment.get_subcondition_from_vk(thresholduser2_pub)[0]