* 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,8 +8,9 @@ on: [push, pull_request]
jobs:
test:
if: ${{ false }
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v3

View File

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

View File

@ -27,6 +27,15 @@ For reference, the possible headings are:
## [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
* **Changed** adjusted to zenroom calling convention of PRP #13 (breaking change)
* **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
@$(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
@$(DC) run --rm --no-deps planetmint pytest -f

View File

@ -17,3 +17,4 @@ RUN pip install --upgrade \
planetmint-driver>=0.9.2 \
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 planetmint-ipld>=0.0.3

View File

@ -23,6 +23,7 @@ import os
# 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_get_tests():
@ -41,7 +42,7 @@ def test_get_tests():
# ## Alice registers her bike in Planetmint
# Alice has a nice bike, and here she creates the "digital twin"
# of her bike.
bike = {"data": {"bicycle": {"serial_number": 420420}}}
bike = {"data": multihash(marshal({"bicycle": {"serial_number": 420420}}))}
# She prepares a `CREATE` transaction...
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.
from planetmint_driver import Planetmint
from planetmint_driver.crypto import generate_keypair
from ipld import multihash, marshal
def test_basic():
@ -41,7 +42,7 @@ def test_basic():
# ## Alice registers her bike in Planetmint
# Alice has a nice bike, and here she creates the "digital twin"
# of her bike.
bike = {"data": {"bicycle": {"serial_number": 420420}}}
bike = {"data": multihash(marshal({"bicycle": {"serial_number": 420420}}))}
# She prepares a `CREATE` transaction...
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.
from planetmint_driver import Planetmint
from planetmint_driver.crypto import generate_keypair
from ipld import multihash, marshal
def test_divisible_assets():
@ -48,10 +49,14 @@ def test_divisible_assets():
# the bike for one hour.
bike_token = {
"data": {
"token_for": {"bike": {"serial_number": 420420}},
"description": "Time share token. Each token equals one hour of riding.",
},
"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.

View File

@ -14,6 +14,7 @@ import queue
import planetmint_driver.exceptions
from planetmint_driver import Planetmint
from planetmint_driver.crypto import generate_keypair
from ipld import multihash, marshal
def test_double_create():
@ -23,7 +24,9 @@ def test_double_create():
results = queue.Queue()
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,
)

View File

@ -25,6 +25,7 @@ import os
# 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_multiple_owners():
@ -41,7 +42,7 @@ def test_multiple_owners():
# high rents anymore. Bob suggests to get a dish washer for the
# kitchen. Alice agrees and here they go, creating the asset for their
# dish washer.
dw_asset = {"data": {"dish washer": {"serial_number": 1337}}}
dw_asset = {"data": multihash(marshal({"dish washer": {"serial_number": 1337}}))}
# They prepare a `CREATE` transaction. To have multiple owners, both
# Bob and Alice need to be the recipients.

View File

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

View File

@ -21,6 +21,7 @@ import queue
import json
from threading import Thread, Event
from uuid import uuid4
from ipld import multihash, marshal
# For this script, we need to set up a websocket connection, that's the reason
# we import the
@ -91,7 +92,9 @@ def test_stream():
for _ in range(10):
tx = bdb.transactions.fulfill(
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,
)

View File

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

View File

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

View File

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

View File

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

View File

@ -108,6 +108,8 @@ class ValidationWorker:
asset_id = dict_transaction["asset"]["id"]
except KeyError:
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])

View File

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

View File

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

View File

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

View File

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

View File

