diff --git a/CHANGELOG.md b/CHANGELOG.md index ce482e0..2bf08cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,13 +27,15 @@ For reference, the possible headings are: ## [Unreleased] - +## [1.2.1] - 2022-20-09 +* **Changed** Create model now validates for CID strings for asset["data"] and metadata +* **Changed** adjusted test cases ## [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 +* **Changed** adjusted test cases ## [1.1.0] - 2022-09-05 diff --git a/docs/root/source/basic-usage.md b/docs/root/source/basic-usage.md index 2956406..16d9490 100644 --- a/docs/root/source/basic-usage.md +++ b/docs/root/source/basic-usage.md @@ -17,7 +17,7 @@ two kinds: CREATE transactions and TRANSFER transactions. You can view the transaction specifications in Github, which describe transaction components and the conditions they have to fulfill in order to be valid. -[Planetmint Transactions Specs](https://github.com/planetmint/BEPs/tree/master/13/) +[Planetmint Transactions Specs](https://github.com/bigchaindb/BEPs/tree/master/13/) ### CREATE Transactions @@ -44,7 +44,7 @@ Planetmint supports a variety of conditions. For details, see the section titled **Transaction Components: Conditions** in the relevant -[Planetmint Transactions Spec](https://github.com/planetmint/BEPs/tree/master/13/). +[Planetmint Transactions Spec](https://github.com/bigchaindb/BEPs/tree/master/13/). ![Example Planetmint CREATE transaction](./_static/CREATE_example.png) @@ -58,7 +58,7 @@ Loosely speaking, that list might be interpreted as the list of "owners." A more accurate word might be fulfillers, signers, controllers, or transfer-enablers. See the section titled **A Note about Owners** -in the relevant [Planetmint Transactions Spec](https://github.com/planetmint/BEPs/tree/master/13/). +in the relevant [Planetmint Transactions Spec](https://github.com/bigchaindb/BEPs/tree/master/13/). A CREATE transaction must be signed by all the owners. (If you're looking for that signature, @@ -119,10 +119,27 @@ of the outgoing paperclips (100). ### Transaction Validity When a node is asked to check if a transaction is valid, it checks several -things. This got documentet by a BigchainDB post (previous version of Planetmint) at*The BigchainDB Blog*: +things. This got documented by a BigchainDB post (previous version of Planetmint) at*The BigchainDB Blog*: ["What is a Valid Transaction in BigchainDB?"](https://blog.bigchaindb.com/what-is-a-valid-transaction-in-planetmint-9a1a075a9598) (Note: That post was about Planetmint Server v1.0.0.) +## A Note on IPLD marshalling and CIDs + +Planetmint utilizes IPLD (interplanetary linked data) marshalling and CIDs (content identifiers) to store and verify data. +Before submitting a transaction to the network the data is marshalled using [py-ipld](https://github.com/planetmint/py-ipld) and instead of the raw data a CID is stored on chain. + +The CID is a self describing data structure. It contains information about the encoding, cryptographic algorithm, length and the actual hashvalue. For example the CID `bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi` tells us the following: + +``` +Encoding: base32 +Codec: dag-pb (MerkleDAG protobuf) +Hashing-Algorithm: sha2-256 +Digest (Hex): C3C4733EC8AFFD06CF9E9FF50FFC6BCD2EC85A6170004BB709669C31DE94391A +``` + +With this information we can validate that information about an asset we've received is actually valid. + + ### Example Transactions There are example Planetmint transactions in diff --git a/planetmint/transactions/common/transaction.py b/planetmint/transactions/common/transaction.py index a8315cc..33f504c 100644 --- a/planetmint/transactions/common/transaction.py +++ b/planetmint/transactions/common/transaction.py @@ -19,6 +19,7 @@ import rapidjson import base58 from cryptoconditions import Fulfillment, ThresholdSha256, Ed25519Sha256, ZenroomSha256 from cryptoconditions.exceptions import ParsingError, ASN1DecodeError, ASN1EncodeError +from cid import is_cid try: from hashlib import sha3_256 @@ -145,7 +146,9 @@ class Transaction(object): 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 + if is_cid(asset["data"]) == False: + raise TypeError("`asset.data` not valid CID") + raise TypeError( ( "`asset` must be None or a dict holding a `data` " @@ -163,7 +166,9 @@ class Transaction(object): raise TypeError("`inputs` must be a list instance or None") if metadata is not None and not isinstance(metadata, str): - # Add CID validation + if is_cid(metadata) == False: + raise TypeError("`metadata` not valid CID") + raise TypeError("`metadata` must be a CID string or None") if script is not None and not isinstance(script, dict): diff --git a/planetmint/transactions/types/assets/create.py b/planetmint/transactions/types/assets/create.py index 14fb5d1..a72583c 100644 --- a/planetmint/transactions/types/assets/create.py +++ b/planetmint/transactions/types/assets/create.py @@ -3,6 +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 +from cid import is_cid + from planetmint.transactions.common.transaction import Transaction from planetmint.transactions.common.input import Input from planetmint.transactions.common.output import Output @@ -26,13 +28,9 @@ class Create(Transaction): 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): + if "data" in asset and not is_cid(asset["data"]): raise TypeError("`asset` must be a CID string or None") - import cid - - cid.make_cid(asset["data"]) - if not (metadata is None or isinstance(metadata, str)): - # add check if metadata is ipld marshalled CID string + if not (metadata is None or is_cid(metadata)): raise TypeError("`metadata` must be a CID string or None") return True diff --git a/planetmint/version.py b/planetmint/version.py index 8cacf6d..2887e47 100644 --- a/planetmint/version.py +++ b/planetmint/version.py @@ -3,7 +3,7 @@ # 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.2.0" +__version__ = "1.2.1" __short_version__ = "1.2" # Supported Tendermint versions diff --git a/tests/common/test_transaction.py b/tests/common/test_transaction.py index 01e491a..5e81937 100644 --- a/tests/common/test_transaction.py +++ b/tests/common/test_transaction.py @@ -22,6 +22,7 @@ from cryptoconditions import Fulfillment from cryptoconditions import PreimageSha256 from cryptoconditions import Ed25519Sha256 from pytest import mark, raises +from ipld import marshal, multihash try: from hashlib import sha3_256 @@ -685,8 +686,8 @@ 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={"data": "not a dict or none"}) - with raises(ValueError): + Create.generate([user_pub], [([user_pub], 1)], metadata={"data": "not a cid string or none"}) + with raises(TypeError): Create.generate([user_pub], [([user_pub], 1)], asset={"data": "not a dict or none"}) diff --git a/tests/db/test_planetmint_api.py b/tests/db/test_planetmint_api.py index d137d10..4ed8ae1 100644 --- a/tests/db/test_planetmint_api.py +++ b/tests/db/test_planetmint_api.py @@ -9,6 +9,7 @@ from planetmint.transactions.types.assets.transfer import Transfer from ipld import marshal, multihash import pytest from base58 import b58decode +import random pytestmark = pytest.mark.bdb @@ -377,7 +378,7 @@ class TestMultipleInputs(object): transactions = [] for i in range(3): - payload = f"QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L{i}" # create unique CIDs + payload = multihash(marshal({"msg": random.random()})) tx = Create.generate([alice.public_key], [([user_pk, user2_pk], 1)], payload) tx = tx.sign([alice.private_key]) transactions.append(tx)