planetmint/acceptance/python/src/test_divisible_asset.py
Jürgen Eckel 637dc4993b
Ipld (#256)
* added ipld dep

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

* Cid tx schema (#252)

* changed asset and metadata schema to string

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

* updated fixtures and adjusted some models and test cases

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

* adjusted dependencies, fixtures and added comments

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

* alignd TX inputs to be CID compatible

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

* converted assets to CIDs

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

* added multihashes

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

* fixed data packaging for IPLD compatible test cases for the unit tests

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

* Transaction hierarchy (#254)

* removed Transaction class from models.py, adjusted imports and function calls

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

* removed comments

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

* removed empty lines

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

* resolved linting error

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

* adjusted import path

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

* added missing argument to mock

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

* resolved linting error

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

* adjusted mock func signature

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

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

* fixed all unit tests

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

* fixed zenroom acceptance test

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

* adjusted common tx schema, fixed election validate

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

* fixed an planetmint-ipld dependency that solved a package namespace collision in the dependencies of IPLD

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

* disabled integration and acceptance tests as they rely on planetmint driver.
Plan is to resolve this circular dependency

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

* adjusted acceptance tests to IPLD requirements

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

* blackified

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

* added missing imports

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

* blackified little changes

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
Co-authored-by: Jürgen Eckel <juergen@riddleandcode.com>
Co-authored-by: Jürgen Eckel <eckelj@users.noreply.github.com>

* increased version
enforce ipld encodings to metadata and asset["data"]

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
Co-authored-by: Lorenz Herzberger <64837895+LaurentMontBlanc@users.noreply.github.com>
2022-09-16 00:13:51 +02:00

169 lines
6.8 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
# # Divisible assets integration testing
# This test checks if we can successfully divide assets.
# The script tests various things like:
#
# - create a transaction with a divisible asset and issue them to someone
# - check if the transaction is stored and has the right amount of tokens
# - spend some tokens
# - try to spend more tokens than available
#
# We run a series of checks for each step, that is retrieving
# the transaction from the remote system, and also checking the `amount`
# of a given transaction.
# ## Imports
# We need some utils from the `os` package, we will interact with
# env variables.
# We need the `pytest` package to catch the `BadRequest` exception properly.
# And of course, we also need the `BadRequest`.
import os
import pytest
from planetmint_driver.exceptions import BadRequest
# For this test case we import and use the Python Driver.
from planetmint_driver import Planetmint
from planetmint_driver.crypto import generate_keypair
from ipld import multihash, marshal
def test_divisible_assets():
# ## Set up a connection to Planetmint
# Check [test_basic.py](./test_basic.html) to get some more details
# about the endpoint.
bdb = Planetmint(os.environ.get("PLANETMINT_ENDPOINT"))
# Oh look, it is Alice again and she brought her friend Bob along.
alice, bob = generate_keypair(), generate_keypair()
# ## Alice creates a time sharing token
# Alice wants to go on vacation, while Bobs bike just broke down.
# Alice decides to rent her bike to Bob while she is gone.
# So she prepares a `CREATE` transaction to issues 10 tokens.
# First, she prepares an asset for a time sharing token. As you can see in
# the description, Bob and Alice agree that each token can be used to ride
# the bike for one hour.
bike_token = {
"data": multihash(
marshal(
{
"token_for": {"bike": {"serial_number": 420420}},
"description": "Time share token. Each token equals one hour of riding.",
}
)
),
}
# She prepares a `CREATE` transaction and issues 10 tokens.
# Here, Alice defines in a tuple that she wants to assign
# these 10 tokens to Bob.
prepared_token_tx = bdb.transactions.prepare(
operation="CREATE", signers=alice.public_key, recipients=[([bob.public_key], 10)], asset=bike_token
)
# She fulfills and sends the transaction.
fulfilled_token_tx = bdb.transactions.fulfill(prepared_token_tx, private_keys=alice.private_key)
bdb.transactions.send_commit(fulfilled_token_tx)
# We store the `id` of the transaction to use it later on.
bike_token_id = fulfilled_token_tx["id"]
# Let's check if the transaction was successful.
assert bdb.transactions.retrieve(bike_token_id), "Cannot find transaction {}".format(bike_token_id)
# Bob owns 10 tokens now.
assert bdb.transactions.retrieve(bike_token_id)["outputs"][0]["amount"] == "10"
# ## Bob wants to use the bike
# Now that Bob got the tokens and the sun is shining, he wants to get out
# with the bike for three hours.
# To use the bike he has to send the tokens back to Alice.
# To learn about the details of transferring a transaction check out
# [test_basic.py](./test_basic.html)
transfer_asset = {"id": bike_token_id}
output_index = 0
output = fulfilled_token_tx["outputs"][output_index]
transfer_input = {
"fulfillment": output["condition"]["details"],
"fulfills": {"output_index": output_index, "transaction_id": fulfilled_token_tx["id"]},
"owners_before": output["public_keys"],
}
# To use the tokens Bob has to reassign 7 tokens to himself and the
# amount he wants to use to Alice.
prepared_transfer_tx = bdb.transactions.prepare(
operation="TRANSFER",
asset=transfer_asset,
inputs=transfer_input,
recipients=[([alice.public_key], 3), ([bob.public_key], 7)],
)
# He signs and sends the transaction.
fulfilled_transfer_tx = bdb.transactions.fulfill(prepared_transfer_tx, private_keys=bob.private_key)
sent_transfer_tx = bdb.transactions.send_commit(fulfilled_transfer_tx)
# First, Bob checks if the transaction was successful.
assert bdb.transactions.retrieve(fulfilled_transfer_tx["id"]) == sent_transfer_tx
# There are two outputs in the transaction now.
# The first output shows that Alice got back 3 tokens...
assert bdb.transactions.retrieve(fulfilled_transfer_tx["id"])["outputs"][0]["amount"] == "3"
# ... while Bob still has 7 left.
assert bdb.transactions.retrieve(fulfilled_transfer_tx["id"])["outputs"][1]["amount"] == "7"
# ## Bob wants to ride the bike again
# It's been a week and Bob wants to right the bike again.
# Now he wants to ride for 8 hours, that's a lot Bob!
# He prepares the transaction again.
transfer_asset = {"id": bike_token_id}
# This time we need an `output_index` of 1, since we have two outputs
# in the `fulfilled_transfer_tx` we created before. The first output with
# index 0 is for Alice and the second output is for Bob.
# Since Bob wants to spend more of his tokens he has to provide the
# correct output with the correct amount of tokens.
output_index = 1
output = fulfilled_transfer_tx["outputs"][output_index]
transfer_input = {
"fulfillment": output["condition"]["details"],
"fulfills": {"output_index": output_index, "transaction_id": fulfilled_transfer_tx["id"]},
"owners_before": output["public_keys"],
}
# This time Bob only provides Alice in the `recipients` because he wants
# to spend all his tokens
prepared_transfer_tx = bdb.transactions.prepare(
operation="TRANSFER", asset=transfer_asset, inputs=transfer_input, recipients=[([alice.public_key], 8)]
)
fulfilled_transfer_tx = bdb.transactions.fulfill(prepared_transfer_tx, private_keys=bob.private_key)
# Oh Bob, what have you done?! You tried to spend more tokens than you had.
# Remember Bob, last time you spent 3 tokens already,
# so you only have 7 left.
with pytest.raises(BadRequest) as error:
bdb.transactions.send_commit(fulfilled_transfer_tx)
# Now Bob gets an error saying that the amount he wanted to spent is
# higher than the amount of tokens he has left.
assert error.value.args[0] == 400
message = (
"Invalid transaction (AmountError): The amount used in the "
"inputs `7` needs to be same as the amount used in the "
"outputs `8`"
)
assert error.value.args[2]["message"] == message
# We have to stop this test now, I am sorry, but Bob is pretty upset
# about his mistake. See you next time :)