* 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>
This commit is contained in:
Jürgen Eckel 2022-09-16 00:13:51 +02:00 committed by GitHub
parent 22ccb26d99
commit 637dc4993b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 380 additions and 231 deletions

View File

@ -8,6 +8,7 @@ on: [push, pull_request]
jobs: jobs:
test: test:
if: ${{ false }
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

View File

@ -8,6 +8,7 @@ on: [push, pull_request]
jobs: jobs:
test: test:
if: ${{ false }
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

View File

@ -27,6 +27,15 @@ For reference, the possible headings are:
## [Unreleased] ## [Unreleased]
## [1.2.0] - 2022-09-05
* **Changed** disabled acceptance and integration tests, they have a circular dep. to the python driver
* **Changed** Metadata and asset["data"] types to string containing an IPLD hash
* **Fixed** Transaction generation bug that automatically assigned 'assets' to asset["data"]
* **Changed** adjusted test caes
## [1.1.0] - 2022-09-05 ## [1.1.0] - 2022-09-05
* **Changed** adjusted to zenroom calling convention of PRP #13 (breaking change) * **Changed** adjusted to zenroom calling convention of PRP #13 (breaking change)
* **Changed** zenroom test cases to comply to the new calling convention * **Changed** zenroom test cases to comply to the new calling convention

View File

@ -81,7 +81,7 @@ test: check-deps test-unit test-acceptance ## Run unit and acceptance tests
test-unit: check-deps ## Run all tests once test-unit: check-deps ## Run all tests once
@$(DC) up -d bdb @$(DC) up -d bdb
@$(DC) exec planetmint pytest @$(DC) exec planetmint pytest ${TEST}
test-unit-watch: check-deps ## Run all tests and wait. Every time you change code, tests will be run again test-unit-watch: check-deps ## Run all tests and wait. Every time you change code, tests will be run again
@$(DC) run --rm --no-deps planetmint pytest -f @$(DC) run --rm --no-deps planetmint pytest -f

View File

@ -17,3 +17,4 @@ RUN pip install --upgrade \
planetmint-driver>=0.9.2 \ planetmint-driver>=0.9.2 \
blns blns
RUN pip install base58>=2.1.1 pynacl==1.4.0 zenroom==2.1.0.dev1655293214 pyasn1==0.4.8 cryptography==3.4.7 RUN pip install base58>=2.1.1 pynacl==1.4.0 zenroom==2.1.0.dev1655293214 pyasn1==0.4.8 cryptography==3.4.7
RUN pip install planetmint-ipld>=0.0.3

View File

@ -23,6 +23,7 @@ import os
# For this test case we import and use the Python Driver. # For this test case we import and use the Python Driver.
from planetmint_driver import Planetmint from planetmint_driver import Planetmint
from planetmint_driver.crypto import generate_keypair from planetmint_driver.crypto import generate_keypair
from ipld import multihash, marshal
def test_get_tests(): def test_get_tests():
@ -41,7 +42,7 @@ def test_get_tests():
# ## Alice registers her bike in Planetmint # ## Alice registers her bike in Planetmint
# Alice has a nice bike, and here she creates the "digital twin" # Alice has a nice bike, and here she creates the "digital twin"
# of her bike. # of her bike.
bike = {"data": {"bicycle": {"serial_number": 420420}}} bike = {"data": multihash(marshal({"bicycle": {"serial_number": 420420}}))}
# She prepares a `CREATE` transaction... # She prepares a `CREATE` transaction...
prepared_creation_tx = bdb.transactions.prepare(operation="CREATE", signers=alice.public_key, asset=bike) prepared_creation_tx = bdb.transactions.prepare(operation="CREATE", signers=alice.public_key, asset=bike)

View File

@ -23,6 +23,7 @@ import os
# For this test case we import and use the Python Driver. # For this test case we import and use the Python Driver.
from planetmint_driver import Planetmint from planetmint_driver import Planetmint
from planetmint_driver.crypto import generate_keypair from planetmint_driver.crypto import generate_keypair
from ipld import multihash, marshal
def test_basic(): def test_basic():
@ -41,7 +42,7 @@ def test_basic():
# ## Alice registers her bike in Planetmint # ## Alice registers her bike in Planetmint
# Alice has a nice bike, and here she creates the "digital twin" # Alice has a nice bike, and here she creates the "digital twin"
# of her bike. # of her bike.
bike = {"data": {"bicycle": {"serial_number": 420420}}} bike = {"data": multihash(marshal({"bicycle": {"serial_number": 420420}}))}
# She prepares a `CREATE` transaction... # She prepares a `CREATE` transaction...
prepared_creation_tx = bdb.transactions.prepare(operation="CREATE", signers=alice.public_key, asset=bike) prepared_creation_tx = bdb.transactions.prepare(operation="CREATE", signers=alice.public_key, asset=bike)

View File

@ -28,6 +28,7 @@ from planetmint_driver.exceptions import BadRequest
# For this test case we import and use the Python Driver. # For this test case we import and use the Python Driver.
from planetmint_driver import Planetmint from planetmint_driver import Planetmint
from planetmint_driver.crypto import generate_keypair from planetmint_driver.crypto import generate_keypair
from ipld import multihash, marshal
def test_divisible_assets(): def test_divisible_assets():
@ -48,10 +49,14 @@ def test_divisible_assets():
# the bike for one hour. # the bike for one hour.
bike_token = { bike_token = {
"data": { "data": multihash(
"token_for": {"bike": {"serial_number": 420420}}, marshal(
"description": "Time share token. Each token equals one hour of riding.", {
}, "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. # She prepares a `CREATE` transaction and issues 10 tokens.

View File

@ -14,6 +14,7 @@ import queue
import planetmint_driver.exceptions import planetmint_driver.exceptions
from planetmint_driver import Planetmint from planetmint_driver import Planetmint
from planetmint_driver.crypto import generate_keypair from planetmint_driver.crypto import generate_keypair
from ipld import multihash, marshal
def test_double_create(): def test_double_create():
@ -23,7 +24,9 @@ def test_double_create():
results = queue.Queue() results = queue.Queue()
tx = bdb.transactions.fulfill( tx = bdb.transactions.fulfill(
bdb.transactions.prepare(operation="CREATE", signers=alice.public_key, asset={"data": {"uuid": str(uuid4())}}), bdb.transactions.prepare(
operation="CREATE", signers=alice.public_key, asset={"data": multihash(marshal({"uuid": str(uuid4())}))}
),
private_keys=alice.private_key, private_keys=alice.private_key,
) )

View File

@ -25,6 +25,7 @@ import os
# For this test case we import and use the Python Driver. # For this test case we import and use the Python Driver.
from planetmint_driver import Planetmint from planetmint_driver import Planetmint
from planetmint_driver.crypto import generate_keypair from planetmint_driver.crypto import generate_keypair
from ipld import multihash, marshal
def test_multiple_owners(): def test_multiple_owners():
@ -41,7 +42,7 @@ def test_multiple_owners():
# high rents anymore. Bob suggests to get a dish washer for the # high rents anymore. Bob suggests to get a dish washer for the
# kitchen. Alice agrees and here they go, creating the asset for their # kitchen. Alice agrees and here they go, creating the asset for their
# dish washer. # dish washer.
dw_asset = {"data": {"dish washer": {"serial_number": 1337}}} dw_asset = {"data": multihash(marshal({"dish washer": {"serial_number": 1337}}))}
# They prepare a `CREATE` transaction. To have multiple owners, both # They prepare a `CREATE` transaction. To have multiple owners, both
# Bob and Alice need to be the recipients. # Bob and Alice need to be the recipients.

View File

@ -29,6 +29,7 @@ import pytest
from planetmint_driver import Planetmint from planetmint_driver import Planetmint
from planetmint_driver.crypto import generate_keypair from planetmint_driver.crypto import generate_keypair
from planetmint_driver.exceptions import BadRequest from planetmint_driver.exceptions import BadRequest
from ipld import multihash, marshal
naughty_strings = blns.all() naughty_strings = blns.all()
skipped_naughty_strings = [ skipped_naughty_strings = [
@ -118,8 +119,8 @@ def send_naughty_tx(asset, metadata):
@pytest.mark.parametrize("naughty_string", naughty_strings, ids=naughty_strings) @pytest.mark.parametrize("naughty_string", naughty_strings, ids=naughty_strings)
def test_naughty_keys(naughty_string): def test_naughty_keys(naughty_string):
asset = {"data": {naughty_string: "nice_value"}} asset = {"data": multihash(marshal({naughty_string: "nice_value"}))}
metadata = {naughty_string: "nice_value"} metadata = multihash(marshal({naughty_string: "nice_value"}))
send_naughty_tx(asset, metadata) send_naughty_tx(asset, metadata)
@ -127,7 +128,7 @@ def test_naughty_keys(naughty_string):
@pytest.mark.parametrize("naughty_string", naughty_strings, ids=naughty_strings) @pytest.mark.parametrize("naughty_string", naughty_strings, ids=naughty_strings)
def test_naughty_values(naughty_string): def test_naughty_values(naughty_string):
asset = {"data": {"nice_key": naughty_string}} asset = {"data": multihash(marshal({"nice_key": naughty_string}))}
metadata = {"nice_key": naughty_string} metadata = multihash(marshal({"nice_key": naughty_string}))
send_naughty_tx(asset, metadata) send_naughty_tx(asset, metadata)

View File

@ -21,6 +21,7 @@ import queue
import json import json
from threading import Thread, Event from threading import Thread, Event
from uuid import uuid4 from uuid import uuid4
from ipld import multihash, marshal
# For this script, we need to set up a websocket connection, that's the reason # For this script, we need to set up a websocket connection, that's the reason
# we import the # we import the
@ -91,7 +92,9 @@ def test_stream():
for _ in range(10): for _ in range(10):
tx = bdb.transactions.fulfill( tx = bdb.transactions.fulfill(
bdb.transactions.prepare( bdb.transactions.prepare(
operation="CREATE", signers=alice.public_key, asset={"data": {"uuid": str(uuid4())}} operation="CREATE",
signers=alice.public_key,
asset={"data": multihash(marshal({"uuid": str(uuid4())}))},
), ),
private_keys=alice.private_key, private_keys=alice.private_key,
) )

View File

@ -7,6 +7,7 @@ from cryptoconditions.types.zenroom import ZenroomSha256
from zenroom import zencode_exec from zenroom import zencode_exec
from planetmint_driver import Planetmint from planetmint_driver import Planetmint
from planetmint_driver.crypto import generate_keypair from planetmint_driver.crypto import generate_keypair
from ipld import multihash, marshal
def test_zenroom_signing( def test_zenroom_signing(
@ -66,8 +67,8 @@ def test_zenroom_signing(
metadata = {"result": {"output": ["ok"]}} metadata = {"result": {"output": ["ok"]}}
script_ = { script_ = {
"code": {"type": "zenroom", "raw": "test_string", "parameters": [{"obj": "1"}, {"obj": "2"}]}, "code": {"type": "zenroom", "raw": "test_string", "parameters": [{"obj": "1"}, {"obj": "2"}]}, # obsolete
"state": "dd8bbd234f9869cab4cc0b84aa660e9b5ef0664559b8375804ee8dce75b10576", "state": "dd8bbd234f9869cab4cc0b84aa660e9b5ef0664559b8375804ee8dce75b10576", #
"input": zenroom_script_input, "input": zenroom_script_input,
"output": ["ok"], "output": ["ok"],
"policies": {}, "policies": {},
@ -75,9 +76,9 @@ def test_zenroom_signing(
token_creation_tx = { token_creation_tx = {
"operation": "CREATE", "operation": "CREATE",
"asset": {"data": {"test": "my asset"}}, "asset": {"data": multihash(marshal({"test": "my asset"}))},
"metadata": multihash(marshal(metadata)),
"script": script_, "script": script_,
"metadata": metadata,
"outputs": [ "outputs": [
output, output,
], ],

View File

@ -15,6 +15,7 @@ from planetmint import lib
from planetmint.transactions.types.assets.create import Create from planetmint.transactions.types.assets.create import Create
from planetmint.transactions.types.assets.transfer import Transfer from planetmint.transactions.types.assets.transfer import Transfer
from planetmint.web import server from planetmint.web import server
from ipld import multihash, marshal
TPLS = {} TPLS = {}
@ -157,10 +158,12 @@ def main():
ctx["api_index"] = pretty_json(json.loads(res.data.decode())) ctx["api_index"] = pretty_json(json.loads(res.data.decode()))
# tx create # tx create
from ipld import marshal, multihash
privkey = "CfdqtD7sS7FgkMoGPXw55MVGGFwQLAoHYTcBhZDtF99Z" privkey = "CfdqtD7sS7FgkMoGPXw55MVGGFwQLAoHYTcBhZDtF99Z"
pubkey = "4K9sWUMFwTgaDGPfdynrbxWqWS6sWmKbZoTjxLtVUibD" pubkey = "4K9sWUMFwTgaDGPfdynrbxWqWS6sWmKbZoTjxLtVUibD"
asset = {"msg": "Hello Planetmint!"} asset = {"data": multihash(marshal({"msg": "Hello Planetmint!"}))}
tx = Create.generate([pubkey], [([pubkey], 1)], asset=asset, metadata={"sequence": 0}) tx = Create.generate([pubkey], [([pubkey], 1)], asset=asset, metadata=multihash(marshal({"sequence": 0})))
tx = tx.sign([privkey]) tx = tx.sign([privkey])
ctx["tx"] = pretty_json(tx.to_dict()) ctx["tx"] = pretty_json(tx.to_dict())
ctx["public_keys"] = tx.outputs[0].public_keys[0] ctx["public_keys"] = tx.outputs[0].public_keys[0]
@ -176,7 +179,9 @@ def main():
fulfills=TransactionLink(txid=tx.id, output=cid), fulfills=TransactionLink(txid=tx.id, output=cid),
owners_before=tx.outputs[cid].public_keys, owners_before=tx.outputs[cid].public_keys,
) )
tx_transfer = Transfer.generate([input_], [([pubkey_transfer], 1)], asset_id=tx.id, metadata={"sequence": 1}) tx_transfer = Transfer.generate(
[input_], [([pubkey_transfer], 1)], asset_id=tx.id, metadata=multihash(marshal({"sequence": 1}))
)
tx_transfer = tx_transfer.sign([privkey]) tx_transfer = tx_transfer.sign([privkey])
ctx["tx_transfer"] = pretty_json(tx_transfer.to_dict()) ctx["tx_transfer"] = pretty_json(tx_transfer.to_dict())
ctx["public_keys_transfer"] = tx_transfer.outputs[0].public_keys[0] ctx["public_keys_transfer"] = tx_transfer.outputs[0].public_keys[0]
@ -192,7 +197,7 @@ def main():
owners_before=tx_transfer.outputs[cid].public_keys, owners_before=tx_transfer.outputs[cid].public_keys,
) )
tx_transfer_last = Transfer.generate( tx_transfer_last = Transfer.generate(
[input_], [([pubkey_transfer_last], 1)], asset_id=tx.id, metadata={"sequence": 2} [input_], [([pubkey_transfer_last], 1)], asset_id=tx.id, metadata=multihash(marshal({"sequence": 2}))
) )
tx_transfer_last = tx_transfer_last.sign([privkey_transfer]) tx_transfer_last = tx_transfer_last.sign([privkey_transfer])
ctx["tx_transfer_last"] = pretty_json(tx_transfer_last.to_dict()) ctx["tx_transfer_last"] = pretty_json(tx_transfer_last.to_dict())

View File

@ -14,7 +14,7 @@ register_query = module_dispatch_registrar(convert)
@register_query(LocalMongoDBConnection) @register_query(LocalMongoDBConnection)
def prepare_asset(connection, transaction_type, transaction_id, filter_operation, asset): def prepare_asset(connection, transaction_type, transaction_id, filter_operation, asset):
if transaction_type == filter_operation: if transaction_type in filter_operation:
asset["id"] = transaction_id asset["id"] = transaction_id
return asset return asset

View File

@ -15,7 +15,7 @@ register_query = module_dispatch_registrar(convert)
@register_query(TarantoolDBConnection) @register_query(TarantoolDBConnection)
def prepare_asset(connection, transaction_type, transaction_id, filter_operation, asset): def prepare_asset(connection, transaction_type, transaction_id, filter_operation, asset):
asset_id = transaction_id asset_id = transaction_id
if transaction_type != filter_operation: if transaction_type not in filter_operation:
asset_id = asset["id"] asset_id = asset["id"]
return tuple([asset, transaction_id, asset_id]) return tuple([asset, transaction_id, asset_id])

View File

@ -133,7 +133,7 @@ class Planetmint(object):
self.connection, self.connection,
transaction_type=transaction["operation"], transaction_type=transaction["operation"],
transaction_id=transaction["id"], transaction_id=transaction["id"],
filter_operation=t.CREATE, filter_operation=[t.CREATE, t.VALIDATOR_ELECTION, t.CHAIN_MIGRATION_ELECTION],
asset=asset, asset=asset,
) )

View File

@ -108,6 +108,8 @@ class ValidationWorker:
asset_id = dict_transaction["asset"]["id"] asset_id = dict_transaction["asset"]["id"]
except KeyError: except KeyError:
asset_id = dict_transaction["id"] asset_id = dict_transaction["id"]
except TypeError:
asset_id = dict_transaction["id"]
transaction = self.planetmint.is_valid_transaction(dict_transaction, self.validated_transactions[asset_id]) transaction = self.planetmint.is_valid_transaction(dict_transaction, self.validated_transactions[asset_id])

View File

@ -69,16 +69,9 @@ definitions:
- CHAIN_MIGRATION_ELECTION - CHAIN_MIGRATION_ELECTION
- VOTE - VOTE
asset: asset:
type: object anyOf:
additionalProperties: false - type: 'null'
properties: - type: object
id:
"$ref": "#/definitions/sha3_hexdigest"
data:
anyOf:
- type: object
additionalProperties: true
- type: 'null'
output: output:
type: object type: object
additionalProperties: false additionalProperties: false
@ -135,9 +128,7 @@ definitions:
- type: 'null' - type: 'null'
metadata: metadata:
anyOf: anyOf:
- type: object - type: string
additionalProperties: true
minProperties: 1
- type: 'null' - type: 'null'
condition_details: condition_details:
anyOf: anyOf:

View File

@ -16,8 +16,7 @@ properties:
properties: properties:
data: data:
anyOf: anyOf:
- type: object - type: string
additionalProperties: true
- type: 'null' - type: 'null'
required: required:
- data - data

View File

@ -73,16 +73,9 @@ definitions:
- COMPOSE - COMPOSE
- DECOMPOSE - DECOMPOSE
asset: asset:
type: object anyOf:
additionalProperties: false - type: 'null'
properties: - type: object
id:
"$ref": "#/definitions/sha3_hexdigest"
data:
anyOf:
- type: object
additionalProperties: true
- type: 'null'
output: output:
type: object type: object
additionalProperties: false additionalProperties: false
@ -139,9 +132,7 @@ definitions:
- type: 'null' - type: 'null'
metadata: metadata:
anyOf: anyOf:
- type: object - type: string
additionalProperties: true
minProperties: 1
- type: 'null' - type: 'null'
condition_details: condition_details:
anyOf: anyOf:

View File

@ -35,8 +35,7 @@ definitions:
properties: properties:
data: data:
anyOf: anyOf:
- type: object - type: string
additionalProperties: true
- type: 'null' - type: 'null'
required: required:
- data - data

View File

@ -57,6 +57,10 @@ UnspentOutput = namedtuple(
), ),
) )
VALIDATOR_ELECTION = "VALIDATOR_ELECTION"
CHAIN_MIGRATION_ELECTION = "CHAIN_MIGRATION_ELECTION"
VOTE = "VOTE"
class Transaction(object): class Transaction(object):
"""A Transaction is used to create and transfer assets. """A Transaction is used to create and transfer assets.
@ -83,6 +87,9 @@ class Transaction(object):
CREATE = "CREATE" CREATE = "CREATE"
TRANSFER = "TRANSFER" TRANSFER = "TRANSFER"
VALIDATOR_ELECTION = VALIDATOR_ELECTION
CHAIN_MIGRATION_ELECTION = CHAIN_MIGRATION_ELECTION
VOTE = VOTE
ALLOWED_OPERATIONS = (CREATE, TRANSFER) ALLOWED_OPERATIONS = (CREATE, TRANSFER)
ASSET = "asset" ASSET = "asset"
METADATA = "metadata" METADATA = "metadata"
@ -127,13 +134,25 @@ class Transaction(object):
# Asset payloads for 'CREATE' operations must be None or # Asset payloads for 'CREATE' operations must be None or
# dicts holding a `data` property. Asset payloads for 'TRANSFER' # dicts holding a `data` property. Asset payloads for 'TRANSFER'
# operations must be dicts holding an `id` property. # operations must be dicts holding an `id` property.
if operation == self.CREATE and asset is not None and not (isinstance(asset, dict) and "data" in asset): if operation == self.CREATE and asset is not None:
raise TypeError( if not isinstance(asset, dict):
( raise TypeError(
"`asset` must be None or a dict holding a `data` " (
" property instance for '{}' Transactions".format(operation) "`asset` must be None or a dict holding a `data` "
" property instance for '{}' Transactions".format(operation)
)
) )
)
if "data" in asset:
if asset["data"] is not None and not isinstance(asset["data"], str):
# add check if data is ipld marshalled CID string
raise TypeError(
(
"`asset` must be None or a dict holding a `data` "
" property instance for '{}' Transactions".format(operation)
)
)
elif operation == self.TRANSFER and not (isinstance(asset, dict) and "id" in asset): elif operation == self.TRANSFER and not (isinstance(asset, dict) and "id" in asset):
raise TypeError(("`asset` must be a dict holding an `id` property " "for 'TRANSFER' Transactions")) raise TypeError(("`asset` must be a dict holding an `id` property " "for 'TRANSFER' Transactions"))
@ -143,8 +162,9 @@ class Transaction(object):
if inputs and not isinstance(inputs, list): if inputs and not isinstance(inputs, list):
raise TypeError("`inputs` must be a list instance or None") raise TypeError("`inputs` must be a list instance or None")
if metadata is not None and not isinstance(metadata, dict): if metadata is not None and not isinstance(metadata, str):
raise TypeError("`metadata` must be a dict or None") # Add CID validation
raise TypeError("`metadata` must be a CID string or None")
if script is not None and not isinstance(script, dict): if script is not None and not isinstance(script, dict):
raise TypeError("`script` must be a dict or None") raise TypeError("`script` must be a dict or None")
@ -490,6 +510,10 @@ class Transaction(object):
return self._inputs_valid(["dummyvalue" for _ in self.inputs]) return self._inputs_valid(["dummyvalue" for _ in self.inputs])
elif self.operation == self.TRANSFER: elif self.operation == self.TRANSFER:
return self._inputs_valid([output.fulfillment.condition_uri for output in outputs]) return self._inputs_valid([output.fulfillment.condition_uri for output in outputs])
elif self.operation == self.VALIDATOR_ELECTION:
return self._inputs_valid(["dummyvalue" for _ in self.inputs])
elif self.operation == self.CHAIN_MIGRATION_ELECTION:
return self._inputs_valid(["dummyvalue" for _ in self.inputs])
else: else:
allowed_ops = ", ".join(self.__class__.ALLOWED_OPERATIONS) allowed_ops = ", ".join(self.__class__.ALLOWED_OPERATIONS)
raise TypeError("`operation` must be one of {}".format(allowed_ops)) raise TypeError("`operation` must be one of {}".format(allowed_ops))
@ -561,7 +585,7 @@ class Transaction(object):
print(f"Exception ASN1EncodeError : {e}") print(f"Exception ASN1EncodeError : {e}")
return False return False
if operation == self.CREATE: if operation in [self.CREATE, self.CHAIN_MIGRATION_ELECTION, self.VALIDATOR_ELECTION]:
# NOTE: In the case of a `CREATE` transaction, the # NOTE: In the case of a `CREATE` transaction, the
# output is always valid. # output is always valid.
output_valid = True output_valid = True
@ -680,7 +704,9 @@ class Transaction(object):
transactions = [transactions] transactions = [transactions]
# create a set of the transactions' asset ids # create a set of the transactions' asset ids
asset_ids = {tx.id if tx.operation == tx.CREATE else tx.asset["id"] for tx in transactions} asset_ids = {
tx.id if tx.operation in [tx.CREATE, tx.VALIDATOR_ELECTION] else tx.asset["id"] for tx in transactions
}
# check that all the transasctions have the same asset id # check that all the transasctions have the same asset id
if len(asset_ids) > 1: if len(asset_ids) > 1:
@ -887,3 +913,22 @@ class Transaction(object):
raise InvalidSignature("Transaction signature is invalid.") raise InvalidSignature("Transaction signature is invalid.")
return True return True
@classmethod
def complete_tx_i_o(self, tx_signers, recipients):
inputs = []
outputs = []
# generate_outputs
for recipient in recipients:
if not isinstance(recipient, tuple) or len(recipient) != 2:
raise ValueError(
("Each `recipient` in the list must be a" " tuple of `([<list of public keys>]," " <amount>)`")
)
pub_keys, amount = recipient
outputs.append(Output.generate(pub_keys, amount))
# generate inputs
inputs.append(Input.generate(tx_signers))
return (inputs, outputs)

View File

@ -23,27 +23,19 @@ class Create(Transaction):
raise ValueError("`tx_signers` list cannot be empty") raise ValueError("`tx_signers` list cannot be empty")
if len(recipients) == 0: if len(recipients) == 0:
raise ValueError("`recipients` list cannot be empty") raise ValueError("`recipients` list cannot be empty")
if not (asset is None or isinstance(asset, dict)): if not asset is None:
raise TypeError("`asset` must be a dict or None") if not isinstance(asset, dict):
if not (metadata is None or isinstance(metadata, dict)): raise TypeError("`asset` must be a CID string or None")
raise TypeError("`metadata` must be a dict or None") if "data" in asset and not isinstance(asset["data"], str):
raise TypeError("`asset` must be a CID string or None")
import cid
inputs = [] cid.make_cid(asset["data"])
outputs = [] if not (metadata is None or isinstance(metadata, str)):
# add check if metadata is ipld marshalled CID string
raise TypeError("`metadata` must be a CID string or None")
# generate_outputs return True
for recipient in recipients:
if not isinstance(recipient, tuple) or len(recipient) != 2:
raise ValueError(
("Each `recipient` in the list must be a" " tuple of `([<list of public keys>]," " <amount>)`")
)
pub_keys, amount = recipient
outputs.append(Output.generate(pub_keys, amount))
# generate inputs
inputs.append(Input.generate(tx_signers))
return (inputs, outputs)
@classmethod @classmethod
def generate(cls, tx_signers, recipients, metadata=None, asset=None): def generate(cls, tx_signers, recipients, metadata=None, asset=None):
@ -74,5 +66,6 @@ class Create(Transaction):
:class:`~planetmint.common.transaction.Transaction` :class:`~planetmint.common.transaction.Transaction`
""" """
(inputs, outputs) = cls.validate_create(tx_signers, recipients, asset, metadata) Create.validate_create(tx_signers, recipients, asset, metadata)
return cls(cls.OPERATION, {"data": asset}, inputs, outputs, metadata) (inputs, outputs) = Transaction.complete_tx_i_o(tx_signers, recipients)
return cls(cls.OPERATION, asset, inputs, outputs, metadata)

View File

@ -1,13 +1,14 @@
import json import json
from planetmint.transactions.common.schema import TX_SCHEMA_CHAIN_MIGRATION_ELECTION from planetmint.transactions.common.schema import TX_SCHEMA_CHAIN_MIGRATION_ELECTION
from planetmint.transactions.common.transaction import CHAIN_MIGRATION_ELECTION
from planetmint.transactions.types.elections.election import Election from planetmint.transactions.types.elections.election import Election
class ChainMigrationElection(Election): class ChainMigrationElection(Election):
OPERATION = "CHAIN_MIGRATION_ELECTION" OPERATION = CHAIN_MIGRATION_ELECTION
CREATE = OPERATION # CREATE = OPERATION
ALLOWED_OPERATIONS = (OPERATION,) ALLOWED_OPERATIONS = (OPERATION,)
TX_SCHEMA_CUSTOM = TX_SCHEMA_CHAIN_MIGRATION_ELECTION TX_SCHEMA_CUSTOM = TX_SCHEMA_CHAIN_MIGRATION_ELECTION

View File

@ -21,7 +21,7 @@ from planetmint.transactions.common.exceptions import (
from planetmint.tendermint_utils import key_from_base64, public_key_to_base64 from planetmint.tendermint_utils import key_from_base64, public_key_to_base64
from planetmint.transactions.common.crypto import public_key_from_ed25519_key from planetmint.transactions.common.crypto import public_key_from_ed25519_key
from planetmint.transactions.common.transaction import Transaction from planetmint.transactions.common.transaction import Transaction
from planetmint.transactions.common.schema import _validate_schema, TX_SCHEMA_COMMON, TX_SCHEMA_CREATE from planetmint.transactions.common.schema import _validate_schema, TX_SCHEMA_COMMON
class Election(Transaction): class Election(Transaction):
@ -94,6 +94,25 @@ class Election(Transaction):
# validators and their voting power in the network # validators and their voting power in the network
return current_topology == voters return current_topology == voters
@classmethod
def validate_election(self, tx_signers, recipients, asset, metadata):
if not isinstance(tx_signers, list):
raise TypeError("`tx_signers` must be a list instance")
if not isinstance(recipients, list):
raise TypeError("`recipients` must be a list instance")
if len(tx_signers) == 0:
raise ValueError("`tx_signers` list cannot be empty")
if len(recipients) == 0:
raise ValueError("`recipients` list cannot be empty")
if not asset is None:
if not isinstance(asset, dict):
raise TypeError("`asset` must be a CID string or None")
if not (metadata is None or isinstance(metadata, str)):
# add check if metadata is ipld marshalled CID string
raise TypeError("`metadata` must be a CID string or None")
return True
def validate(self, planet, current_transactions=[]): def validate(self, planet, current_transactions=[]):
"""Validate election transaction """Validate election transaction
@ -145,7 +164,8 @@ class Election(Transaction):
uuid = uuid4() uuid = uuid4()
election_data["seed"] = str(uuid) election_data["seed"] = str(uuid)
(inputs, outputs) = Create.validate_create(initiator, voters, election_data, metadata) Election.validate_election(initiator, voters, election_data, metadata)
(inputs, outputs) = Transaction.complete_tx_i_o(initiator, voters)
election = cls(cls.OPERATION, {"data": election_data}, inputs, outputs, metadata) election = cls(cls.OPERATION, {"data": election_data}, inputs, outputs, metadata)
cls.validate_schema(election.to_dict()) cls.validate_schema(election.to_dict())
return election return election
@ -156,7 +176,6 @@ class Election(Transaction):
`CREATE` transaction should be inherited `CREATE` transaction should be inherited
""" """
_validate_schema(TX_SCHEMA_COMMON, tx) _validate_schema(TX_SCHEMA_COMMON, tx)
_validate_schema(TX_SCHEMA_CREATE, tx)
if cls.TX_SCHEMA_CUSTOM: if cls.TX_SCHEMA_CUSTOM:
_validate_schema(cls.TX_SCHEMA_CUSTOM, tx) _validate_schema(cls.TX_SCHEMA_CUSTOM, tx)

View File

@ -5,6 +5,7 @@
from planetmint.transactions.types.assets.create import Create from planetmint.transactions.types.assets.create import Create
from planetmint.transactions.types.assets.transfer import Transfer from planetmint.transactions.types.assets.transfer import Transfer
from planetmint.transactions.common.transaction import VOTE
from planetmint.transactions.common.schema import ( from planetmint.transactions.common.schema import (
_validate_schema, _validate_schema,
TX_SCHEMA_COMMON, TX_SCHEMA_COMMON,
@ -15,7 +16,7 @@ from planetmint.transactions.common.schema import (
class Vote(Transfer): class Vote(Transfer):
OPERATION = "VOTE" OPERATION = VOTE
# NOTE: This class inherits TRANSFER txn type. The `TRANSFER` property is # NOTE: This class inherits TRANSFER txn type. The `TRANSFER` property is
# overriden to re-use methods from parent class # overriden to re-use methods from parent class
TRANSFER = OPERATION TRANSFER = OPERATION

View File

@ -6,15 +6,16 @@
from planetmint.transactions.common.exceptions import InvalidPowerChange from planetmint.transactions.common.exceptions import InvalidPowerChange
from planetmint.transactions.types.elections.election import Election from planetmint.transactions.types.elections.election import Election
from planetmint.transactions.common.schema import TX_SCHEMA_VALIDATOR_ELECTION from planetmint.transactions.common.schema import TX_SCHEMA_VALIDATOR_ELECTION
from planetmint.transactions.common.transaction import VALIDATOR_ELECTION
# from planetmint.transactions.common.transaction import Transaction
from .validator_utils import new_validator_set, encode_validator, validate_asset_public_key from .validator_utils import new_validator_set, encode_validator, validate_asset_public_key
class ValidatorElection(Election): class ValidatorElection(Election):
OPERATION = "VALIDATOR_ELECTION" OPERATION = VALIDATOR_ELECTION
# NOTE: this transaction class extends create so the operation inheritence is achieved
# by renaming CREATE to VALIDATOR_ELECTION
CREATE = OPERATION
ALLOWED_OPERATIONS = (OPERATION,) ALLOWED_OPERATIONS = (OPERATION,)
TX_SCHEMA_CUSTOM = TX_SCHEMA_VALIDATOR_ELECTION TX_SCHEMA_CUSTOM = TX_SCHEMA_VALIDATOR_ELECTION

View File

@ -3,8 +3,8 @@
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
# Code is Apache-2.0 and docs are CC-BY-4.0 # Code is Apache-2.0 and docs are CC-BY-4.0
__version__ = "1.1.1" __version__ = "1.2.0"
__short_version__ = "1.1" __short_version__ = "1.2"
# Supported Tendermint versions # Supported Tendermint versions
__tm_supported_versions__ = ["0.34.15"] __tm_supported_versions__ = ["0.34.15"]

View File

@ -51,7 +51,7 @@ docs_require = [
"charset-normalizer==2.0.12", "charset-normalizer==2.0.12",
"commonmark==0.9.1", "commonmark==0.9.1",
"docutils==0.17.1", "docutils==0.17.1",
"idna", "idna==2.10", # version conflict with requests lib (required version <3)
"imagesize==1.3.0", "imagesize==1.3.0",
"importlib-metadata==4.11.3", "importlib-metadata==4.11.3",
"Jinja2==3.0.0", "Jinja2==3.0.0",
@ -129,6 +129,13 @@ install_requires = [
"werkzeug==2.0.3", "werkzeug==2.0.3",
"nest-asyncio==1.5.5", "nest-asyncio==1.5.5",
"protobuf==3.20.1", "protobuf==3.20.1",
"planetmint-ipld>=0.0.3",
"pyasn1",
"zenroom==2.1.0.dev1655293214",
"base58>=2.1.0",
"PyNaCl==1.4.0",
"pyasn1>=0.4.8",
"cryptography==3.4.7",
] ]
setup( setup(

View File

@ -51,9 +51,13 @@ def test_asset_id_mismatch(alice, user_pk):
from planetmint.transactions.common.transaction import Transaction from planetmint.transactions.common.transaction import Transaction
from planetmint.transactions.common.exceptions import AssetIdMismatch from planetmint.transactions.common.exceptions import AssetIdMismatch
tx1 = Create.generate([alice.public_key], [([user_pk], 1)], metadata={"msg": random.random()}) tx1 = Create.generate(
[alice.public_key], [([user_pk], 1)], metadata="QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"
)
tx1.sign([alice.private_key]) tx1.sign([alice.private_key])
tx2 = Create.generate([alice.public_key], [([user_pk], 1)], metadata={"msg": random.random()}) tx2 = Create.generate(
[alice.public_key], [([user_pk], 1)], metadata="zb2rhe5P4gXftAwvA4eXQ5HJwsER2owDyS9sKaQRRVQPn93bA"
)
tx2.sign([alice.private_key]) tx2.sign([alice.private_key])
with pytest.raises(AssetIdMismatch): with pytest.raises(AssetIdMismatch):

View File

@ -19,7 +19,9 @@ from planetmint.transactions.common.exceptions import DoubleSpend
# Single owners_after # Single owners_after
def test_single_in_single_own_single_out_single_own_create(alice, user_pk, b): def test_single_in_single_own_single_out_single_own_create(alice, user_pk, b):
tx = Create.generate([alice.public_key], [([user_pk], 100)], asset={"name": random.random()}) tx = Create.generate(
[alice.public_key], [([user_pk], 100)], asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
)
tx_signed = tx.sign([alice.private_key]) tx_signed = tx.sign([alice.private_key])
assert tx_signed.validate(b) == tx_signed assert tx_signed.validate(b) == tx_signed
@ -35,7 +37,11 @@ def test_single_in_single_own_single_out_single_own_create(alice, user_pk, b):
# Single owners_after per output # Single owners_after per output
def test_single_in_single_own_multiple_out_single_own_create(alice, user_pk, b): def test_single_in_single_own_multiple_out_single_own_create(alice, user_pk, b):
tx = Create.generate([alice.public_key], [([user_pk], 50), ([user_pk], 50)], asset={"name": random.random()}) tx = Create.generate(
[alice.public_key],
[([user_pk], 50), ([user_pk], 50)],
asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
)
tx_signed = tx.sign([alice.private_key]) tx_signed = tx.sign([alice.private_key])
assert tx_signed.validate(b) == tx_signed assert tx_signed.validate(b) == tx_signed
@ -52,7 +58,11 @@ def test_single_in_single_own_multiple_out_single_own_create(alice, user_pk, b):
# Multiple owners_after # Multiple owners_after
def test_single_in_single_own_single_out_multiple_own_create(alice, user_pk, b): def test_single_in_single_own_single_out_multiple_own_create(alice, user_pk, b):
tx = Create.generate([alice.public_key], [([user_pk, user_pk], 100)], asset={"name": random.random()}) tx = Create.generate(
[alice.public_key],
[([user_pk, user_pk], 100)],
asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
)
tx_signed = tx.sign([alice.private_key]) tx_signed = tx.sign([alice.private_key])
assert tx_signed.validate(b) == tx_signed assert tx_signed.validate(b) == tx_signed
@ -75,7 +85,9 @@ def test_single_in_single_own_single_out_multiple_own_create(alice, user_pk, b):
def test_single_in_single_own_multiple_out_mix_own_create(alice, user_pk, b): def test_single_in_single_own_multiple_out_mix_own_create(alice, user_pk, b):
tx = Create.generate( tx = Create.generate(
[alice.public_key], [([user_pk], 50), ([user_pk, user_pk], 50)], asset={"name": random.random()} [alice.public_key],
[([user_pk], 50), ([user_pk, user_pk], 50)],
asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
) )
tx_signed = tx.sign([alice.private_key]) tx_signed = tx.sign([alice.private_key])
@ -98,7 +110,11 @@ def test_single_in_single_own_multiple_out_mix_own_create(alice, user_pk, b):
def test_single_in_multiple_own_single_out_single_own_create(alice, b, user_pk, user_sk): def test_single_in_multiple_own_single_out_single_own_create(alice, b, user_pk, user_sk):
from planetmint.transactions.common.utils import _fulfillment_to_details from planetmint.transactions.common.utils import _fulfillment_to_details
tx = Create.generate([alice.public_key, user_pk], [([user_pk], 100)], asset={"name": random.random()}) tx = Create.generate(
[alice.public_key, user_pk],
[([user_pk], 100)],
asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
)
tx_signed = tx.sign([alice.private_key, user_sk]) tx_signed = tx.sign([alice.private_key, user_sk])
assert tx_signed.validate(b) == tx_signed assert tx_signed.validate(b) == tx_signed
assert len(tx_signed.outputs) == 1 assert len(tx_signed.outputs) == 1
@ -118,7 +134,9 @@ def test_single_in_multiple_own_single_out_single_own_create(alice, b, user_pk,
def test_single_in_single_own_single_out_single_own_transfer(alice, b, user_pk, user_sk): def test_single_in_single_own_single_out_single_own_transfer(alice, b, user_pk, user_sk):
# CREATE divisible asset # CREATE divisible asset
tx_create = Create.generate([alice.public_key], [([user_pk], 100)], asset={"name": random.random()}) tx_create = Create.generate(
[alice.public_key], [([user_pk], 100)], asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
)
tx_create_signed = tx_create.sign([alice.private_key]) tx_create_signed = tx_create.sign([alice.private_key])
# TRANSFER # TRANSFER
@ -141,7 +159,9 @@ def test_single_in_single_own_single_out_single_own_transfer(alice, b, user_pk,
def test_single_in_single_own_multiple_out_single_own_transfer(alice, b, user_pk, user_sk): def test_single_in_single_own_multiple_out_single_own_transfer(alice, b, user_pk, user_sk):
# CREATE divisible asset # CREATE divisible asset
tx_create = Create.generate([alice.public_key], [([user_pk], 100)], asset={"name": random.random()}) tx_create = Create.generate(
[alice.public_key], [([user_pk], 100)], asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
)
tx_create_signed = tx_create.sign([alice.private_key]) tx_create_signed = tx_create.sign([alice.private_key])
# TRANSFER # TRANSFER
@ -167,7 +187,9 @@ def test_single_in_single_own_multiple_out_single_own_transfer(alice, b, user_pk
def test_single_in_single_own_single_out_multiple_own_transfer(alice, b, user_pk, user_sk): def test_single_in_single_own_single_out_multiple_own_transfer(alice, b, user_pk, user_sk):
# CREATE divisible asset # CREATE divisible asset
tx_create = Create.generate([alice.public_key], [([user_pk], 100)], asset={"name": random.random()}) tx_create = Create.generate(
[alice.public_key], [([user_pk], 100)], asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
)
tx_create_signed = tx_create.sign([alice.private_key]) tx_create_signed = tx_create.sign([alice.private_key])
# TRANSFER # TRANSFER
@ -201,7 +223,9 @@ def test_single_in_single_own_single_out_multiple_own_transfer(alice, b, user_pk
def test_single_in_single_own_multiple_out_mix_own_transfer(alice, b, user_pk, user_sk): def test_single_in_single_own_multiple_out_mix_own_transfer(alice, b, user_pk, user_sk):
# CREATE divisible asset # CREATE divisible asset
tx_create = Create.generate([alice.public_key], [([user_pk], 100)], asset={"name": random.random()}) tx_create = Create.generate(
[alice.public_key], [([user_pk], 100)], asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
)
tx_create_signed = tx_create.sign([alice.private_key]) tx_create_signed = tx_create.sign([alice.private_key])
# TRANSFER # TRANSFER
@ -240,7 +264,9 @@ def test_single_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk
# CREATE divisible asset # CREATE divisible asset
tx_create = Create.generate( tx_create = Create.generate(
[alice.public_key], [([alice.public_key, user_pk], 100)], asset={"name": random.random()} [alice.public_key],
[([alice.public_key, user_pk], 100)],
asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
) )
tx_create_signed = tx_create.sign([alice.private_key]) tx_create_signed = tx_create.sign([alice.private_key])
@ -272,7 +298,9 @@ def test_single_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk
def test_multiple_in_single_own_single_out_single_own_transfer(alice, b, user_pk, user_sk): def test_multiple_in_single_own_single_out_single_own_transfer(alice, b, user_pk, user_sk):
# CREATE divisible asset # CREATE divisible asset
tx_create = Create.generate( tx_create = Create.generate(
[alice.public_key], [([user_pk], 50), ([user_pk], 50)], asset={"name": random.random()} [alice.public_key],
[([user_pk], 50), ([user_pk], 50)],
asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
) )
tx_create_signed = tx_create.sign([alice.private_key]) tx_create_signed = tx_create.sign([alice.private_key])
@ -304,7 +332,7 @@ def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_
tx_create = Create.generate( tx_create = Create.generate(
[alice.public_key], [alice.public_key],
[([user_pk, alice.public_key], 50), ([user_pk, alice.public_key], 50)], [([user_pk, alice.public_key], 50), ([user_pk, alice.public_key], 50)],
asset={"name": random.random()}, asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
) )
tx_create_signed = tx_create.sign([alice.private_key]) tx_create_signed = tx_create.sign([alice.private_key])
@ -342,7 +370,9 @@ def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(alice, b, user_pk
# CREATE divisible asset # CREATE divisible asset
tx_create = Create.generate( tx_create = Create.generate(
[alice.public_key], [([user_pk], 50), ([user_pk, alice.public_key], 50)], asset={"name": random.random()} [alice.public_key],
[([user_pk], 50), ([user_pk, alice.public_key], 50)],
asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
) )
tx_create_signed = tx_create.sign([alice.private_key]) tx_create_signed = tx_create.sign([alice.private_key])
@ -379,7 +409,9 @@ def test_muiltiple_in_mix_own_multiple_out_mix_own_transfer(alice, b, user_pk, u
# CREATE divisible asset # CREATE divisible asset
tx_create = Create.generate( tx_create = Create.generate(
[alice.public_key], [([user_pk], 50), ([user_pk, alice.public_key], 50)], asset={"name": random.random()} [alice.public_key],
[([user_pk], 50), ([user_pk, alice.public_key], 50)],
asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
) )
tx_create_signed = tx_create.sign([alice.private_key]) tx_create_signed = tx_create.sign([alice.private_key])
# TRANSFER # TRANSFER
@ -423,7 +455,9 @@ def test_multiple_in_different_transactions(alice, b, user_pk, user_sk):
# `b` creates a divisible asset and assigns 50 shares to `b` and # `b` creates a divisible asset and assigns 50 shares to `b` and
# 50 shares to `user_pk` # 50 shares to `user_pk`
tx_create = Create.generate( tx_create = Create.generate(
[alice.public_key], [([user_pk], 50), ([alice.public_key], 50)], asset={"name": random.random()} [alice.public_key],
[([user_pk], 50), ([alice.public_key], 50)],
asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
) )
tx_create_signed = tx_create.sign([alice.private_key]) tx_create_signed = tx_create.sign([alice.private_key])
@ -462,7 +496,9 @@ def test_amount_error_transfer(alice, b, user_pk, user_sk):
from planetmint.transactions.common.exceptions import AmountError from planetmint.transactions.common.exceptions import AmountError
# CREATE divisible asset # CREATE divisible asset
tx_create = Create.generate([alice.public_key], [([user_pk], 100)], asset={"name": random.random()}) tx_create = Create.generate(
[alice.public_key], [([user_pk], 100)], asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
)
tx_create_signed = tx_create.sign([alice.private_key]) tx_create_signed = tx_create.sign([alice.private_key])
b.store_bulk_transactions([tx_create_signed]) b.store_bulk_transactions([tx_create_signed])
@ -493,7 +529,11 @@ def test_threshold_same_public_key(alice, b, user_pk, user_sk):
# that does not mean that the code shouldn't work. # that does not mean that the code shouldn't work.
# CREATE divisible asset # CREATE divisible asset
tx_create = Create.generate([alice.public_key], [([user_pk, user_pk], 100)], asset={"name": random.random()}) tx_create = Create.generate(
[alice.public_key],
[([user_pk, user_pk], 100)],
asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
)
tx_create_signed = tx_create.sign([alice.private_key]) tx_create_signed = tx_create.sign([alice.private_key])
# TRANSFER # TRANSFER
@ -512,7 +552,9 @@ def test_sum_amount(alice, b, user_pk, user_sk):
# CREATE divisible asset with 3 outputs with amount 1 # CREATE divisible asset with 3 outputs with amount 1
tx_create = Create.generate( tx_create = Create.generate(
[alice.public_key], [([user_pk], 1), ([user_pk], 1), ([user_pk], 1)], asset={"name": random.random()} [alice.public_key],
[([user_pk], 1), ([user_pk], 1), ([user_pk], 1)],
asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
) )
tx_create_signed = tx_create.sign([alice.private_key]) tx_create_signed = tx_create.sign([alice.private_key])
@ -535,7 +577,9 @@ def test_sum_amount(alice, b, user_pk, user_sk):
def test_divide(alice, b, user_pk, user_sk): def test_divide(alice, b, user_pk, user_sk):
# CREATE divisible asset with 1 output with amount 3 # CREATE divisible asset with 1 output with amount 3
tx_create = Create.generate([alice.public_key], [([user_pk], 3)], asset={"name": random.random()}) tx_create = Create.generate(
[alice.public_key], [([user_pk], 3)], asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
)
tx_create_signed = tx_create.sign([alice.private_key]) tx_create_signed = tx_create.sign([alice.private_key])
# create a transfer transaction with 3 outputs and check if the amount # create a transfer transaction with 3 outputs and check if the amount

View File

@ -6,6 +6,7 @@ from zenroom import zencode_exec
from cryptoconditions.types.ed25519 import Ed25519Sha256 from cryptoconditions.types.ed25519 import Ed25519Sha256
from cryptoconditions.types.zenroom import ZenroomSha256 from cryptoconditions.types.zenroom import ZenroomSha256
from planetmint.transactions.common.crypto import generate_key_pair from planetmint.transactions.common.crypto import generate_key_pair
from ipld import multihash, marshal
CONDITION_SCRIPT = """Scenario 'ecdh': create the signature of an object CONDITION_SCRIPT = """Scenario 'ecdh': create the signature of an object
Given I have the 'keyring' Given I have the 'keyring'
@ -101,8 +102,8 @@ def test_zenroom_signing():
metadata = {"result": {"output": ["ok"]}} metadata = {"result": {"output": ["ok"]}}
token_creation_tx = { token_creation_tx = {
"operation": "CREATE", "operation": "CREATE",
"asset": {"data": {"test": "my asset"}}, "asset": {"data": multihash(marshal({"test": "my asset"}))},
"metadata": metadata, "metadata": multihash(marshal(metadata)),
"script": script_, "script": script_,
"outputs": [ "outputs": [
output, output,
@ -171,9 +172,6 @@ def test_zenroom_signing():
except ValidationError as e: except ValidationError as e:
print("Invalid transaction ({}): {}".format(type(e).__name__, e)) print("Invalid transaction ({}): {}".format(type(e).__name__, e))
assert () assert ()
except e:
print(f"Exception : {e}")
assert ()
print(f"VALIDATED : {tx_obj}") print(f"VALIDATED : {tx_obj}")
assert (tx_obj == False) is False assert (tx_obj == False) is False

View File

@ -89,7 +89,7 @@ def test_bigchain_show_config(capsys):
print(f"config : {sorted_output_config}") print(f"config : {sorted_output_config}")
# Note: This test passed previously because we were always # Note: This test passed previously because we were always
# using the default configuration parameters, but since we # using the default configuration parameters, but since we
# are running with docker-compose now and expose parameters like # are running with docker compose now and expose parameters like
# PLANETMINT_SERVER_BIND, PLANETMINT_WSSERVER_HOST, PLANETMINT_WSSERVER_ADVERTISED_HOST # PLANETMINT_SERVER_BIND, PLANETMINT_WSSERVER_HOST, PLANETMINT_WSSERVER_ADVERTISED_HOST
# the default comparison fails i.e. when config is imported at the beginning the # the default comparison fails i.e. when config is imported at the beginning the
# dict returned is different that what is expected after run_show_config # dict returned is different that what is expected after run_show_config
@ -268,10 +268,16 @@ def test_run_recover(b, alice, bob):
from planetmint.backend import query from planetmint.backend import query
tx1 = Create.generate( tx1 = Create.generate(
[alice.public_key], [([alice.public_key], 1)], asset={"cycle": "hero"}, metadata={"name": "hohenheim"} [alice.public_key],
[([alice.public_key], 1)],
asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
metadata="QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4",
).sign([alice.private_key]) ).sign([alice.private_key])
tx2 = Create.generate( tx2 = Create.generate(
[bob.public_key], [([bob.public_key], 1)], asset={"cycle": "hero"}, metadata={"name": "hohenheim"} [bob.public_key],
[([bob.public_key], 1)],
asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
metadata="QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4",
).sign([bob.private_key]) ).sign([bob.private_key])
print(tx1.id) print(tx1.id)
print(tx2.id) print(tx2.id)

View File

@ -23,9 +23,9 @@ CC_FULFILLMENT_URI = (
) )
CC_CONDITION_URI = "ni:///sha-256;" "eZI5q6j8T_fqv7xMROaei9_tmTMk4S7WR5Kr4onPHV8" "?fpt=ed25519-sha-256&cost=131072" CC_CONDITION_URI = "ni:///sha-256;" "eZI5q6j8T_fqv7xMROaei9_tmTMk4S7WR5Kr4onPHV8" "?fpt=ed25519-sha-256&cost=131072"
ASSET_DEFINITION = {"data": {"definition": "Asset definition"}} ASSET_DEFINITION = {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
DATA = {"msg": "Hello Planetmint!"} DATA = "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"
@pytest.fixture @pytest.fixture
@ -189,11 +189,7 @@ def dummy_transaction():
@pytest.fixture @pytest.fixture
def unfulfilled_transaction(): def unfulfilled_transaction():
return { return {
"asset": { "asset": {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
"data": {
"msg": "Hello Planetmint!",
}
},
"id": None, "id": None,
"inputs": [ "inputs": [
{ {
@ -229,11 +225,7 @@ def unfulfilled_transaction():
@pytest.fixture @pytest.fixture
def fulfilled_transaction(): def fulfilled_transaction():
return { return {
"asset": { "asset": {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
"data": {
"msg": "Hello Planetmint!",
}
},
"id": None, "id": None,
"inputs": [ "inputs": [
{ {
@ -292,11 +284,7 @@ def fulfilled_transaction():
) )
def tri_state_transaction(request): def tri_state_transaction(request):
tx = { tx = {
"asset": { "asset": {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
"data": {
"msg": "Hello Planetmint!",
}
},
"id": None, "id": None,
"inputs": [ "inputs": [
{"fulfillment": None, "fulfills": None, "owners_before": ["JEAkEJqLbbgDRAtMm8YAjGp759Aq2qTn9eaEHUj2XePE"]} {"fulfillment": None, "fulfills": None, "owners_before": ["JEAkEJqLbbgDRAtMm8YAjGp759Aq2qTn9eaEHUj2XePE"]}

View File

@ -17,9 +17,7 @@ pytestmark = pytest.mark.bdb
def test_memoize_to_dict(b): def test_memoize_to_dict(b):
alice = generate_key_pair() alice = generate_key_pair()
asset = { asset = {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
"data": {"id": "test_id"},
}
assert to_dict.cache_info().hits == 0 assert to_dict.cache_info().hits == 0
assert to_dict.cache_info().misses == 0 assert to_dict.cache_info().misses == 0
@ -44,9 +42,7 @@ def test_memoize_to_dict(b):
def test_memoize_from_dict(b): def test_memoize_from_dict(b):
alice = generate_key_pair() alice = generate_key_pair()
asset = { asset = {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
"data": {"id": "test_id"},
}
assert from_dict.cache_info().hits == 0 assert from_dict.cache_info().hits == 0
assert from_dict.cache_info().misses == 0 assert from_dict.cache_info().misses == 0
@ -72,9 +68,7 @@ def test_memoize_from_dict(b):
def test_memoize_input_valid(b): def test_memoize_input_valid(b):
alice = generate_key_pair() alice = generate_key_pair()
asset = { asset = {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
"data": {"id": "test_id"},
}
assert Transaction._input_valid.cache_info().hits == 0 assert Transaction._input_valid.cache_info().hits == 0
assert Transaction._input_valid.cache_info().misses == 0 assert Transaction._input_valid.cache_info().misses == 0

View File

@ -259,7 +259,9 @@ def test_invalid_transaction_initialization(asset_definition):
with raises(TypeError): with raises(TypeError):
Transaction(operation="CREATE", asset=asset_definition, outputs=[], inputs="invalid inputs") Transaction(operation="CREATE", asset=asset_definition, outputs=[], inputs="invalid inputs")
with raises(TypeError): with raises(TypeError):
Transaction(operation="CREATE", asset=asset_definition, outputs=[], inputs=[], metadata="invalid metadata") Transaction(
operation="CREATE", asset=asset_definition, outputs=[], inputs=[], metadata={"data": "invalid metadata"}
)
def test_create_default_asset_on_tx_initialization(asset_definition): def test_create_default_asset_on_tx_initialization(asset_definition):
@ -576,7 +578,7 @@ def test_create_create_transaction_single_io(user_output, user_pub, data):
"version": Transaction.VERSION, "version": Transaction.VERSION,
} }
tx = Create.generate([user_pub], [([user_pub], 1)], metadata=data, asset=data) tx = Create.generate([user_pub], [([user_pub], 1)], metadata=data, asset={"data": data})
tx_dict = tx.to_dict() tx_dict = tx.to_dict()
tx_dict["inputs"][0]["fulfillment"] = None tx_dict["inputs"][0]["fulfillment"] = None
tx_dict.pop("id") tx_dict.pop("id")
@ -600,13 +602,15 @@ def test_create_create_transaction_multiple_io(user_output, user2_output, user_p
input = Input.generate([user_pub, user2_pub]).to_dict() input = Input.generate([user_pub, user2_pub]).to_dict()
expected = { expected = {
"outputs": [user_output.to_dict(), user2_output.to_dict()], "outputs": [user_output.to_dict(), user2_output.to_dict()],
"metadata": {"message": "hello"}, "metadata": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4",
"inputs": [input], "inputs": [input],
"operation": "CREATE", "operation": "CREATE",
"version": Transaction.VERSION, "version": Transaction.VERSION,
} }
tx = Create.generate( tx = Create.generate(
[user_pub, user2_pub], [([user_pub], 1), ([user2_pub], 1)], metadata={"message": "hello"} [user_pub, user2_pub],
[([user_pub], 1), ([user2_pub], 1)],
metadata="QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4",
).to_dict() ).to_dict()
tx.pop("id") tx.pop("id")
tx.pop("asset") tx.pop("asset")
@ -617,7 +621,11 @@ def test_create_create_transaction_multiple_io(user_output, user2_output, user_p
def test_validate_multiple_io_create_transaction(user_pub, user_priv, user2_pub, user2_priv, asset_definition): def test_validate_multiple_io_create_transaction(user_pub, user_priv, user2_pub, user2_priv, asset_definition):
from .utils import validate_transaction_model from .utils import validate_transaction_model
tx = Create.generate([user_pub, user2_pub], [([user_pub], 1), ([user2_pub], 1)], metadata={"message": "hello"}) tx = Create.generate(
[user_pub, user2_pub],
[([user_pub], 1), ([user2_pub], 1)],
metadata="QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4",
)
tx = tx.sign([user_priv, user2_priv]) tx = tx.sign([user_priv, user2_priv])
assert tx.inputs_valid() is True assert tx.inputs_valid() is True
@ -645,7 +653,7 @@ def test_create_create_transaction_threshold(
"operation": "CREATE", "operation": "CREATE",
"version": Transaction.VERSION, "version": Transaction.VERSION,
} }
tx = Create.generate([user_pub], [([user_pub, user2_pub], 1)], metadata=data, asset=data) tx = Create.generate([user_pub], [([user_pub, user2_pub], 1)], metadata=data, asset={"data": data})
tx_dict = tx.to_dict() tx_dict = tx.to_dict()
tx_dict.pop("id") tx_dict.pop("id")
tx_dict["inputs"][0]["fulfillment"] = None tx_dict["inputs"][0]["fulfillment"] = None
@ -677,9 +685,9 @@ def test_create_create_transaction_with_invalid_parameters(user_pub):
with raises(ValueError): with raises(ValueError):
Create.generate([user_pub], [([user_pub],)]) Create.generate([user_pub], [([user_pub],)])
with raises(TypeError): with raises(TypeError):
Create.generate([user_pub], [([user_pub], 1)], metadata="not a dict or none") Create.generate([user_pub], [([user_pub], 1)], metadata={"data": "not a dict or none"})
with raises(TypeError): with raises(ValueError):
Create.generate([user_pub], [([user_pub], 1)], asset="not a dict or none") Create.generate([user_pub], [([user_pub], 1)], asset={"data": "not a dict or none"})
def test_outputs_to_inputs(tx): def test_outputs_to_inputs(tx):
@ -741,7 +749,9 @@ def test_create_transfer_transaction_single_io(tx, user_pub, user2_pub, user2_ou
def test_create_transfer_transaction_multiple_io( def test_create_transfer_transaction_multiple_io(
user_pub, user_priv, user2_pub, user2_priv, user3_pub, user2_output, asset_definition user_pub, user_priv, user2_pub, user2_priv, user3_pub, user2_output, asset_definition
): ):
tx = Create.generate([user_pub], [([user_pub], 1), ([user2_pub], 1)], metadata={"message": "hello"}) tx = Create.generate(
[user_pub], [([user_pub], 1), ([user2_pub], 1)], metadata="QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"
)
tx = tx.sign([user_priv]) tx = tx.sign([user_priv])
expected = { expected = {
@ -794,7 +804,7 @@ def test_create_transfer_with_invalid_parameters(tx, user_pub):
with raises(ValueError): with raises(ValueError):
Transfer.generate(["fulfillment"], [([user_pub],)], tx.id) Transfer.generate(["fulfillment"], [([user_pub],)], tx.id)
with raises(TypeError): with raises(TypeError):
Transfer.generate(["fulfillment"], [([user_pub], 1)], tx.id, metadata="not a dict or none") Transfer.generate(["fulfillment"], [([user_pub], 1)], tx.id, metadata={"data": "not a cid string or none"})
with raises(TypeError): with raises(TypeError):
Transfer.generate(["fulfillment"], [([user_pub], 1)], ["not a string"]) Transfer.generate(["fulfillment"], [([user_pub], 1)], ["not a string"])
@ -851,7 +861,7 @@ def test_unspent_outputs_property(merlin, alice, bob, carol):
tx = Create.generate( tx = Create.generate(
[merlin.public_key], [merlin.public_key],
[([alice.public_key], 1), ([bob.public_key], 2), ([carol.public_key], 3)], [([alice.public_key], 1), ([bob.public_key], 2), ([carol.public_key], 3)],
asset={"hash": "06e47bcf9084f7ecfd2a2a2ad275444a"}, asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
).sign([merlin.private_key]) ).sign([merlin.private_key])
unspent_outputs = list(tx.unspent_outputs) unspent_outputs = list(tx.unspent_outputs)
assert len(unspent_outputs) == 3 assert len(unspent_outputs) == 3

View File

@ -15,6 +15,7 @@ import copy
import random import random
import tempfile import tempfile
import codecs import codecs
from ipld import marshal, multihash
from collections import namedtuple from collections import namedtuple
from logging import getLogger from logging import getLogger
from logging.config import dictConfig from logging.config import dictConfig
@ -287,7 +288,8 @@ def create_tx(alice, user_pk):
from planetmint.transactions.types.assets.create import Create from planetmint.transactions.types.assets.create import Create
name = f"I am created by the create_tx fixture. My random identifier is {random.random()}." name = f"I am created by the create_tx fixture. My random identifier is {random.random()}."
return Create.generate([alice.public_key], [([user_pk], 1)], asset={"name": name}) asset = {"data": multihash(marshal({"name": name}))}
return Create.generate([alice.public_key], [([user_pk], 1)], asset=asset)
@pytest.fixture @pytest.fixture
@ -333,9 +335,7 @@ def inputs(user_pk, b, alice):
for height in range(1, 4): for height in range(1, 4):
transactions = [ transactions = [
Create.generate( Create.generate(
[alice.public_key], [alice.public_key], [([user_pk], 1)], metadata=multihash(marshal({"data": f"{random.random()}"}))
[([user_pk], 1)],
metadata={"msg": random.random()},
).sign([alice.private_key]) ).sign([alice.private_key])
for _ in range(10) for _ in range(10)
] ]

View File

@ -6,7 +6,7 @@ import warnings
from unittest.mock import patch from unittest.mock import patch
from planetmint.transactions.types.assets.create import Create from planetmint.transactions.types.assets.create import Create
from planetmint.transactions.types.assets.transfer import Transfer from planetmint.transactions.types.assets.transfer import Transfer
from ipld import marshal, multihash
import pytest import pytest
from base58 import b58decode from base58 import b58decode
@ -65,9 +65,9 @@ class TestBigchainApi(object):
return return
# define the assets # define the assets
asset1 = {"msg": "Planetmint 1"} asset1 = {"data": multihash(marshal({"msg": "Planetmint 1"}))}
asset2 = {"msg": "Planetmint 2"} asset2 = {"data": multihash(marshal({"msg": "Planetmint 2"}))}
asset3 = {"msg": "Planetmint 3"} asset3 = {"data": multihash(marshal({"msg": "Planetmint 3"}))}
# create the transactions # create the transactions
tx1 = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset1).sign([alice.private_key]) tx1 = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset1).sign([alice.private_key])
@ -79,7 +79,7 @@ class TestBigchainApi(object):
# get the assets through text search # get the assets through text search
assets = list(b.text_search("planetmint")) assets = list(b.text_search("planetmint"))
assert len(assets) == 3 assert len(assets) == 0
@pytest.mark.usefixtures("inputs") @pytest.mark.usefixtures("inputs")
def test_non_create_input_not_found(self, b, user_pk): def test_non_create_input_not_found(self, b, user_pk):
@ -97,7 +97,7 @@ class TestBigchainApi(object):
def test_write_transaction(self, b, user_sk, user_pk, alice, create_tx): def test_write_transaction(self, b, user_sk, user_pk, alice, create_tx):
asset1 = {"msg": "Planetmint 1"} asset1 = {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset1).sign([alice.private_key]) tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset1).sign([alice.private_key])
b.store_bulk_transactions([tx]) b.store_bulk_transactions([tx])
@ -377,7 +377,7 @@ class TestMultipleInputs(object):
transactions = [] transactions = []
for i in range(3): for i in range(3):
payload = {"somedata": i} payload = f"QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L{i}" # create unique CIDs
tx = Create.generate([alice.public_key], [([user_pk, user2_pk], 1)], payload) tx = Create.generate([alice.public_key], [([user_pk, user2_pk], 1)], payload)
tx = tx.sign([alice.private_key]) tx = tx.sign([alice.private_key])
transactions.append(tx) transactions.append(tx)
@ -472,12 +472,15 @@ def test_transaction_unicode(b, alice):
from planetmint.transactions.common.utils import serialize from planetmint.transactions.common.utils import serialize
# http://www.fileformat.info/info/unicode/char/1f37a/index.htm # http://www.fileformat.info/info/unicode/char/1f37a/index.htm
beer_python = {"beer": "\N{BEER MUG}"}
beer_json = '{"beer":"\N{BEER MUG}"}'
tx = (Create.generate([alice.public_key], [([alice.public_key], 100)], beer_python)).sign([alice.private_key]) beer_python = {"data": multihash(marshal({"beer": "\N{BEER MUG}"}))}
beer_json = {"data": multihash(marshal({"beer": "\N{BEER MUG}"}))}
tx = (Create.generate([alice.public_key], [([alice.public_key], 100)], asset=beer_python)).sign(
[alice.private_key]
)
tx_1 = copy.deepcopy(tx) tx_1 = copy.deepcopy(tx)
b.store_bulk_transactions([tx]) b.store_bulk_transactions([tx])
assert beer_json in serialize(tx_1.to_dict()) assert beer_json["data"] in serialize(tx_1.to_dict())

View File

@ -299,7 +299,7 @@ def test_deliver_transfer_tx__double_spend_fails(b, init_chain_request):
bob = generate_key_pair() bob = generate_key_pair()
carly = generate_key_pair() carly = generate_key_pair()
asset = {"msg": "live long and prosper"} asset = {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset).sign([alice.private_key]) tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset).sign([alice.private_key])
@ -355,9 +355,9 @@ def test_store_pre_commit_state_in_end_block(b, alice, init_chain_request):
from planetmint import App from planetmint import App
from planetmint.backend import query from planetmint.backend import query
tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset={"msg": "live long and prosper"}).sign( tx = Create.generate(
[alice.private_key] [alice.public_key], [([alice.public_key], 1)], asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
) ).sign([alice.private_key])
app = App(b) app = App(b)
app.init_chain(init_chain_request) app.init_chain(init_chain_request)

View File

@ -25,6 +25,7 @@ from planetmint.transactions.common.transaction_mode_types import (
BROADCAST_TX_SYNC, BROADCAST_TX_SYNC,
) )
from planetmint.lib import Block from planetmint.lib import Block
from ipld import marshal, multihash
@pytest.mark.bdb @pytest.mark.bdb
@ -40,15 +41,21 @@ def test_asset_is_separated_from_transaciton(b):
bob = generate_key_pair() bob = generate_key_pair()
asset = { asset = {
"Never gonna": [ "data": multihash(
"give you up", marshal(
"let you down", {
"run around" "desert you", "Never gonna": [
"make you cry", "give you up",
"say goodbye", "let you down",
"tell a lie", "run around" "desert you",
"hurt you", "make you cry",
] "say goodbye",
"tell a lie",
"hurt you",
]
}
)
)
} }
tx = Create.generate([alice.public_key], [([bob.public_key], 1)], metadata=None, asset=asset).sign( tx = Create.generate([alice.public_key], [([bob.public_key], 1)], metadata=None, asset=asset).sign(
@ -404,7 +411,7 @@ def test_get_spent_transaction_critical_double_spend(b, alice, bob, carol):
from planetmint.exceptions import CriticalDoubleSpend from planetmint.exceptions import CriticalDoubleSpend
from planetmint.transactions.common.exceptions import DoubleSpend from planetmint.transactions.common.exceptions import DoubleSpend
asset = {"test": "asset"} asset = {"data": multihash(marshal({"test": "asset"}))}
tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset).sign([alice.private_key]) tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset).sign([alice.private_key])

View File

@ -20,6 +20,7 @@ from unittest.mock import MagicMock
from planetmint.transactions.common.exceptions import AmountError, SchemaValidationError, ThresholdTooDeep from planetmint.transactions.common.exceptions import AmountError, SchemaValidationError, ThresholdTooDeep
from planetmint.transactions.common.transaction import Transaction from planetmint.transactions.common.transaction import Transaction
from planetmint.transactions.common.utils import _fulfillment_to_details, _fulfillment_from_details from planetmint.transactions.common.utils import _fulfillment_to_details, _fulfillment_from_details
from ipld import marshal, multihash
################################################################################ ################################################################################
# Helper functions # Helper functions
@ -85,7 +86,7 @@ def test_validate_invalid_operation(b, create_tx, alice):
def test_validate_fails_metadata_empty_dict(b, create_tx, alice): def test_validate_fails_metadata_empty_dict(b, create_tx, alice):
create_tx.metadata = {"a": 1} create_tx.metadata = multihash(marshal({"a": 1}))
signed_tx = create_tx.sign([alice.private_key]) signed_tx = create_tx.sign([alice.private_key])
validate(signed_tx) validate(signed_tx)
@ -129,9 +130,10 @@ def test_create_tx_no_asset_id(b, create_tx, alice):
def test_create_tx_asset_type(b, create_tx, alice): def test_create_tx_asset_type(b, create_tx, alice):
create_tx.asset["data"] = "a" create_tx.asset["data"] = multihash(marshal({"a": ""}))
signed_tx = create_tx.sign([alice.private_key]) signed_tx = create_tx.sign([alice.private_key])
validate_raises(signed_tx) validate(signed_tx)
# validate_raises(signed_tx)
def test_create_tx_no_asset_data(b, create_tx, alice): def test_create_tx_no_asset_data(b, create_tx, alice):

View File

@ -5,6 +5,7 @@
import pytest import pytest
from planetmint.transactions.types.assets.create import Create from planetmint.transactions.types.assets.create import Create
from ipld import marshal, multihash
ASSETS_ENDPOINT = "/api/v1/assets/" ASSETS_ENDPOINT = "/api/v1/assets/"
@ -29,24 +30,24 @@ def test_get_assets_tendermint(client, b, alice):
assert res.status_code == 200 assert res.status_code == 200
# create asset # create asset
asset = {"msg": "abc"} asset = {"data": multihash(marshal({"msg": "abc"}))}
tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset).sign([alice.private_key]) tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset).sign([alice.private_key])
b.store_bulk_transactions([tx]) b.store_bulk_transactions([tx])
# test that asset is returned # test that asset is returned
res = client.get(ASSETS_ENDPOINT + "?search=abc") res = client.get(ASSETS_ENDPOINT + "?search=" + asset["data"])
assert res.status_code == 200 assert res.status_code == 200
assert len(res.json) == 1 assert len(res.json) == 1
assert res.json[0] == {"data": {"msg": "abc"}, "id": tx.id} assert res.json[0] == {"data": asset["data"], "id": tx.id}
@pytest.mark.bdb @pytest.mark.bdb
def test_get_assets_limit_tendermint(client, b, alice): def test_get_assets_limit_tendermint(client, b, alice):
# create two assets # create two assets
asset1 = {"msg": "abc 1"} asset1 = {"data": multihash(marshal({"msg": "abc 1"}))}
asset2 = {"msg": "abc 2"} asset2 = {"data": multihash(marshal({"msg": "abc 2"}))}
tx1 = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset1).sign([alice.private_key]) tx1 = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset1).sign([alice.private_key])
tx2 = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset2).sign([alice.private_key]) tx2 = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset2).sign([alice.private_key])
@ -54,11 +55,11 @@ def test_get_assets_limit_tendermint(client, b, alice):
b.store_bulk_transactions([tx2]) b.store_bulk_transactions([tx2])
# test that both assets are returned without limit # test that both assets are returned without limit
res = client.get(ASSETS_ENDPOINT + "?search=abc") res = client.get(ASSETS_ENDPOINT + "?search=" + asset1["data"])
assert res.status_code == 200 assert res.status_code == 200
assert len(res.json) == 2 assert len(res.json) == 1
# test that only one asset is returned when using limit=1 # test that only one asset is returned when using limit=1
res = client.get(ASSETS_ENDPOINT + "?search=abc&limit=1") res = client.get(ASSETS_ENDPOINT + "?search=" + asset1["data"] + "&limit=1")
assert res.status_code == 200 assert res.status_code == 200
assert len(res.json) == 1 assert len(res.json) == 1

View File

@ -7,6 +7,7 @@ import pytest
from planetmint.transactions.types.assets.create import Create from planetmint.transactions.types.assets.create import Create
from planetmint.lib import Block from planetmint.lib import Block
from ipld import marshal, multihash
BLOCKS_ENDPOINT = "/api/v1/blocks/" BLOCKS_ENDPOINT = "/api/v1/blocks/"
@ -16,7 +17,9 @@ BLOCKS_ENDPOINT = "/api/v1/blocks/"
def test_get_block_endpoint(b, client, alice): def test_get_block_endpoint(b, client, alice):
import copy import copy
tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset={"cycle": "hero"}) tx = Create.generate(
[alice.public_key], [([alice.public_key], 1)], asset={"data": multihash(marshal({"cycle": "hero"}))}
)
tx = tx.sign([alice.private_key]) tx = tx.sign([alice.private_key])
# with store_bulk_transactions we use `insert_many` where PyMongo # with store_bulk_transactions we use `insert_many` where PyMongo
@ -47,7 +50,9 @@ def test_get_block_returns_404_if_not_found(client):
@pytest.mark.bdb @pytest.mark.bdb
def test_get_block_containing_transaction(b, client, alice): def test_get_block_containing_transaction(b, client, alice):
tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset={"cycle": "hero"}) tx = Create.generate(
[alice.public_key], [([alice.public_key], 1)], asset={"data": multihash(marshal({"cycle": "hero"}))}
)
tx = tx.sign([alice.private_key]) tx = tx.sign([alice.private_key])
b.store_bulk_transactions([tx]) b.store_bulk_transactions([tx])

View File

@ -5,6 +5,7 @@
import pytest import pytest
from planetmint.transactions.types.assets.create import Create from planetmint.transactions.types.assets.create import Create
from ipld import marshal, multihash
METADATA_ENDPOINT = "/api/v1/metadata/" METADATA_ENDPOINT = "/api/v1/metadata/"
@ -22,15 +23,15 @@ def test_get_metadata_with_missing_text_search(client):
@pytest.mark.bdb @pytest.mark.bdb
def test_get_metadata_tendermint(client, b, alice): def test_get_metadata_tendermint(client, b, alice):
asset = {"data": multihash(marshal({"msg": "abc"}))}
# test returns empty list when no assets are found # test returns empty list when no assets are found
res = client.get(METADATA_ENDPOINT + "?search=abc") res = client.get(METADATA_ENDPOINT + "?search=" + asset["data"])
assert res.json == [] assert res.json == []
assert res.status_code == 200 assert res.status_code == 200
# create asset # create asset
asset = {"msg": "abc"} # asset #= {"msg": "abc"}
metadata = {"key": "my_meta"} metadata = multihash(marshal({"key": "my_meta"}))
tx = Create.generate([alice.public_key], [([alice.public_key], 1)], metadata=metadata, asset=asset).sign( tx = Create.generate([alice.public_key], [([alice.public_key], 1)], metadata=metadata, asset=asset).sign(
[alice.private_key] [alice.private_key]
) )
@ -38,36 +39,36 @@ def test_get_metadata_tendermint(client, b, alice):
b.store_bulk_transactions([tx]) b.store_bulk_transactions([tx])
# test that metadata is returned # test that metadata is returned
res = client.get(METADATA_ENDPOINT + "?search=my_meta") res = client.get(METADATA_ENDPOINT + "?search=" + metadata)
assert res.status_code == 200 assert res.status_code == 200
assert len(res.json) == 1 assert len(res.json) == 1
assert res.json[0] == {"metadata": {"key": "my_meta"}, "id": tx.id} assert res.json[0] == {"metadata": metadata, "id": tx.id}
@pytest.mark.bdb @pytest.mark.bdb
def test_get_metadata_limit_tendermint(client, b, alice): def test_get_metadata_limit_tendermint(client, b, alice):
# create two assets # create two assets
asset1 = {"msg": "abc 1"} asset1 = {"data": multihash(marshal({"msg": "abc 1"}))}
meta1 = {"key": "meta 1"} meta1 = multihash(marshal({"key": "meta 1"}))
tx1 = Create.generate([alice.public_key], [([alice.public_key], 1)], metadata=meta1, asset=asset1).sign( tx1 = Create.generate([alice.public_key], [([alice.public_key], 1)], metadata=meta1, asset=asset1).sign(
[alice.private_key] [alice.private_key]
) )
b.store_bulk_transactions([tx1]) b.store_bulk_transactions([tx1])
asset2 = {"msg": "abc 2"} asset2 = {"data": multihash(marshal({"msg": "abc 2"}))}
meta2 = {"key": "meta 2"} meta2 = multihash(marshal({"key": "meta 2"}))
tx2 = Create.generate([alice.public_key], [([alice.public_key], 1)], metadata=meta2, asset=asset2).sign( tx2 = Create.generate([alice.public_key], [([alice.public_key], 1)], metadata=meta2, asset=asset2).sign(
[alice.private_key] [alice.private_key]
) )
b.store_bulk_transactions([tx2]) b.store_bulk_transactions([tx2])
# test that both assets are returned without limit # test that both assets are returned without limit
res = client.get(METADATA_ENDPOINT + "?search=meta") res = client.get(METADATA_ENDPOINT + "?search=" + meta1)
assert res.status_code == 200 assert res.status_code == 200
assert len(res.json) == 2 assert len(res.json) == 1
# test that only one asset is returned when using limit=1 # test that only one asset is returned when using limit=1
res = client.get(METADATA_ENDPOINT + "?search=meta&limit=1") res = client.get(METADATA_ENDPOINT + "?search=" + meta2 + "&limit=1")
assert res.status_code == 200 assert res.status_code == 200
assert len(res.json) == 1 assert len(res.json) == 1

View File

@ -9,6 +9,7 @@ from unittest.mock import Mock, patch
import base58 import base58
import pytest import pytest
from cryptoconditions import Ed25519Sha256 from cryptoconditions import Ed25519Sha256
from ipld import multihash, marshal
try: try:
from hashlib import sha3_256 from hashlib import sha3_256
@ -108,7 +109,7 @@ def test_post_create_transaction_with_language(b, client, nested, language, expe
asset = {"root": lang_obj} asset = {"root": lang_obj}
else: else:
asset = lang_obj asset = lang_obj
asset = {"data": multihash(marshal(asset))}
tx = Create.generate([user_pub], [([user_pub], 1)], asset=asset) tx = Create.generate([user_pub], [([user_pub], 1)], asset=asset)
tx = tx.sign([user_priv]) tx = tx.sign([user_priv])
res = client.post(TX_ENDPOINT, data=json.dumps(tx.to_dict())) res = client.post(TX_ENDPOINT, data=json.dumps(tx.to_dict()))
@ -368,7 +369,9 @@ def test_post_wrong_asset_division_transfer_returns_400(b, client, user_pk):
priv_key, pub_key = crypto.generate_key_pair() priv_key, pub_key = crypto.generate_key_pair()
create_tx = Create.generate([pub_key], [([pub_key], 10)], asset={"test": "asset"}).sign([priv_key]) create_tx = Create.generate(
[pub_key], [([pub_key], 10)], asset={"data": multihash(marshal({"test": "asset"}))}
).sign([priv_key])
res = client.post(TX_ENDPOINT + "?mode=commit", data=json.dumps(create_tx.to_dict())) res = client.post(TX_ENDPOINT + "?mode=commit", data=json.dumps(create_tx.to_dict()))
assert res.status_code == 202 assert res.status_code == 202

View File

@ -11,6 +11,7 @@ import threading
# from unittest.mock import patch # from unittest.mock import patch
from planetmint.transactions.types.assets.create import Create from planetmint.transactions.types.assets.create import Create
from planetmint.transactions.types.assets.transfer import Transfer from planetmint.transactions.types.assets.transfer import Transfer
from ipld import multihash, marshal
import pytest import pytest
@ -263,7 +264,7 @@ def test_integration_from_webapi_to_websocket(monkeypatch, client, loop):
# Create a keypair and generate a new asset # Create a keypair and generate a new asset
user_priv, user_pub = crypto.generate_key_pair() user_priv, user_pub = crypto.generate_key_pair()
asset = {"random": random.random()} asset = {"data": multihash(marshal({"random": random.random()}))}
tx = Create.generate([user_pub], [([user_pub], 1)], asset=asset) tx = Create.generate([user_pub], [([user_pub], 1)], asset=asset)
tx = tx.sign([user_priv]) tx = tx.sign([user_priv])
# Post the transaction to the Planetmint Web API # Post the transaction to the Planetmint Web API