@ -57,6 +57,10 @@ UnspentOutput = namedtuple(
),
)
VALIDATOR_ELECTION = "VALIDATOR_ELECTION"
CHAIN_MIGRATION_ELECTION = "CHAIN_MIGRATION_ELECTION"
VOTE = "VOTE"
class Transaction(object):
"""A Transaction is used to create and transfer assets.
@ -83,6 +87,9 @@ class Transaction(object):
CREATE = "CREATE"
TRANSFER = "TRANSFER"
VALIDATOR_ELECTION = VALIDATOR_ELECTION
CHAIN_MIGRATION_ELECTION = CHAIN_MIGRATION_ELECTION
VOTE = VOTE
ALLOWED_OPERATIONS = (CREATE, TRANSFER)
ASSET = "asset"
METADATA = "metadata"
@ -127,13 +134,25 @@ class Transaction(object):
# Asset payloads for 'CREATE' operations must be None or
# dicts holding a `data` property. Asset payloads for 'TRANSFER'
# 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):
raise TypeError(
(
"`asset` must be None or a dict holding a `data` "
" property instance for '{}' Transactions".format(operation)
if operation == self.CREATE and asset is not None:
if not isinstance(asset, dict):
raise TypeError(
(
"`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):
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):
raise TypeError("`inputs` must be a list instance or None")
if metadata is not None and not isinstance(metadata, dict):
raise TypeError("`metadata` must be a dict or None")
if metadata is not None and not isinstance(metadata, str):
# Add CID validation
raise TypeError("`metadata` must be a CID string or None")
if script is not None and not isinstance(script, dict):
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])
elif self.operation == self.TRANSFER:
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:
allowed_ops = ", ".join(self.__class__.ALLOWED_OPERATIONS)
raise TypeError("`operation` must be one of {}".format(allowed_ops))
@ -561,7 +585,7 @@ class Transaction(object):
print(f"Exception ASN1EncodeError : {e}")
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
# output is always valid.
output_valid = True
@ -680,7 +704,9 @@ class Transaction(object):
transactions = [transactions]
# 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
if len(asset_ids) > 1:
@ -887,3 +913,22 @@ class Transaction(object):
raise InvalidSignature("Transaction signature is invalid.")
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")
if len(recipients) == 0:
raise ValueError("`recipients` list cannot be empty")
if not (asset is None or isinstance(asset, dict)):
raise TypeError("`asset` must be a dict or None")
if not (metadata is None or isinstance(metadata, dict)):
raise TypeError("`metadata` must be a dict or None")
if not asset is None:
if not isinstance(asset, dict):
raise TypeError("`asset` must be a CID string 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 = []
outputs = []
cid.make_cid(asset["data"])
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
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)
return True
@classmethod
def generate(cls, tx_signers, recipients, metadata=None, asset=None):
@ -74,5 +66,6 @@ class Create(Transaction):
:class:`~planetmint.common.transaction.Transaction`
"""
(inputs, outputs) = cls.validate_create(tx_signers, recipients, asset, metadata)
return cls(cls.OPERATION, {"data": asset}, inputs, outputs, metadata)
Create.validate_create(tx_signers, recipients, asset, 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
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
class ChainMigrationElection(Election):
OPERATION = "CHAIN_MIGRATION_ELECTION"
CREATE = OPERATION
OPERATION = CHAIN_MIGRATION_ELECTION
# CREATE = OPERATION
ALLOWED_OPERATIONS = (OPERATION,)
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.transactions.common.crypto import public_key_from_ed25519_key
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):
@ -94,6 +94,25 @@ class Election(Transaction):
# validators and their voting power in the network
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=[]):
"""Validate election transaction
@ -145,7 +164,8 @@ class Election(Transaction):
uuid = uuid4()
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)
cls.validate_schema(election.to_dict())
return election
@ -156,7 +176,6 @@ class Election(Transaction):
`CREATE` transaction should be inherited
"""
_validate_schema(TX_SCHEMA_COMMON, tx)
_validate_schema(TX_SCHEMA_CREATE, tx)
if cls.TX_SCHEMA_CUSTOM:
_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.transfer import Transfer
from planetmint.transactions.common.transaction import VOTE
from planetmint.transactions.common.schema import (
_validate_schema,
TX_SCHEMA_COMMON,
@ -15,7 +16,7 @@ from planetmint.transactions.common.schema import (
class Vote(Transfer):
OPERATION = "VOTE"
OPERATION = VOTE
# NOTE: This class inherits TRANSFER txn type. The `TRANSFER` property is
# overriden to re-use methods from parent class
TRANSFER = OPERATION

View File

@ -6,15 +6,16 @@
from planetmint.transactions.common.exceptions import InvalidPowerChange
from planetmint.transactions.types.elections.election import 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
class ValidatorElection(Election):
OPERATION = "VALIDATOR_ELECTION"
# NOTE: this transaction class extends create so the operation inheritence is achieved
# by renaming CREATE to VALIDATOR_ELECTION
CREATE = OPERATION
OPERATION = VALIDATOR_ELECTION
ALLOWED_OPERATIONS = (OPERATION,)
TX_SCHEMA_CUSTOM = TX_SCHEMA_VALIDATOR_ELECTION

View File

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

View File

@ -51,7 +51,7 @@ docs_require = [
"charset-normalizer==2.0.12",
"commonmark==0.9.1",
"docutils==0.17.1",
"idna",
"idna==2.10", # version conflict with requests lib (required version <3)
"imagesize==1.3.0",
"importlib-metadata==4.11.3",
"Jinja2==3.0.0",
@ -129,6 +129,13 @@ install_requires = [
"werkzeug==2.0.3",
"nest-asyncio==1.5.5",
"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(

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.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])
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])
with pytest.raises(AssetIdMismatch):

