planetmint/integration/python/src/test_threshold.py
Lorenz Herzberger df7c1e1ccf
Enhance integration test suite (#62)
* restructering, added helper, split cli tests for later

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>

* fixed threshold test

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>

* added acceptance tests to integration test suite

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>

* added different threshold signature test scenarios

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>

* started chain-migration test implementation

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>

* fixed linter errors

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>

* removed -s from test command

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
2022-03-24 14:24:32 +01:00

337 lines
11 KiB
Python

# 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
# ## Imports
import time
import json
# For this test case we need the planetmint_driver.crypto package
import base58
import sha3
from cryptoconditions import Ed25519Sha256, ThresholdSha256
from planetmint_driver.crypto import generate_keypair
# Import helper to deal with multiple nodes
from .helper.hosts import Hosts
def prepare_condition_details(condition: ThresholdSha256):
condition_details = {
'subconditions': [],
'threshold': condition.threshold,
'type': condition.TYPE_NAME
}
for s in condition.subconditions:
if (s['type'] == 'fulfillment' and s['body'].TYPE_NAME == 'ed25519-sha-256'):
condition_details['subconditions'].append({
'type': s['body'].TYPE_NAME,
'public_key': base58.b58encode(s['body'].public_key).decode()
})
else:
condition_details['subconditions'].append(prepare_condition_details(s['body']))
return condition_details
def test_threshold():
# Setup connection to test nodes
hosts = Hosts('/shared/hostnames')
pm = hosts.get_connection()
# Generate Keypars for Alice, Bob an Carol!
alice, bob, carol = generate_keypair(), 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
}
}
}
# Create subfulfillments
alice_ed25519 = Ed25519Sha256(public_key=base58.b58decode(alice.public_key))
bob_ed25519 = Ed25519Sha256(public_key=base58.b58decode(bob.public_key))
carol_ed25519 = Ed25519Sha256(public_key=base58.b58decode(carol.public_key))
# Create threshold condition (2/3) and add subfulfillments
threshold_sha256 = ThresholdSha256(2)
threshold_sha256.add_subfulfillment(alice_ed25519)
threshold_sha256.add_subfulfillment(bob_ed25519)
threshold_sha256.add_subfulfillment(carol_ed25519)
# Create a condition uri and details for the output object
condition_uri = threshold_sha256.condition.serialize_uri()
condition_details = prepare_condition_details(threshold_sha256)
# Assemble output and input for the handcrafted tx
output = {
'amount': '1',
'condition': {
'details': condition_details,
'uri': condition_uri,
},
'public_keys': (alice.public_key, bob.public_key, carol.public_key),
}
# The yet to be fulfilled input:
input_ = {
'fulfillment': None,
'fulfills': None,
'owners_before': (alice.public_key, bob.public_key),
}
# Assemble the handcrafted transaction
handcrafted_dw_tx = {
'operation': 'CREATE',
'asset': dw_asset,
'metadata': None,
'outputs': (output,),
'inputs': (input_,),
'version': '2.0',
'id': None,
}
# Create sha3-256 of message to sign
message = json.dumps(
handcrafted_dw_tx,
sort_keys=True,
separators=(',', ':'),
ensure_ascii=False,
)
message = sha3.sha3_256(message.encode())
# Sign message with Alice's und Bob's private key
alice_ed25519.sign(message.digest(), base58.b58decode(alice.private_key))
bob_ed25519.sign(message.digest(), base58.b58decode(bob.private_key))
# Create fulfillment and add uri to inputs
fulfillment_threshold = ThresholdSha256(2)
fulfillment_threshold.add_subfulfillment(alice_ed25519)
fulfillment_threshold.add_subfulfillment(bob_ed25519)
fulfillment_threshold.add_subcondition(carol_ed25519.condition)
fulfillment_uri = fulfillment_threshold.serialize_uri()
handcrafted_dw_tx['inputs'][0]['fulfillment'] = fulfillment_uri
# Create tx_id for handcrafted_dw_tx and send tx commit
json_str_tx = json.dumps(
handcrafted_dw_tx,
sort_keys=True,
separators=(',', ':'),
ensure_ascii=False,
)
dw_creation_txid = sha3.sha3_256(json_str_tx.encode()).hexdigest()
handcrafted_dw_tx['id'] = dw_creation_txid
pm.transactions.send_commit(handcrafted_dw_tx)
time.sleep(1)
# Assert that the tx is propagated to all nodes
hosts.assert_transaction(dw_creation_txid)
def test_weighted_threshold():
hosts = Hosts('/shared/hostnames')
pm = hosts.get_connection()
alice, bob, carol = generate_keypair(), generate_keypair(), generate_keypair()
asset = {
'data': {
'trashcan': {
'animals': ['racoon_1', 'racoon_2']
}
}
}
alice_ed25519 = Ed25519Sha256(public_key=base58.b58decode(alice.public_key))
bob_ed25519 = Ed25519Sha256(public_key=base58.b58decode(bob.public_key))
carol_ed25519 = Ed25519Sha256(public_key=base58.b58decode(carol.public_key))
threshold = ThresholdSha256(1)
threshold.add_subfulfillment(alice_ed25519)
sub_threshold = ThresholdSha256(2)
sub_threshold.add_subfulfillment(bob_ed25519)
sub_threshold.add_subfulfillment(carol_ed25519)
threshold.add_subfulfillment(sub_threshold)
condition_uri = threshold.condition.serialize_uri()
condition_details = prepare_condition_details(threshold)
# Assemble output and input for the handcrafted tx
output = {
'amount': '1',
'condition': {
'details': condition_details,
'uri': condition_uri,
},
'public_keys': (alice.public_key, bob.public_key, carol.public_key),
}
# The yet to be fulfilled input:
input_ = {
'fulfillment': None,
'fulfills': None,
'owners_before': (alice.public_key, bob.public_key),
}
# Assemble the handcrafted transaction
handcrafted_tx = {
'operation': 'CREATE',
'asset': asset,
'metadata': None,
'outputs': (output,),
'inputs': (input_,),
'version': '2.0',
'id': None,
}
# Create sha3-256 of message to sign
message = json.dumps(
handcrafted_tx,
sort_keys=True,
separators=(',', ':'),
ensure_ascii=False,
)
message = sha3.sha3_256(message.encode())
# Sign message with Alice's und Bob's private key
alice_ed25519.sign(message.digest(), base58.b58decode(alice.private_key))
# Create fulfillment and add uri to inputs
sub_fulfillment_threshold = ThresholdSha256(2)
sub_fulfillment_threshold.add_subcondition(bob_ed25519.condition)
sub_fulfillment_threshold.add_subcondition(carol_ed25519.condition)
fulfillment_threshold = ThresholdSha256(1)
fulfillment_threshold.add_subfulfillment(alice_ed25519)
fulfillment_threshold.add_subfulfillment(sub_fulfillment_threshold)
fulfillment_uri = fulfillment_threshold.serialize_uri()
handcrafted_tx['inputs'][0]['fulfillment'] = fulfillment_uri
# Create tx_id for handcrafted_dw_tx and send tx commit
json_str_tx = json.dumps(
handcrafted_tx,
sort_keys=True,
separators=(',', ':'),
ensure_ascii=False,
)
creation_tx_id = sha3.sha3_256(json_str_tx.encode()).hexdigest()
handcrafted_tx['id'] = creation_tx_id
pm.transactions.send_commit(handcrafted_tx)
time.sleep(1)
# Assert that the tx is propagated to all nodes
hosts.assert_transaction(creation_tx_id)
# Now transfer created asset
alice_transfer_ed25519 = Ed25519Sha256(public_key=base58.b58decode(alice.public_key))
bob_transfer_ed25519 = Ed25519Sha256(public_key=base58.b58decode(bob.public_key))
carol_transfer_ed25519 = Ed25519Sha256(public_key=base58.b58decode(carol.public_key))
transfer_condition_uri = alice_transfer_ed25519.condition.serialize_uri()
# Assemble output and input for the handcrafted tx
transfer_output = {
'amount': '1',
'condition': {
'details': {
'type': alice_transfer_ed25519.TYPE_NAME,
'public_key': base58.b58encode(alice_transfer_ed25519.public_key).decode()
},
'uri': transfer_condition_uri,
},
'public_keys': (alice.public_key,),
}
# The yet to be fulfilled input:
transfer_input_ = {
'fulfillment': None,
'fulfills': {
'transaction_id': creation_tx_id,
'output_index': 0
},
'owners_before': (alice.public_key, bob.public_key, carol.public_key),
}
# Assemble the handcrafted transaction
handcrafted_transfer_tx = {
'operation': 'TRANSFER',
'asset': {'id': creation_tx_id},
'metadata': None,
'outputs': (transfer_output,),
'inputs': (transfer_input_,),
'version': '2.0',
'id': None,
}
# Create sha3-256 of message to sign
message = json.dumps(
handcrafted_transfer_tx,
sort_keys=True,
separators=(',', ':'),
ensure_ascii=False,
)
message = sha3.sha3_256(message.encode())
message.update('{}{}'.format(
handcrafted_transfer_tx['inputs'][0]['fulfills']['transaction_id'],
handcrafted_transfer_tx['inputs'][0]['fulfills']['output_index']).encode())
# Sign message with Alice's und Bob's private key
bob_transfer_ed25519.sign(message.digest(), base58.b58decode(bob.private_key))
carol_transfer_ed25519.sign(message.digest(), base58.b58decode(carol.private_key))
sub_fulfillment_threshold = ThresholdSha256(2)
sub_fulfillment_threshold.add_subfulfillment(bob_transfer_ed25519)
sub_fulfillment_threshold.add_subfulfillment(carol_transfer_ed25519)
# Create fulfillment and add uri to inputs
fulfillment_threshold = ThresholdSha256(1)
fulfillment_threshold.add_subcondition(alice_transfer_ed25519.condition)
fulfillment_threshold.add_subfulfillment(sub_fulfillment_threshold)
fulfillment_uri = fulfillment_threshold.serialize_uri()
handcrafted_transfer_tx['inputs'][0]['fulfillment'] = fulfillment_uri
# Create tx_id for handcrafted_dw_tx and send tx commit
json_str_tx = json.dumps(
handcrafted_transfer_tx,
sort_keys=True,
separators=(',', ':'),
ensure_ascii=False,
)
transfer_tx_id = sha3.sha3_256(json_str_tx.encode()).hexdigest()
handcrafted_transfer_tx['id'] = transfer_tx_id
pm.transactions.send_commit(handcrafted_transfer_tx)
time.sleep(1)
# Assert that the tx is propagated to all nodes
hosts.assert_transaction(transfer_tx_id)