From 6d99427bc7bdbda6cdff517a3b4c61ddd8aa60c8 Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 21 Apr 2016 18:59:48 +0200 Subject: [PATCH 1/3] hashlocked conditions + tests + docs --- bigchaindb/util.py | 33 +- docs/source/python-server-api-examples.md | 146 ++++++ tests/db/test_bigchain_api.py | 130 ++++++ .../doc/run_doc_python_server_api_examples.py | 429 ++++++++++-------- 4 files changed, 540 insertions(+), 198 deletions(-) diff --git a/bigchaindb/util.py b/bigchaindb/util.py index e17874ac..8b03444d 100644 --- a/bigchaindb/util.py +++ b/bigchaindb/util.py @@ -202,15 +202,20 @@ def create_tx(current_owners, new_owners, inputs, operation, payload=None): }, } """ - current_owners = current_owners if isinstance(current_owners, list) else [current_owners] - new_owners = new_owners if isinstance(new_owners, list) else [new_owners] - inputs = inputs if isinstance(inputs, list) else [inputs] + # validate arguments (owners and inputs should be lists or None) - # validate arguments (owners and inputs should be lists) + # The None case appears on fulfilling a hashlock + if current_owners is None: + current_owners = [] if not isinstance(current_owners, list): current_owners = [current_owners] + + # The None case appears on assigning a hashlock + if new_owners is None: + new_owners = [] if not isinstance(new_owners, list): new_owners = [new_owners] + if not isinstance(inputs, list): inputs = [inputs] @@ -250,20 +255,24 @@ def create_tx(current_owners, new_owners, inputs, operation, payload=None): # handle outputs conditions = [] for fulfillment in fulfillments: + condition = None if len(new_owners) > 1: condition = cc.ThresholdSha256Fulfillment(threshold=len(new_owners)) for new_owner in new_owners: condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=new_owner)) elif len(new_owners) == 1: condition = cc.Ed25519Fulfillment(public_key=new_owners[0]) - conditions.append({ - 'new_owners': new_owners, - 'condition': { - 'details': json.loads(condition.serialize_json()), - 'uri': condition.condition.serialize_uri() - }, - 'cid': fulfillment['fid'] - }) + + # The None case appears on assigning a hashlock + if condition: + conditions.append({ + 'new_owners': new_owners, + 'condition': { + 'details': json.loads(condition.serialize_json()), + 'uri': condition.condition.serialize_uri() + }, + 'cid': fulfillment['fid'] + }) tx = { 'fulfillments': fulfillments, diff --git a/docs/source/python-server-api-examples.md b/docs/source/python-server-api-examples.md index 15ee08f7..4bbfe6d1 100644 --- a/docs/source/python-server-api-examples.md +++ b/docs/source/python-server-api-examples.md @@ -746,3 +746,149 @@ threshold_tx_transfer "version":1 } ``` + + +### Hash-locked Conditions + +By creating a hash of a difficult-to-guess 256-bit random or pseudo-random integer it is possible to create a condition which the creator can trivially fulfill by publishing the random value. However, for anyone else, the condition is cryptographically hard to fulfill, because they would have to find a preimage for the given condition hash. + +One possible usecase might be to redeem a digital voucher when given a secret (voucher code). + +```python +# Create a hash-locked asset without any new_owners +hashlock_tx = b.create_transaction(b.me, None, None, 'CREATE') + +# Define a secret that will be hashed - fulfillments need to guess the secret +secret = b'much secret! wow!' +first_tx_condition = cc.PreimageSha256Fulfillment(preimage=secret) + +# The conditions list is empty, so we need to append a new condition +hashlock_tx['transaction']['conditions'].append({ + 'condition': { + 'details': json.loads(first_tx_condition.serialize_json()), + 'uri': first_tx_condition.condition.serialize_uri() + }, + 'cid': 0, + 'new_owners': None +}) + +# Conditions have been updated, so hash needs updating +hashlock_tx['id'] = util.get_hash_data(hashlock_tx) + +# The asset needs to be signed by the current_owner +hashlock_tx_signed = b.sign_transaction(hashlock_tx, b.me_private) + +# Some validations +assert b.validate_transaction(hashlock_tx_signed) == hashlock_tx_signed +assert b.is_valid_transaction(hashlock_tx_signed) == hashlock_tx_signed + +b.write_transaction(hashlock_tx_signed) +hashlock_tx_signed +``` + +```python +{ + "assignee":"FmLm6MxCABc8TsiZKdeYaZKo5yZWMM6Vty7Q1B6EgcP2", + "id":"604c520244b7ff63604527baf269e0cbfb887122f503703120fd347d6b99a237", + "transaction":{ + "conditions":[ + { + "cid":0, + "condition":{ + "details":{ + "bitmask":3, + "preimage":"much secret! wow!", + "type":"fulfillment", + "type_id":0 + }, + "uri":"cc:0:3:nsW2IiYgk9EUtsg4uBe3pBnOgRoAEX2IIsPgjqZz47U:17" + }, + "new_owners":None + } + ], + "data":None, + "fulfillments":[ + { + "current_owners":[ + "FmLm6MxCABc8TsiZKdeYaZKo5yZWMM6Vty7Q1B6EgcP2" + ], + "fid":0, + "fulfillment":"cf:4:21-D-LfNhIQhvY5914ArFTUGpgPKc7EVC1ZtJqqOTHGx1p9FuRr9tRfkbdqtX2MZWh7sRVUmMnwp7I1-xZbCnCkeADf69IwDHbZvNS6aTr1CpekREsV9ZG8m_wjlZiUN", + "input":None + } + ], + "operation":"CREATE", + "timestamp":"1461250387.910102" + }, + "version":1 +} +``` + +In order to redeem the asset, one needs to create a fulfillment the correct secret as a preimage: + +```python +hashlockuser_priv, hashlockuser_pub = crypto.generate_key_pair() + +# create hashlock fulfillment tx +hashlock_fulfill_tx = b.create_transaction(None, hashlockuser_pub, {'txid': hashlock_tx['id'], 'cid': 0}, 'TRANSFER') + +# provide a wrong secret +hashlock_fulfill_tx_fulfillment = cc.PreimageSha256Fulfillment(preimage=b'') +hashlock_fulfill_tx['transaction']['fulfillments'][0]['fulfillment'] = \ + hashlock_fulfill_tx_fulfillment.serialize_uri() + +assert b.is_valid_transaction(hashlock_fulfill_tx) == False + +# provide the right secret +hashlock_fulfill_tx_fulfillment = cc.PreimageSha256Fulfillment(preimage=secret) +hashlock_fulfill_tx['transaction']['fulfillments'][0]['fulfillment'] = \ + hashlock_fulfill_tx_fulfillment.serialize_uri() + +assert b.validate_transaction(hashlock_fulfill_tx) == hashlock_fulfill_tx +assert b.is_valid_transaction(hashlock_fulfill_tx) == hashlock_fulfill_tx + +b.write_transaction(hashlock_fulfill_tx) +hashlock_fulfill_tx +``` + +```python +{ + "assignee":"FmLm6MxCABc8TsiZKdeYaZKo5yZWMM6Vty7Q1B6EgcP2", + "id":"fe6871bf3ca62eb61c52c5555cec2e07af51df817723f0cb76e5cf6248f449d2", + "transaction":{ + "conditions":[ + { + "cid":0, + "condition":{ + "details":{ + "bitmask":32, + "public_key":"EiqCKxnBCmmNb83qyGch48tULK9RLaEt4xFA43UVCVDb", + "signature":None, + "type":"fulfillment", + "type_id":4 + }, + "uri":"cc:4:20:y9884Md2YI_wdnGSTJGhwvFaNsKLe8sqwimqk-2JLSI:96" + }, + "new_owners":[ + "EiqCKxnBCmmNb83qyGch48tULK9RLaEt4xFA43UVCVDb" + ] + } + ], + "data":None, + "fulfillments":[ + { + "current_owners":[], + "fid":0, + "fulfillment":"cf:0:bXVjaCBzZWNyZXQhIHdvdyE", + "input":{ + "cid":0, + "txid":"604c520244b7ff63604527baf269e0cbfb887122f503703120fd347d6b99a237" + } + } + ], + "operation":"TRANSFER", + "timestamp":"1461250397.944510" + }, + "version":1 +} +``` \ No newline at end of file diff --git a/tests/db/test_bigchain_api.py b/tests/db/test_bigchain_api.py index 71ad97a2..07479944 100644 --- a/tests/db/test_bigchain_api.py +++ b/tests/db/test_bigchain_api.py @@ -1544,6 +1544,136 @@ class TestCryptoconditions(object): assert b.verify_signature(tx_transfer_signed) is True + def test_create_asset_with_hashlock_condition(self, b): + hashlock_tx = b.create_transaction(b.me, None, None, 'CREATE') + + secret = b'much secret! wow!' + first_tx_condition = cc.PreimageSha256Fulfillment(preimage=secret) + + hashlock_tx['transaction']['conditions'].append({ + 'condition': { + 'details': json.loads(first_tx_condition.serialize_json()), + 'uri': first_tx_condition.condition.serialize_uri() + }, + 'cid': 0, + 'new_owners': None + }) + # conditions have been updated, so hash needs updating + hashlock_tx['id'] = util.get_hash_data(hashlock_tx) + + hashlock_tx_signed = b.sign_transaction(hashlock_tx, b.me_private) + + assert b.validate_transaction(hashlock_tx_signed) == hashlock_tx_signed + assert b.is_valid_transaction(hashlock_tx_signed) == hashlock_tx_signed + + b.write_transaction(hashlock_tx_signed) + + # create and write block to bigchain + block = b.create_block([hashlock_tx_signed]) + b.write_block(block, durability='hard') + + @pytest.mark.usefixtures('inputs') + def test_transfer_asset_with_hashlock_condition(self, b, user_vk, user_sk): + first_input_tx = b.get_owned_ids(user_vk).pop() + + hashlock_tx = b.create_transaction(user_vk, None, first_input_tx, 'TRANSFER') + + secret = b'much secret! wow!' + first_tx_condition = cc.PreimageSha256Fulfillment(preimage=secret) + + hashlock_tx['transaction']['conditions'].append({ + 'condition': { + 'details': json.loads(first_tx_condition.serialize_json()), + 'uri': first_tx_condition.condition.serialize_uri() + }, + 'cid': 0, + 'new_owners': None + }) + # conditions have been updated, so hash needs updating + hashlock_tx['id'] = util.get_hash_data(hashlock_tx) + + hashlock_tx_signed = b.sign_transaction(hashlock_tx, user_sk) + + assert b.validate_transaction(hashlock_tx_signed) == hashlock_tx_signed + assert b.is_valid_transaction(hashlock_tx_signed) == hashlock_tx_signed + assert len(b.get_owned_ids(user_vk)) == 1 + + b.write_transaction(hashlock_tx_signed) + + # create and write block to bigchain + block = b.create_block([hashlock_tx_signed]) + b.write_block(block, durability='hard') + + assert len(b.get_owned_ids(user_vk)) == 0 + + def test_create_and_fulfill_asset_with_hashlock_condition(self, b, user_vk): + hashlock_tx = b.create_transaction(b.me, None, None, 'CREATE') + + secret = b'much secret! wow!' + first_tx_condition = cc.PreimageSha256Fulfillment(preimage=secret) + + hashlock_tx['transaction']['conditions'].append({ + 'condition': { + 'details': json.loads(first_tx_condition.serialize_json()), + 'uri': first_tx_condition.condition.serialize_uri() + }, + 'cid': 0, + 'new_owners': None + }) + # conditions have been updated, so hash needs updating + hashlock_tx['id'] = util.get_hash_data(hashlock_tx) + + hashlock_tx_signed = b.sign_transaction(hashlock_tx, b.me_private) + + assert b.validate_transaction(hashlock_tx_signed) == hashlock_tx_signed + assert b.is_valid_transaction(hashlock_tx_signed) == hashlock_tx_signed + + b.write_transaction(hashlock_tx_signed) + + # create and write block to bigchain + block = b.create_block([hashlock_tx_signed]) + b.write_block(block, durability='hard') + + assert len(b.get_owned_ids(b.me)) == 0 + + # create hashlock fulfillment tx + hashlock_fulfill_tx = b.create_transaction(None, user_vk, {'txid': hashlock_tx['id'], 'cid': 0}, 'TRANSFER') + + hashlock_fulfill_tx_fulfillment = cc.PreimageSha256Fulfillment(preimage=b'') + hashlock_fulfill_tx['transaction']['fulfillments'][0]['fulfillment'] = \ + hashlock_fulfill_tx_fulfillment.serialize_uri() + + with pytest.raises(exceptions.InvalidSignature): + b.validate_transaction(hashlock_fulfill_tx) + assert b.is_valid_transaction(hashlock_fulfill_tx) == False + + hashlock_fulfill_tx_fulfillment = cc.PreimageSha256Fulfillment(preimage=secret) + hashlock_fulfill_tx['transaction']['fulfillments'][0]['fulfillment'] = \ + hashlock_fulfill_tx_fulfillment.serialize_uri() + + assert b.validate_transaction(hashlock_fulfill_tx) == hashlock_fulfill_tx + assert b.is_valid_transaction(hashlock_fulfill_tx) == hashlock_fulfill_tx + + b.write_transaction(hashlock_fulfill_tx) + + # create and write block to bigchain + block = b.create_block([hashlock_fulfill_tx]) + b.write_block(block, durability='hard') + + assert len(b.get_owned_ids(b.me)) == 0 + assert len(b.get_owned_ids(user_vk)) == 1 + + # try doublespending + user2_sk, user2_vk = crypto.generate_key_pair() + hashlock_doublespend_tx = b.create_transaction(None, user2_vk, {'txid': hashlock_tx['id'], 'cid': 0}, 'TRANSFER') + + hashlock_doublespend_tx_fulfillment = cc.PreimageSha256Fulfillment(preimage=secret) + hashlock_doublespend_tx['transaction']['fulfillments'][0]['fulfillment'] = \ + hashlock_doublespend_tx_fulfillment.serialize_uri() + + with pytest.raises(exceptions.DoubleSpend): + b.validate_transaction(hashlock_doublespend_tx) + def test_get_subcondition_from_vk(self, b, user_sk, user_vk): user2_sk, user2_vk = crypto.generate_key_pair() user3_sk, user3_vk = crypto.generate_key_pair() diff --git a/tests/doc/run_doc_python_server_api_examples.py b/tests/doc/run_doc_python_server_api_examples.py index 3500d6ab..355cc957 100644 --- a/tests/doc/run_doc_python_server_api_examples.py +++ b/tests/doc/run_doc_python_server_api_examples.py @@ -29,208 +29,265 @@ tx_signed = b.sign_transaction(tx, b.me_private) # included in a block, and written to the bigchain b.write_transaction(tx_signed) -sleep(10) +# 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=(',', ':'))) +# +# 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() +# +# # retrieve the transaction with condition id +# tx_retrieved_id = b.get_owned_ids(testuser1_pub).pop() +# print(json.dumps(tx_retrieved_id, sort_keys=True, indent=4, separators=(',', ':'))) +# +# # create a transfer transaction +# tx_transfer = b.create_transaction(testuser1_pub, testuser2_pub, tx_retrieved_id, 'TRANSFER') +# +# # sign the transaction +# tx_transfer_signed = b.sign_transaction(tx_transfer, testuser1_priv) +# +# # write the transaction +# b.write_transaction(tx_transfer_signed) +# +# sleep(10) +# +# # check if the transaction is already in the bigchain +# 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') +# +# # sign the transaction +# tx_transfer_signed2 = b.sign_transaction(tx_transfer2, testuser1_priv) +# +# # check if the transaction is valid +# try: +# b.validate_transaction(tx_transfer_signed2) +# 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') +# +# # Have the federation sign the transaction +# tx_multisig_signed = b.sign_transaction(tx_multisig, b.me_private) +# b.write_transaction(tx_multisig_signed) +# +# # wait a few seconds for the asset to appear on the blockchain +# sleep(10) +# +# # retrieve the transaction +# tx_multisig_retrieved = b.get_transaction(tx_multisig_signed['id']) +# +# print(json.dumps(tx_multisig_retrieved, sort_keys=True, indent=4, separators=(',', ':'))) +# +# testuser3_priv, testuser3_pub = crypto.generate_key_pair() +# +# tx_multisig_retrieved_id = b.get_owned_ids(testuser2_pub).pop() +# tx_multisig_transfer = b.create_transaction([testuser1_pub, testuser2_pub], testuser3_pub, tx_multisig_retrieved_id, 'TRANSFER') +# tx_multisig_transfer_signed = b.sign_transaction(tx_multisig_transfer, [testuser1_priv, testuser2_priv]) +# +# b.write_transaction(tx_multisig_transfer_signed) +# +# # wait a few seconds for the asset to appear on the blockchain +# sleep(10) +# +# # retrieve the transaction +# 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() +# thresholduser3_priv, thresholduser3_pub = crypto.generate_key_pair() +# +# # retrieve the last transaction of testuser2 +# tx_retrieved_id = b.get_owned_ids(testuser2_pub).pop() +# +# # create a base template for a 1-input/3-output transaction +# threshold_tx = b.create_transaction(testuser2_pub, [thresholduser1_pub, thresholduser2_pub, thresholduser3_pub], +# tx_retrieved_id, 'TRANSFER') +# +# # create a 2-out-of-3 Threshold Cryptocondition +# 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'] = { +# 'details': json.loads(threshold_condition.serialize_json()), +# 'uri': threshold_condition.condition.serialize_uri() +# } +# +# # conditions have been updated, so hash needs updating +# threshold_tx['id'] = util.get_hash_data(threshold_tx) +# +# # sign the transaction +# threshold_tx_signed = b.sign_transaction(threshold_tx, testuser2_priv) +# +# # write the transaction +# b.write_transaction(threshold_tx_signed) +# +# sleep(10) +# +# # check if the transaction is already in the bigchain +# tx_threshold_retrieved = b.get_transaction(threshold_tx_signed['id']) +# print(json.dumps(tx_threshold_retrieved, sort_keys=True, indent=4, separators=(',', ':'))) +# +# thresholduser4_priv, thresholduser4_pub = crypto.generate_key_pair() +# +# # retrieve the last transaction of thresholduser1_pub +# tx_retrieved_id = b.get_owned_ids(thresholduser1_pub).pop() +# +# # create a base template for a 2-input/1-output transaction +# threshold_tx_transfer = b.create_transaction([thresholduser1_pub, thresholduser2_pub, thresholduser3_pub], +# thresholduser4_pub, tx_retrieved_id, 'TRANSFER') +# +# # parse the threshold cryptocondition +# 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] +# subfulfillment3 = threshold_fulfillment.get_subcondition_from_vk(thresholduser3_pub)[0] +# +# +# # get the fulfillment message to sign +# threshold_tx_fulfillment_message = util.get_fulfillment_message(threshold_tx_transfer, +# threshold_tx_transfer['transaction']['fulfillments'][0], +# serialized=True) +# +# # clear the subconditions of the threshold fulfillment, they will be added again after signing +# threshold_fulfillment.subconditions = [] +# +# # sign and add the subconditions until threshold of 2 is reached +# subfulfillment1.sign(threshold_tx_fulfillment_message, crypto.SigningKey(thresholduser1_priv)) +# threshold_fulfillment.add_subfulfillment(subfulfillment1) +# subfulfillment2.sign(threshold_tx_fulfillment_message, crypto.SigningKey(thresholduser2_priv)) +# threshold_fulfillment.add_subfulfillment(subfulfillment2) +# +# # Add remaining (unfulfilled) fulfillment as a condition +# threshold_fulfillment.add_subcondition(subfulfillment3.condition) +# +# assert threshold_fulfillment.validate(threshold_tx_fulfillment_message) == True +# +# threshold_tx_transfer['transaction']['fulfillments'][0]['fulfillment'] = threshold_fulfillment.serialize_uri() +# +# assert b.verify_signature(threshold_tx_transfer) == True +# +# assert b.validate_transaction(threshold_tx_transfer) == threshold_tx_transfer +# +# b.write_transaction(threshold_tx_transfer) +# +# print(json.dumps(threshold_tx_transfer, sort_keys=True, indent=4, separators=(',', ':'))) """ -Read the Creation Transaction from the DB +Hashlocked Conditions """ -tx_retrieved = b.get_transaction(tx_signed['id']) +# Create a hash-locked asset without any new_owners +hashlock_tx = b.create_transaction(b.me, None, None, 'CREATE') -print(json.dumps(tx_retrieved, sort_keys=True, indent=4, separators=(',', ':'))) +# Define a secret that will be hashed - fulfillments need to guess the secret +secret = b'much secret! wow!' +first_tx_condition = cc.PreimageSha256Fulfillment(preimage=secret) -print(testuser1_pub) -print(b.me) +# The conditions list is empty, so we need to append a new condition +hashlock_tx['transaction']['conditions'].append({ + 'condition': { + 'details': json.loads(first_tx_condition.serialize_json()), + 'uri': first_tx_condition.condition.serialize_uri() + }, + 'cid': 0, + 'new_owners': None +}) -print(tx_retrieved['id']) +# Conditions have been updated, so hash needs updating +hashlock_tx['id'] = util.get_hash_data(hashlock_tx) -""" -Transfer the Digital Asset -""" +# The asset needs to be signed by the current_owner +hashlock_tx_signed = b.sign_transaction(hashlock_tx, b.me_private) -# create a second testuser -testuser2_priv, testuser2_pub = crypto.generate_key_pair() +# Some validations +assert b.validate_transaction(hashlock_tx_signed) == hashlock_tx_signed +assert b.is_valid_transaction(hashlock_tx_signed) == hashlock_tx_signed -# retrieve the transaction with condition id -tx_retrieved_id = b.get_owned_ids(testuser1_pub).pop() -print(json.dumps(tx_retrieved_id, sort_keys=True, indent=4, separators=(',', ':'))) - -# create a transfer transaction -tx_transfer = b.create_transaction(testuser1_pub, testuser2_pub, tx_retrieved_id, 'TRANSFER') - -# sign the transaction -tx_transfer_signed = b.sign_transaction(tx_transfer, testuser1_priv) - -# write the transaction -b.write_transaction(tx_transfer_signed) +b.write_transaction(hashlock_tx_signed) +print(json.dumps(hashlock_tx_signed, sort_keys=True, indent=4, separators=(',', ':'))) sleep(10) -# check if the transaction is already in the bigchain -tx_transfer_retrieved = b.get_transaction(tx_transfer_signed['id']) -print(json.dumps(tx_transfer_retrieved, sort_keys=True, indent=4, separators=(',', ':'))) +hashlockuser_priv, hashlockuser_pub = crypto.generate_key_pair() -""" -Double Spends -""" +# create hashlock fulfillment tx +hashlock_fulfill_tx = b.create_transaction(None, hashlockuser_priv, {'txid': hashlock_tx['id'], 'cid': 0}, 'TRANSFER') -# create another transfer transaction with the same input -tx_transfer2 = b.create_transaction(testuser1_pub, testuser2_pub, tx_retrieved_id, 'TRANSFER') +# try a wrong secret +hashlock_fulfill_tx_fulfillment = cc.PreimageSha256Fulfillment(preimage=b'') +hashlock_fulfill_tx['transaction']['fulfillments'][0]['fulfillment'] = \ + hashlock_fulfill_tx_fulfillment.serialize_uri() -# sign the transaction -tx_transfer_signed2 = b.sign_transaction(tx_transfer2, testuser1_priv) +assert b.is_valid_transaction(hashlock_fulfill_tx) == False -# check if the transaction is valid -try: - b.validate_transaction(tx_transfer_signed2) -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') - -# Have the federation sign the transaction -tx_multisig_signed = b.sign_transaction(tx_multisig, b.me_private) -b.write_transaction(tx_multisig_signed) - -# wait a few seconds for the asset to appear on the blockchain -sleep(10) - -# retrieve the transaction -tx_multisig_retrieved = b.get_transaction(tx_multisig_signed['id']) - -print(json.dumps(tx_multisig_retrieved, sort_keys=True, indent=4, separators=(',', ':'))) - -testuser3_priv, testuser3_pub = crypto.generate_key_pair() - -tx_multisig_retrieved_id = b.get_owned_ids(testuser2_pub).pop() -tx_multisig_transfer = b.create_transaction([testuser1_pub, testuser2_pub], testuser3_pub, tx_multisig_retrieved_id, 'TRANSFER') -tx_multisig_transfer_signed = b.sign_transaction(tx_multisig_transfer, [testuser1_priv, testuser2_priv]) - -b.write_transaction(tx_multisig_transfer_signed) - -# wait a few seconds for the asset to appear on the blockchain -sleep(10) - -# retrieve the transaction -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() -thresholduser3_priv, thresholduser3_pub = crypto.generate_key_pair() - -# retrieve the last transaction of testuser2 -tx_retrieved_id = b.get_owned_ids(testuser2_pub).pop() - -# create a base template for a 1-input/3-output transaction -threshold_tx = b.create_transaction(testuser2_pub, [thresholduser1_pub, thresholduser2_pub, thresholduser3_pub], - tx_retrieved_id, 'TRANSFER') - -# create a 2-out-of-3 Threshold Cryptocondition -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'] = { - 'details': json.loads(threshold_condition.serialize_json()), - 'uri': threshold_condition.condition.serialize_uri() -} - -# conditions have been updated, so hash needs updating -threshold_tx['id'] = util.get_hash_data(threshold_tx) - -# sign the transaction -threshold_tx_signed = b.sign_transaction(threshold_tx, testuser2_priv) - -# write the transaction -b.write_transaction(threshold_tx_signed) - -sleep(10) - -# check if the transaction is already in the bigchain -tx_threshold_retrieved = b.get_transaction(threshold_tx_signed['id']) -print(json.dumps(tx_threshold_retrieved, sort_keys=True, indent=4, separators=(',', ':'))) - -thresholduser4_priv, thresholduser4_pub = crypto.generate_key_pair() - -# retrieve the last transaction of thresholduser1_pub -tx_retrieved_id = b.get_owned_ids(thresholduser1_pub).pop() - -# create a base template for a 2-input/1-output transaction -threshold_tx_transfer = b.create_transaction([thresholduser1_pub, thresholduser2_pub, thresholduser3_pub], - thresholduser4_pub, tx_retrieved_id, 'TRANSFER') - -# parse the threshold cryptocondition -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] -subfulfillment3 = threshold_fulfillment.get_subcondition_from_vk(thresholduser3_pub)[0] - - -# get the fulfillment message to sign -threshold_tx_fulfillment_message = util.get_fulfillment_message(threshold_tx_transfer, - threshold_tx_transfer['transaction']['fulfillments'][0], - serialized=True) - -# clear the subconditions of the threshold fulfillment, they will be added again after signing -threshold_fulfillment.subconditions = [] - -# sign and add the subconditions until threshold of 2 is reached -subfulfillment1.sign(threshold_tx_fulfillment_message, crypto.SigningKey(thresholduser1_priv)) -threshold_fulfillment.add_subfulfillment(subfulfillment1) -subfulfillment2.sign(threshold_tx_fulfillment_message, crypto.SigningKey(thresholduser2_priv)) -threshold_fulfillment.add_subfulfillment(subfulfillment2) - -# Add remaining (unfulfilled) fulfillment as a condition -threshold_fulfillment.add_subcondition(subfulfillment3.condition) - -assert threshold_fulfillment.validate(threshold_tx_fulfillment_message) == True - -threshold_tx_transfer['transaction']['fulfillments'][0]['fulfillment'] = threshold_fulfillment.serialize_uri() - -assert b.verify_signature(threshold_tx_transfer) == True - -assert b.validate_transaction(threshold_tx_transfer) == threshold_tx_transfer - -b.write_transaction(threshold_tx_transfer) - -print(json.dumps(threshold_tx_transfer, sort_keys=True, indent=4, separators=(',', ':'))) +# provide the right secret +hashlock_fulfill_tx_fulfillment = cc.PreimageSha256Fulfillment(preimage=secret) +hashlock_fulfill_tx['transaction']['fulfillments'][0]['fulfillment'] = \ + hashlock_fulfill_tx_fulfillment.serialize_uri() +assert b.validate_transaction(hashlock_fulfill_tx) == hashlock_fulfill_tx +assert b.is_valid_transaction(hashlock_fulfill_tx) == hashlock_fulfill_tx +b.write_transaction(hashlock_fulfill_tx) +print(json.dumps(hashlock_fulfill_tx, sort_keys=True, indent=4, separators=(',', ':'))) From e92627e4474be8f53e1f4a38c2019e07d3bbd85c Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 21 Apr 2016 19:02:07 +0200 Subject: [PATCH 2/3] uncommented example code --- .../doc/run_doc_python_server_api_examples.py | 406 +++++++++--------- 1 file changed, 203 insertions(+), 203 deletions(-) diff --git a/tests/doc/run_doc_python_server_api_examples.py b/tests/doc/run_doc_python_server_api_examples.py index 355cc957..17e9cf87 100644 --- a/tests/doc/run_doc_python_server_api_examples.py +++ b/tests/doc/run_doc_python_server_api_examples.py @@ -29,209 +29,209 @@ tx_signed = b.sign_transaction(tx, b.me_private) # included in a block, and written to the bigchain 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=(',', ':'))) -# -# 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() -# -# # retrieve the transaction with condition id -# tx_retrieved_id = b.get_owned_ids(testuser1_pub).pop() -# print(json.dumps(tx_retrieved_id, sort_keys=True, indent=4, separators=(',', ':'))) -# -# # create a transfer transaction -# tx_transfer = b.create_transaction(testuser1_pub, testuser2_pub, tx_retrieved_id, 'TRANSFER') -# -# # sign the transaction -# tx_transfer_signed = b.sign_transaction(tx_transfer, testuser1_priv) -# -# # write the transaction -# b.write_transaction(tx_transfer_signed) -# -# sleep(10) -# -# # check if the transaction is already in the bigchain -# 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') -# -# # sign the transaction -# tx_transfer_signed2 = b.sign_transaction(tx_transfer2, testuser1_priv) -# -# # check if the transaction is valid -# try: -# b.validate_transaction(tx_transfer_signed2) -# 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') -# -# # Have the federation sign the transaction -# tx_multisig_signed = b.sign_transaction(tx_multisig, b.me_private) -# b.write_transaction(tx_multisig_signed) -# -# # wait a few seconds for the asset to appear on the blockchain -# sleep(10) -# -# # retrieve the transaction -# tx_multisig_retrieved = b.get_transaction(tx_multisig_signed['id']) -# -# print(json.dumps(tx_multisig_retrieved, sort_keys=True, indent=4, separators=(',', ':'))) -# -# testuser3_priv, testuser3_pub = crypto.generate_key_pair() -# -# tx_multisig_retrieved_id = b.get_owned_ids(testuser2_pub).pop() -# tx_multisig_transfer = b.create_transaction([testuser1_pub, testuser2_pub], testuser3_pub, tx_multisig_retrieved_id, 'TRANSFER') -# tx_multisig_transfer_signed = b.sign_transaction(tx_multisig_transfer, [testuser1_priv, testuser2_priv]) -# -# b.write_transaction(tx_multisig_transfer_signed) -# -# # wait a few seconds for the asset to appear on the blockchain -# sleep(10) -# -# # retrieve the transaction -# 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() -# thresholduser3_priv, thresholduser3_pub = crypto.generate_key_pair() -# -# # retrieve the last transaction of testuser2 -# tx_retrieved_id = b.get_owned_ids(testuser2_pub).pop() -# -# # create a base template for a 1-input/3-output transaction -# threshold_tx = b.create_transaction(testuser2_pub, [thresholduser1_pub, thresholduser2_pub, thresholduser3_pub], -# tx_retrieved_id, 'TRANSFER') -# -# # create a 2-out-of-3 Threshold Cryptocondition -# 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'] = { -# 'details': json.loads(threshold_condition.serialize_json()), -# 'uri': threshold_condition.condition.serialize_uri() -# } -# -# # conditions have been updated, so hash needs updating -# threshold_tx['id'] = util.get_hash_data(threshold_tx) -# -# # sign the transaction -# threshold_tx_signed = b.sign_transaction(threshold_tx, testuser2_priv) -# -# # write the transaction -# b.write_transaction(threshold_tx_signed) -# -# sleep(10) -# -# # check if the transaction is already in the bigchain -# tx_threshold_retrieved = b.get_transaction(threshold_tx_signed['id']) -# print(json.dumps(tx_threshold_retrieved, sort_keys=True, indent=4, separators=(',', ':'))) -# -# thresholduser4_priv, thresholduser4_pub = crypto.generate_key_pair() -# -# # retrieve the last transaction of thresholduser1_pub -# tx_retrieved_id = b.get_owned_ids(thresholduser1_pub).pop() -# -# # create a base template for a 2-input/1-output transaction -# threshold_tx_transfer = b.create_transaction([thresholduser1_pub, thresholduser2_pub, thresholduser3_pub], -# thresholduser4_pub, tx_retrieved_id, 'TRANSFER') -# -# # parse the threshold cryptocondition -# 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] -# subfulfillment3 = threshold_fulfillment.get_subcondition_from_vk(thresholduser3_pub)[0] -# -# -# # get the fulfillment message to sign -# threshold_tx_fulfillment_message = util.get_fulfillment_message(threshold_tx_transfer, -# threshold_tx_transfer['transaction']['fulfillments'][0], -# serialized=True) -# -# # clear the subconditions of the threshold fulfillment, they will be added again after signing -# threshold_fulfillment.subconditions = [] -# -# # sign and add the subconditions until threshold of 2 is reached -# subfulfillment1.sign(threshold_tx_fulfillment_message, crypto.SigningKey(thresholduser1_priv)) -# threshold_fulfillment.add_subfulfillment(subfulfillment1) -# subfulfillment2.sign(threshold_tx_fulfillment_message, crypto.SigningKey(thresholduser2_priv)) -# threshold_fulfillment.add_subfulfillment(subfulfillment2) -# -# # Add remaining (unfulfilled) fulfillment as a condition -# threshold_fulfillment.add_subcondition(subfulfillment3.condition) -# -# assert threshold_fulfillment.validate(threshold_tx_fulfillment_message) == True -# -# threshold_tx_transfer['transaction']['fulfillments'][0]['fulfillment'] = threshold_fulfillment.serialize_uri() -# -# assert b.verify_signature(threshold_tx_transfer) == True -# -# assert b.validate_transaction(threshold_tx_transfer) == threshold_tx_transfer -# -# b.write_transaction(threshold_tx_transfer) -# -# print(json.dumps(threshold_tx_transfer, sort_keys=True, indent=4, separators=(',', ':'))) +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=(',', ':'))) + +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() + +# retrieve the transaction with condition id +tx_retrieved_id = b.get_owned_ids(testuser1_pub).pop() +print(json.dumps(tx_retrieved_id, sort_keys=True, indent=4, separators=(',', ':'))) + +# create a transfer transaction +tx_transfer = b.create_transaction(testuser1_pub, testuser2_pub, tx_retrieved_id, 'TRANSFER') + +# sign the transaction +tx_transfer_signed = b.sign_transaction(tx_transfer, testuser1_priv) + +# write the transaction +b.write_transaction(tx_transfer_signed) + +sleep(10) + +# check if the transaction is already in the bigchain +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') + +# sign the transaction +tx_transfer_signed2 = b.sign_transaction(tx_transfer2, testuser1_priv) + +# check if the transaction is valid +try: + b.validate_transaction(tx_transfer_signed2) +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') + +# Have the federation sign the transaction +tx_multisig_signed = b.sign_transaction(tx_multisig, b.me_private) +b.write_transaction(tx_multisig_signed) + +# wait a few seconds for the asset to appear on the blockchain +sleep(10) + +# retrieve the transaction +tx_multisig_retrieved = b.get_transaction(tx_multisig_signed['id']) + +print(json.dumps(tx_multisig_retrieved, sort_keys=True, indent=4, separators=(',', ':'))) + +testuser3_priv, testuser3_pub = crypto.generate_key_pair() + +tx_multisig_retrieved_id = b.get_owned_ids(testuser2_pub).pop() +tx_multisig_transfer = b.create_transaction([testuser1_pub, testuser2_pub], testuser3_pub, tx_multisig_retrieved_id, 'TRANSFER') +tx_multisig_transfer_signed = b.sign_transaction(tx_multisig_transfer, [testuser1_priv, testuser2_priv]) + +b.write_transaction(tx_multisig_transfer_signed) + +# wait a few seconds for the asset to appear on the blockchain +sleep(10) + +# retrieve the transaction +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() +thresholduser3_priv, thresholduser3_pub = crypto.generate_key_pair() + +# retrieve the last transaction of testuser2 +tx_retrieved_id = b.get_owned_ids(testuser2_pub).pop() + +# create a base template for a 1-input/3-output transaction +threshold_tx = b.create_transaction(testuser2_pub, [thresholduser1_pub, thresholduser2_pub, thresholduser3_pub], + tx_retrieved_id, 'TRANSFER') + +# create a 2-out-of-3 Threshold Cryptocondition +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'] = { + 'details': json.loads(threshold_condition.serialize_json()), + 'uri': threshold_condition.condition.serialize_uri() +} + +# conditions have been updated, so hash needs updating +threshold_tx['id'] = util.get_hash_data(threshold_tx) + +# sign the transaction +threshold_tx_signed = b.sign_transaction(threshold_tx, testuser2_priv) + +# write the transaction +b.write_transaction(threshold_tx_signed) + +sleep(10) + +# check if the transaction is already in the bigchain +tx_threshold_retrieved = b.get_transaction(threshold_tx_signed['id']) +print(json.dumps(tx_threshold_retrieved, sort_keys=True, indent=4, separators=(',', ':'))) + +thresholduser4_priv, thresholduser4_pub = crypto.generate_key_pair() + +# retrieve the last transaction of thresholduser1_pub +tx_retrieved_id = b.get_owned_ids(thresholduser1_pub).pop() + +# create a base template for a 2-input/1-output transaction +threshold_tx_transfer = b.create_transaction([thresholduser1_pub, thresholduser2_pub, thresholduser3_pub], + thresholduser4_pub, tx_retrieved_id, 'TRANSFER') + +# parse the threshold cryptocondition +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] +subfulfillment3 = threshold_fulfillment.get_subcondition_from_vk(thresholduser3_pub)[0] + + +# get the fulfillment message to sign +threshold_tx_fulfillment_message = util.get_fulfillment_message(threshold_tx_transfer, + threshold_tx_transfer['transaction']['fulfillments'][0], + serialized=True) + +# clear the subconditions of the threshold fulfillment, they will be added again after signing +threshold_fulfillment.subconditions = [] + +# sign and add the subconditions until threshold of 2 is reached +subfulfillment1.sign(threshold_tx_fulfillment_message, crypto.SigningKey(thresholduser1_priv)) +threshold_fulfillment.add_subfulfillment(subfulfillment1) +subfulfillment2.sign(threshold_tx_fulfillment_message, crypto.SigningKey(thresholduser2_priv)) +threshold_fulfillment.add_subfulfillment(subfulfillment2) + +# Add remaining (unfulfilled) fulfillment as a condition +threshold_fulfillment.add_subcondition(subfulfillment3.condition) + +assert threshold_fulfillment.validate(threshold_tx_fulfillment_message) == True + +threshold_tx_transfer['transaction']['fulfillments'][0]['fulfillment'] = threshold_fulfillment.serialize_uri() + +assert b.verify_signature(threshold_tx_transfer) == True + +assert b.validate_transaction(threshold_tx_transfer) == threshold_tx_transfer + +b.write_transaction(threshold_tx_transfer) + +print(json.dumps(threshold_tx_transfer, sort_keys=True, indent=4, separators=(',', ':'))) """ Hashlocked Conditions From db06970b1a864daede1ee3c450c94ce576477612 Mon Sep 17 00:00:00 2001 From: diminator Date: Tue, 3 May 2016 11:18:57 +0200 Subject: [PATCH 3/3] PR comments --- bigchaindb/util.py | 10 ++++++++-- docs/source/python-server-api-examples.md | 7 ------- tests/doc/run_doc_python_server_api_examples.py | 1 - 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/bigchaindb/util.py b/bigchaindb/util.py index f173d4e5..9f0e59c3 100644 --- a/bigchaindb/util.py +++ b/bigchaindb/util.py @@ -256,15 +256,21 @@ def create_tx(current_owners, new_owners, inputs, operation, payload=None): # handle outputs conditions = [] for fulfillment in fulfillments: - condition = None + + # threshold condition if len(new_owners) > 1: condition = cc.ThresholdSha256Fulfillment(threshold=len(new_owners)) for new_owner in new_owners: condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=new_owner)) + + # simple signature condition elif len(new_owners) == 1: condition = cc.Ed25519Fulfillment(public_key=new_owners[0]) - # The None case appears on assigning a hashlock + # to be added later (hashlock conditions) + else: + condition = None + if condition: conditions.append({ 'new_owners': new_owners, diff --git a/docs/source/python-server-api-examples.md b/docs/source/python-server-api-examples.md index 4bbfe6d1..c191fe74 100644 --- a/docs/source/python-server-api-examples.md +++ b/docs/source/python-server-api-examples.md @@ -765,7 +765,6 @@ first_tx_condition = cc.PreimageSha256Fulfillment(preimage=secret) # The conditions list is empty, so we need to append a new condition hashlock_tx['transaction']['conditions'].append({ 'condition': { - 'details': json.loads(first_tx_condition.serialize_json()), 'uri': first_tx_condition.condition.serialize_uri() }, 'cid': 0, @@ -795,12 +794,6 @@ hashlock_tx_signed { "cid":0, "condition":{ - "details":{ - "bitmask":3, - "preimage":"much secret! wow!", - "type":"fulfillment", - "type_id":0 - }, "uri":"cc:0:3:nsW2IiYgk9EUtsg4uBe3pBnOgRoAEX2IIsPgjqZz47U:17" }, "new_owners":None diff --git a/tests/doc/run_doc_python_server_api_examples.py b/tests/doc/run_doc_python_server_api_examples.py index 17e9cf87..56a6aa31 100644 --- a/tests/doc/run_doc_python_server_api_examples.py +++ b/tests/doc/run_doc_python_server_api_examples.py @@ -247,7 +247,6 @@ first_tx_condition = cc.PreimageSha256Fulfillment(preimage=secret) # The conditions list is empty, so we need to append a new condition hashlock_tx['transaction']['conditions'].append({ 'condition': { - 'details': json.loads(first_tx_condition.serialize_json()), 'uri': first_tx_condition.condition.serialize_uri() }, 'cid': 0,