ipld documentation and validation (#259)

* added information on CID and IPLD marhsalling to basic-usage

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

* adjusted test cases for cid validation

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

* fixed linting errors

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

* updated version number and CHANGELOG

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

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
This commit is contained in:
Lorenz Herzberger 2022-09-20 10:34:44 +02:00 committed by GitHub
parent da27c7f2d5
commit 69fe9b253d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 42 additions and 18 deletions

View File

@ -27,13 +27,15 @@ For reference, the possible headings are:
## [Unreleased] ## [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 ## [1.2.0] - 2022-09-05
* **Changed** disabled acceptance and integration tests, they have a circular dep. to the python driver * **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 * **Changed** Metadata and asset["data"] types to string containing an IPLD hash
* **Fixed** Transaction generation bug that automatically assigned 'assets' to asset["data"] * **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 ## [1.1.0] - 2022-09-05

View File

@ -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. 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 ### CREATE Transactions
@ -44,7 +44,7 @@ Planetmint supports a variety of conditions.
For details, see For details, see
the section titled **Transaction Components: Conditions** the section titled **Transaction Components: Conditions**
in the relevant 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) ![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, A more accurate word might be fulfillers, signers, controllers,
or transfer-enablers. or transfer-enablers.
See the section titled **A Note about Owners** 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. A CREATE transaction must be signed by all the owners.
(If you're looking for that signature, (If you're looking for that signature,
@ -119,10 +119,27 @@ of the outgoing paperclips (100).
### Transaction Validity ### Transaction Validity
When a node is asked to check if a transaction is valid, it checks several 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) ["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.) (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 ### Example Transactions
There are example Planetmint transactions in There are example Planetmint transactions in

View File

@ -19,6 +19,7 @@ import rapidjson
import base58 import base58
from cryptoconditions import Fulfillment, ThresholdSha256, Ed25519Sha256, ZenroomSha256 from cryptoconditions import Fulfillment, ThresholdSha256, Ed25519Sha256, ZenroomSha256
from cryptoconditions.exceptions import ParsingError, ASN1DecodeError, ASN1EncodeError from cryptoconditions.exceptions import ParsingError, ASN1DecodeError, ASN1EncodeError
from cid import is_cid
try: try:
from hashlib import sha3_256 from hashlib import sha3_256
@ -145,7 +146,9 @@ class Transaction(object):
if "data" in asset: if "data" in asset:
if asset["data"] is not None and not isinstance(asset["data"], str): 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( raise TypeError(
( (
"`asset` must be None or a dict holding a `data` " "`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") raise TypeError("`inputs` must be a list instance or None")
if metadata is not None and not isinstance(metadata, str): 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") 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):

View File

@ -3,6 +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
from cid import is_cid
from planetmint.transactions.common.transaction import Transaction from planetmint.transactions.common.transaction import Transaction
from planetmint.transactions.common.input import Input from planetmint.transactions.common.input import Input
from planetmint.transactions.common.output import Output from planetmint.transactions.common.output import Output
@ -26,13 +28,9 @@ class Create(Transaction):
if not asset is None: if not asset is None:
if not isinstance(asset, dict): if not isinstance(asset, dict):
raise TypeError("`asset` must be a CID string or None") 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") raise TypeError("`asset` must be a CID string or None")
import cid if not (metadata is None or is_cid(metadata)):
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") raise TypeError("`metadata` must be a CID string or None")
return True return True

View File

@ -3,7 +3,7 @@
# 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.2.0" __version__ = "1.2.1"
__short_version__ = "1.2" __short_version__ = "1.2"
# Supported Tendermint versions # Supported Tendermint versions

View File

@ -22,6 +22,7 @@ from cryptoconditions import Fulfillment
from cryptoconditions import PreimageSha256 from cryptoconditions import PreimageSha256
from cryptoconditions import Ed25519Sha256 from cryptoconditions import Ed25519Sha256
from pytest import mark, raises from pytest import mark, raises
from ipld import marshal, multihash
try: try:
from hashlib import sha3_256 from hashlib import sha3_256
@ -685,8 +686,8 @@ 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={"data": "not a dict or none"}) Create.generate([user_pub], [([user_pub], 1)], metadata={"data": "not a cid string or none"})
with raises(ValueError): with raises(TypeError):
Create.generate([user_pub], [([user_pub], 1)], asset={"data": "not a dict or none"}) Create.generate([user_pub], [([user_pub], 1)], asset={"data": "not a dict or none"})

View File

@ -9,6 +9,7 @@ from planetmint.transactions.types.assets.transfer import Transfer
from ipld import marshal, multihash from ipld import marshal, multihash
import pytest import pytest
from base58 import b58decode from base58 import b58decode
import random
pytestmark = pytest.mark.bdb pytestmark = pytest.mark.bdb
@ -377,7 +378,7 @@ class TestMultipleInputs(object):
transactions = [] transactions = []
for i in range(3): 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 = 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)