mirror of
https://github.com/planetmint/planetmint.git
synced 2025-06-15 10:46:38 +00:00

* 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>
337 lines
11 KiB
Python
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)
|