mirror of
https://github.com/planetmint/planetmint.git
synced 2025-11-25 23:15:44 +00:00
* adjusted to neweest transaction package * adjusted to new planetmint-cryptoconditions imports * added Changelog and increased version Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
320 lines
10 KiB
Python
320 lines
10 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 planetmint_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()
|
|
|
|
assets = [{"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": assets,
|
|
"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",
|
|
"assets": [{"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)
|