View File

@ -19,7 +19,9 @@ from planetmint.transactions.common.exceptions import DoubleSpend
# Single owners_after
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])
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
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])
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
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])
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):
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])
@ -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):
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])
assert tx_signed.validate(b) == tx_signed
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):
# 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])
# 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):
# 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])
# 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):
# 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])
# 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):
# 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])
# TRANSFER
@ -240,7 +264,9 @@ def test_single_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk
# CREATE divisible asset
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])
@ -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):
# CREATE divisible asset
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])
@ -304,7 +332,7 @@ def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_
tx_create = Create.generate(
[alice.public_key],
[([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])
@ -342,7 +370,9 @@ def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(alice, b, user_pk
# CREATE divisible asset
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])
@ -379,7 +409,9 @@ def test_muiltiple_in_mix_own_multiple_out_mix_own_transfer(alice, b, user_pk, u
# CREATE divisible asset
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])
# 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
# 50 shares to `user_pk`
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])
@ -462,7 +496,9 @@ def test_amount_error_transfer(alice, b, user_pk, user_sk):
from planetmint.transactions.common.exceptions import AmountError
# 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])
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.
# 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])
# TRANSFER
@ -512,7 +552,9 @@ def test_sum_amount(alice, b, user_pk, user_sk):
# CREATE divisible asset with 3 outputs with amount 1
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])
@ -535,7 +577,9 @@ def test_sum_amount(alice, b, user_pk, user_sk):
def test_divide(alice, b, user_pk, user_sk):
# 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])
# 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.zenroom import ZenroomSha256
from planetmint.transactions.common.crypto import generate_key_pair
from ipld import multihash, marshal
CONDITION_SCRIPT = """Scenario 'ecdh': create the signature of an object
Given I have the 'keyring'
@ -101,8 +102,8 @@ def test_zenroom_signing():
metadata = {"result": {"output": ["ok"]}}
token_creation_tx = {
"operation": "CREATE",
"asset": {"data": {"test": "my asset"}},
"metadata": metadata,
"asset": {"data": multihash(marshal({"test": "my asset"}))},
"metadata": multihash(marshal(metadata)),
"script": script_,
"outputs": [
output,
@ -171,9 +172,6 @@ def test_zenroom_signing():
except ValidationError as e:
print("Invalid transaction ({}): {}".format(type(e).__name__, e))
assert ()
except e:
print(f"Exception : {e}")
assert ()
print(f"VALIDATED : {tx_obj}")
assert (tx_obj == False) is False

View File

@ -89,7 +89,7 @@ def test_bigchain_show_config(capsys):
print(f"config : {sorted_output_config}")
# Note: This test passed previously because we were always
# 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
# 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
@ -268,10 +268,16 @@ def test_run_recover(b, alice, bob):
from planetmint.backend import query
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])
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])
print(tx1.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"
ASSET_DEFINITION = {"data": {"definition": "Asset definition"}}
ASSET_DEFINITION = {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
DATA = {"msg": "Hello Planetmint!"}
DATA = "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"
@pytest.fixture
@ -189,11 +189,7 @@ def dummy_transaction():
@pytest.fixture
def unfulfilled_transaction():
return {
"asset": {
"data": {
"msg": "Hello Planetmint!",
}
},
"asset": {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
"id": None,
"inputs": [
{
@ -229,11 +225,7 @@ def unfulfilled_transaction():
@pytest.fixture
def fulfilled_transaction():
return {
"asset": {
"data": {
"msg": "Hello Planetmint!",
}
},
"asset": {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
"id": None,
"inputs": [
{
@ -292,11 +284,7 @@ def fulfilled_transaction():
)
def tri_state_transaction(request):
tx = {
"asset": {
"data": {
"msg": "Hello Planetmint!",
}
},
"asset": {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
"id": None,
"inputs": [
{"fulfillment": None, "fulfills": None, "owners_before": ["JEAkEJqLbbgDRAtMm8YAjGp759Aq2qTn9eaEHUj2XePE"]}

View File

@ -17,9 +17,7 @@ pytestmark = pytest.mark.bdb
def test_memoize_to_dict(b):
alice = generate_key_pair()
asset = {
"data": {"id": "test_id"},
}
asset = {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
assert to_dict.cache_info().hits == 0
assert to_dict.cache_info().misses == 0
@ -44,9 +42,7 @@ def test_memoize_to_dict(b):
def test_memoize_from_dict(b):
alice = generate_key_pair()
asset = {
"data": {"id": "test_id"},
}
asset = {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
assert from_dict.cache_info().hits == 0
assert from_dict.cache_info().misses == 0
@ -72,9 +68,7 @@ def test_memoize_from_dict(b):
def test_memoize_input_valid(b):
alice = generate_key_pair()
asset = {
"data": {"id": "test_id"},
}
asset = {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
assert Transaction._input_valid.cache_info().hits == 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):
Transaction(operation="CREATE", asset=asset_definition, outputs=[], inputs="invalid inputs")
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):
@ -576,7 +578,7 @@ def test_create_create_transaction_single_io(user_output, user_pub, data):
"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["inputs"][0]["fulfillment"] = None
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()
expected = {
"outputs": [user_output.to_dict(), user2_output.to_dict()],
"metadata": {"message": "hello"},
"metadata": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4",
"inputs": [input],
"operation": "CREATE",
"version": Transaction.VERSION,
}
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()
tx.pop("id")
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):
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])
assert tx.inputs_valid() is True
@ -645,7 +653,7 @@ def test_create_create_transaction_threshold(
"operation": "CREATE",
"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.pop("id")
tx_dict["inputs"][0]["fulfillment"] = None
@ -677,9 +685,9 @@ def test_create_create_transaction_with_invalid_parameters(user_pub):
with raises(ValueError):
Create.generate([user_pub], [([user_pub],)])
with raises(TypeError):
Create.generate([user_pub], [([user_pub], 1)], metadata="not a dict or none")
with raises(TypeError):
Create.generate([user_pub], [([user_pub], 1)], asset="not a dict or none")
Create.generate([user_pub], [([user_pub], 1)], metadata={"data": "not a dict or none"})
with raises(ValueError):
Create.generate([user_pub], [([user_pub], 1)], asset={"data": "not a dict or none"})
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(
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])
expected = {
@ -794,7 +804,7 @@ def test_create_transfer_with_invalid_parameters(tx, user_pub):
with raises(ValueError):
Transfer.generate(["fulfillment"], [([user_pub],)], tx.id)
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):
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(
[merlin.public_key],
[([alice.public_key], 1), ([bob.public_key], 2), ([carol.public_key], 3)],
asset={"hash": "06e47bcf9084f7ecfd2a2a2ad275444a"},
asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"},
).sign([merlin.private_key])
unspent_outputs = list(tx.unspent_outputs)
assert len(unspent_outputs) == 3

View File

@ -15,6 +15,7 @@ import copy
import random
import tempfile
import codecs
from ipld import marshal, multihash
from collections import namedtuple
from logging import getLogger
from logging.config import dictConfig
@ -287,7 +288,8 @@ def create_tx(alice, user_pk):
from planetmint.transactions.types.assets.create import Create
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
@ -333,9 +335,7 @@ def inputs(user_pk, b, alice):
for height in range(1, 4):
transactions = [
Create.generate(
[alice.public_key],
[([user_pk], 1)],
metadata={"msg": random.random()},
[alice.public_key], [([user_pk], 1)], metadata=multihash(marshal({"data": f"{random.random()}"}))
).sign([alice.private_key])
for _ in range(10)
]

View File

@ -6,7 +6,7 @@ import warnings
from unittest.mock import patch
from planetmint.transactions.types.assets.create import Create
from planetmint.transactions.types.assets.transfer import Transfer
from ipld import marshal, multihash
import pytest
from base58 import b58decode
@ -65,9 +65,9 @@ class TestBigchainApi(object):
return
# define the assets
asset1 = {"msg": "Planetmint 1"}
asset2 = {"msg": "Planetmint 2"}
asset3 = {"msg": "Planetmint 3"}
asset1 = {"data": multihash(marshal({"msg": "Planetmint 1"}))}
asset2 = {"data": multihash(marshal({"msg": "Planetmint 2"}))}
asset3 = {"data": multihash(marshal({"msg": "Planetmint 3"}))}
# create the transactions
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
assets = list(b.text_search("planetmint"))
assert len(assets) == 3
assert len(assets) == 0
@pytest.mark.usefixtures("inputs")
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):
asset1 = {"msg": "Planetmint 1"}
asset1 = {"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset=asset1).sign([alice.private_key])
b.store_bulk_transactions([tx])
@ -377,7 +377,7 @@ class TestMultipleInputs(object):
transactions = []
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 = tx.sign([alice.private_key])
transactions.append(tx)
@ -472,12 +472,15 @@ def test_transaction_unicode(b, alice):
from planetmint.transactions.common.utils import serialize
# 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)
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()
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])
@ -355,9 +355,9 @@ def test_store_pre_commit_state_in_end_block(b, alice, init_chain_request):
from planetmint import App
from planetmint.backend import query
tx = Create.generate([alice.public_key], [([alice.public_key], 1)], asset={"msg": "live long and prosper"}).sign(
[alice.private_key]
)
tx = Create.generate(
[alice.public_key], [([alice.public_key], 1)], asset={"data": "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4"}
).sign([alice.private_key])
app = App(b)
app.init_chain(init_chain_request)

View File

@ -25,6 +25,7 @@ from planetmint.transactions.common.transaction_mode_types import (
BROADCAST_TX_SYNC,
)
from planetmint.lib import Block
from ipld import marshal, multihash
@pytest.mark.bdb
@ -40,15 +41,21 @@ def test_asset_is_separated_from_transaciton(b):
bob = generate_key_pair()
asset = {
"Never gonna": [
"give you up",
"let you down",
"run around" "desert you",
"make you cry",
"say goodbye",
"tell a lie",
"hurt you",
]
"data": multihash(
marshal(
{
"Never gonna": [
"give you up",
"let you down",
"run around" "desert 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(
@ -404,7 +411,7 @@ def test_get_spent_transaction_critical_double_spend(b, alice, bob, carol):
from planetmint.exceptions import CriticalDoubleSpend
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])

View File

@ -20,6 +20,7 @@ from unittest.mock import MagicMock
from planetmint.transactions.common.exceptions import AmountError, SchemaValidationError, ThresholdTooDeep
from planetmint.transactions.common.transaction import Transaction
from planetmint.transactions.common.utils import _fulfillment_to_details, _fulfillment_from_details
from ipld import marshal, multihash
################################################################################
# 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):
create_tx.metadata = {"a": 1}
create_tx.metadata = multihash(marshal({"a": 1}))
signed_tx = create_tx.sign([alice.private_key])
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):
create_tx.asset["data"] = "a"
create_tx.asset["data"] = multihash(marshal({"a": ""}))
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):

View File

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

View File

@ -7,6 +7,7 @@ import pytest
from planetmint.transactions.types.assets.create import Create
from planetmint.lib import Block
from ipld import marshal, multihash
BLOCKS_ENDPOINT = "/api/v1/blocks/"
@ -16,7 +17,9 @@ BLOCKS_ENDPOINT = "/api/v1/blocks/"
def test_get_block_endpoint(b, client, alice):
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])
# 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
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])
b.store_bulk_transactions([tx])

View File

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

View File

@ -9,6 +9,7 @@ from unittest.mock import Mock, patch
import base58
import pytest
from cryptoconditions import Ed25519Sha256
from ipld import multihash, marshal
try:
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}
else:
asset = lang_obj
asset = {"data": multihash(marshal(asset))}
tx = Create.generate([user_pub], [([user_pub], 1)], asset=asset)
tx = tx.sign([user_priv])
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()
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()))
assert res.status_code == 202

View File

@ -11,6 +11,7 @@ import threading
# from unittest.mock import patch
from planetmint.transactions.types.assets.create import Create
from planetmint.transactions.types.assets.transfer import Transfer
from ipld import multihash, marshal
import pytest
@ -263,7 +264,7 @@ def test_integration_from_webapi_to_websocket(monkeypatch, client, loop):
# Create a keypair and generate a new asset
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 = tx.sign([user_priv])
# Post the transaction to the Planetmint Web API