# Copyright © 2020 Interplanetary Database Association e.V., # Planetmint and IPDB software contributors. # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # Code is Apache-2.0 and docs are CC-BY-4.0 # # Multisignature integration testing # This test checks if we can successfully create and transfer a transaction # with multiple owners. # The script tests various things like: # # - create a transaction with multiple owners # - check if the transaction is stored and has the right amount of public keys # - transfer the transaction to a third person # # We run a series of checks for each step, that is retrieving # the transaction from the remote system, and also checking the public keys # of a given transaction. # # This integration test is a rip-off of our mutliple signature acceptance tests. # # Imports import time # For this test case we need import and use the Python driver from planetmint_driver import Planetmint from planetmint_driver.crypto import generate_keypair def test_multiple_owners(): # Setup up connection to Planetmint integration test nodes hosts = [] with open('/shared/hostnames') as f: hosts = f.readlines() pm_hosts = list(map(lambda x: Planetmint(x), hosts)) pm_alpha = pm_hosts[0] pm_betas = pm_hosts[1:] # Generate Keypairs for Alice and Bob! alice, bob = generate_keypair(), generate_keypair() # ## Alice and Bob create a transaction # Alice and Bob just moved into a shared flat, no one can afford these # high rents anymore. Bob suggests to get a dish washer for the # kitchen. Alice agrees and here they go, creating the asset for their # dish washer. dw_asset = { 'data': { 'dish washer': { 'serial_number': 1337 } } } # They prepare a `CREATE` transaction. To have multiple owners, both # Bob and Alice need to be the recipients. prepared_dw_tx = pm_alpha.transactions.prepare( operation='CREATE', signers=alice.public_key, recipients=(alice.public_key, bob.public_key), asset=dw_asset) # Now they both sign the transaction by providing their private keys. # And send it afterwards. fulfilled_dw_tx = pm_alpha.transactions.fulfill( prepared_dw_tx, private_keys=[alice.private_key, bob.private_key]) pm_alpha.transactions.send_commit(fulfilled_dw_tx) # We store the `id` of the transaction to use it later on. dw_id = fulfilled_dw_tx['id'] time.sleep(1) # Let's retrieve the transaction from both nodes pm_alpha_tx = pm_alpha.transactions.retrieve(dw_id) pm_betas_tx = list(map(lambda beta: beta.transactions.retrieve(dw_id), pm_betas)) # Both retrieved transactions should be the same for tx in pm_betas_tx: assert pm_alpha_tx == tx # Let's check if the transaction was successful. assert pm_alpha.transactions.retrieve(dw_id), \ 'Cannot find transaction {}'.format(dw_id) # The transaction should have two public keys in the outputs. assert len( pm_alpha.transactions.retrieve(dw_id)['outputs'][0]['public_keys']) == 2 # ## Alice and Bob transfer a transaction to Carol. # Alice and Bob save a lot of money living together. They often go out # for dinner and don't cook at home. But now they don't have any dishes to # wash, so they decide to sell the dish washer to their friend Carol. # Hey Carol, nice to meet you! carol = generate_keypair() # Alice and Bob prepare the transaction to transfer the dish washer to # Carol. transfer_asset = {'id': dw_id} output_index = 0 output = fulfilled_dw_tx['outputs'][output_index] transfer_input = {'fulfillment': output['condition']['details'], 'fulfills': {'output_index': output_index, 'transaction_id': fulfilled_dw_tx[ 'id']}, 'owners_before': output['public_keys']} # Now they create the transaction... prepared_transfer_tx = pm_alpha.transactions.prepare( operation='TRANSFER', asset=transfer_asset, inputs=transfer_input, recipients=carol.public_key) # ... and sign it with their private keys, then send it. fulfilled_transfer_tx = pm_alpha.transactions.fulfill( prepared_transfer_tx, private_keys=[alice.private_key, bob.private_key]) sent_transfer_tx = pm_alpha.transactions.send_commit(fulfilled_transfer_tx) time.sleep(1) # Retrieve the fulfilled transaction from both nodes pm_alpha_tx = pm_alpha.transactions.retrieve(fulfilled_transfer_tx['id']) pm_betas_tx = list(map(lambda beta: beta.transactions.retrieve(fulfilled_transfer_tx['id']), pm_betas)) # Now compare if both nodes returned the same transaction for tx in pm_betas_tx: assert pm_alpha_tx == tx # They check if the transaction was successful. assert pm_alpha.transactions.retrieve( fulfilled_transfer_tx['id']) == sent_transfer_tx # The owners before should include both Alice and Bob. assert len( pm_alpha.transactions.retrieve(fulfilled_transfer_tx['id'])['inputs'][0][ 'owners_before']) == 2 # While the new owner is Carol. assert pm_alpha.transactions.retrieve(fulfilled_transfer_tx['id'])[ 'outputs'][0]['public_keys'][0] == carol.public_key