mirror of
https://github.com/planetmint/planetmint.git
synced 2025-11-23 22:15:44 +00:00
fixed linting errors
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
This commit is contained in:
parent
a35f705865
commit
ea05872927
@ -42,13 +42,13 @@ class Output(object):
|
||||
TypeError: if `public_keys` is not instance of `list`.
|
||||
"""
|
||||
if not isinstance(public_keys, list) and public_keys is not None:
|
||||
raise TypeError('`public_keys` must be a list instance or None')
|
||||
raise TypeError("`public_keys` must be a list instance or None")
|
||||
if not isinstance(amount, int):
|
||||
raise TypeError('`amount` must be an int')
|
||||
raise TypeError("`amount` must be an int")
|
||||
if amount < 1:
|
||||
raise AmountError('`amount` must be greater than 0')
|
||||
raise AmountError("`amount` must be greater than 0")
|
||||
if amount > self.MAX_AMOUNT:
|
||||
raise AmountError('`amount` must be <= %s' % self.MAX_AMOUNT)
|
||||
raise AmountError("`amount` must be <= %s" % self.MAX_AMOUNT)
|
||||
|
||||
self.fulfillment = fulfillment
|
||||
self.amount = amount
|
||||
@ -73,19 +73,19 @@ class Output(object):
|
||||
condition = {}
|
||||
try:
|
||||
# TODO verify if a script is returned in case of zenroom fulfillments
|
||||
condition['details'] = _fulfillment_to_details(self.fulfillment)
|
||||
condition["details"] = _fulfillment_to_details(self.fulfillment)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
condition['uri'] = self.fulfillment.condition_uri
|
||||
condition["uri"] = self.fulfillment.condition_uri
|
||||
except AttributeError:
|
||||
condition['uri'] = self.fulfillment
|
||||
condition["uri"] = self.fulfillment
|
||||
|
||||
output = {
|
||||
'public_keys': self.public_keys,
|
||||
'condition': condition,
|
||||
'amount': str(self.amount),
|
||||
"public_keys": self.public_keys,
|
||||
"condition": condition,
|
||||
"amount": str(self.amount),
|
||||
}
|
||||
return output
|
||||
|
||||
@ -115,28 +115,24 @@ class Output(object):
|
||||
"""
|
||||
threshold = len(public_keys)
|
||||
if not isinstance(amount, int):
|
||||
raise TypeError('`amount` must be a int')
|
||||
raise TypeError("`amount` must be a int")
|
||||
if amount < 1:
|
||||
raise AmountError('`amount` needs to be greater than zero')
|
||||
raise AmountError("`amount` needs to be greater than zero")
|
||||
if not isinstance(public_keys, list):
|
||||
raise TypeError('`public_keys` must be an instance of list')
|
||||
raise TypeError("`public_keys` must be an instance of list")
|
||||
if len(public_keys) == 0:
|
||||
raise ValueError('`public_keys` needs to contain at least one'
|
||||
'owner')
|
||||
raise ValueError("`public_keys` needs to contain at least one" "owner")
|
||||
elif len(public_keys) == 1 and not isinstance(public_keys[0], list):
|
||||
if isinstance(public_keys[0], Fulfillment):
|
||||
ffill = public_keys[0]
|
||||
elif isinstance(public_keys[0], ZenroomSha256):
|
||||
ffill = ZenroomSha256(
|
||||
public_key=base58.b58decode(public_keys[0]))
|
||||
ffill = ZenroomSha256(public_key=base58.b58decode(public_keys[0]))
|
||||
else:
|
||||
ffill = Ed25519Sha256(
|
||||
public_key=base58.b58decode(public_keys[0]))
|
||||
ffill = Ed25519Sha256(public_key=base58.b58decode(public_keys[0]))
|
||||
return cls(ffill, public_keys, amount=amount)
|
||||
else:
|
||||
initial_cond = ThresholdSha256(threshold=threshold)
|
||||
threshold_cond = reduce(cls._gen_condition, public_keys,
|
||||
initial_cond)
|
||||
threshold_cond = reduce(cls._gen_condition, public_keys, initial_cond)
|
||||
return cls(threshold_cond, public_keys, amount=amount)
|
||||
|
||||
@classmethod
|
||||
@ -166,7 +162,7 @@ class Output(object):
|
||||
ffill = ThresholdSha256(threshold=threshold)
|
||||
reduce(cls._gen_condition, new_public_keys, ffill)
|
||||
elif isinstance(new_public_keys, list) and len(new_public_keys) <= 1:
|
||||
raise ValueError('Sublist cannot contain single owner')
|
||||
raise ValueError("Sublist cannot contain single owner")
|
||||
else:
|
||||
try:
|
||||
new_public_keys = new_public_keys.pop()
|
||||
@ -181,8 +177,7 @@ class Output(object):
|
||||
if isinstance(new_public_keys, Fulfillment):
|
||||
ffill = new_public_keys
|
||||
else:
|
||||
ffill = Ed25519Sha256(
|
||||
public_key=base58.b58decode(new_public_keys))
|
||||
ffill = Ed25519Sha256(public_key=base58.b58decode(new_public_keys))
|
||||
initial.add_subfulfillment(ffill)
|
||||
return initial
|
||||
|
||||
@ -203,12 +198,12 @@ class Output(object):
|
||||
:class:`~planetmint.transactions.common.transaction.Output`
|
||||
"""
|
||||
try:
|
||||
fulfillment = _fulfillment_from_details(data['condition']['details'])
|
||||
fulfillment = _fulfillment_from_details(data["condition"]["details"])
|
||||
except KeyError:
|
||||
# NOTE: Hashlock condition case
|
||||
fulfillment = data['condition']['uri']
|
||||
fulfillment = data["condition"]["uri"]
|
||||
try:
|
||||
amount = int(data['amount'])
|
||||
amount = int(data["amount"])
|
||||
except ValueError:
|
||||
raise AmountError('Invalid amount: %s' % data['amount'])
|
||||
return cls(fulfillment, data['public_keys'], amount)
|
||||
raise AmountError("Invalid amount: %s" % data["amount"])
|
||||
return cls(fulfillment, data["public_keys"], amount)
|
||||
|
||||
@ -18,8 +18,8 @@ import rapidjson
|
||||
|
||||
import base58
|
||||
from cryptoconditions import Fulfillment, ThresholdSha256, Ed25519Sha256, ZenroomSha256
|
||||
from cryptoconditions.exceptions import (
|
||||
ParsingError, ASN1DecodeError, ASN1EncodeError)
|
||||
from cryptoconditions.exceptions import ParsingError, ASN1DecodeError, ASN1EncodeError
|
||||
|
||||
try:
|
||||
from hashlib import sha3_256
|
||||
except ImportError:
|
||||
@ -27,8 +27,14 @@ except ImportError:
|
||||
|
||||
from planetmint.transactions.common.crypto import PrivateKey, hash_data
|
||||
from planetmint.transactions.common.exceptions import (
|
||||
KeypairMismatchException, InputDoesNotExist, DoubleSpend,
|
||||
InvalidHash, InvalidSignature, AmountError, AssetIdMismatch)
|
||||
KeypairMismatchException,
|
||||
InputDoesNotExist,
|
||||
DoubleSpend,
|
||||
InvalidHash,
|
||||
InvalidSignature,
|
||||
AmountError,
|
||||
AssetIdMismatch,
|
||||
)
|
||||
from planetmint.transactions.common.utils import serialize
|
||||
from .memoize import memoize_from_dict, memoize_to_dict
|
||||
from .input import Input
|
||||
@ -36,15 +42,16 @@ from .output import Output
|
||||
from .transaction_link import TransactionLink
|
||||
|
||||
UnspentOutput = namedtuple(
|
||||
'UnspentOutput', (
|
||||
"UnspentOutput",
|
||||
(
|
||||
# TODO 'utxo_hash': sha3_256(f'{txid}{output_index}'.encode())
|
||||
# 'utxo_hash', # noqa
|
||||
'transaction_id',
|
||||
'output_index',
|
||||
'amount',
|
||||
'asset_id',
|
||||
'condition_uri',
|
||||
)
|
||||
"transaction_id",
|
||||
"output_index",
|
||||
"amount",
|
||||
"asset_id",
|
||||
"condition_uri",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@ -71,13 +78,22 @@ class Transaction(object):
|
||||
version (string): Defines the version number of a Transaction.
|
||||
"""
|
||||
|
||||
CREATE = 'CREATE'
|
||||
TRANSFER = 'TRANSFER'
|
||||
CREATE = "CREATE"
|
||||
TRANSFER = "TRANSFER"
|
||||
ALLOWED_OPERATIONS = (CREATE, TRANSFER)
|
||||
VERSION = '2.0'
|
||||
VERSION = "2.0"
|
||||
|
||||
def __init__(self, operation, asset, inputs=None, outputs=None,
|
||||
metadata=None, version=None, hash_id=None, tx_dict=None):
|
||||
def __init__(
|
||||
self,
|
||||
operation,
|
||||
asset,
|
||||
inputs=None,
|
||||
outputs=None,
|
||||
metadata=None,
|
||||
version=None,
|
||||
hash_id=None,
|
||||
tx_dict=None,
|
||||
):
|
||||
"""The constructor allows to create a customizable Transaction.
|
||||
|
||||
Note:
|
||||
@ -98,30 +114,41 @@ class Transaction(object):
|
||||
hash_id (string): Hash id of the transaction.
|
||||
"""
|
||||
if operation not in self.ALLOWED_OPERATIONS:
|
||||
allowed_ops = ', '.join(self.__class__.ALLOWED_OPERATIONS)
|
||||
raise ValueError('`operation` must be one of {}'
|
||||
.format(allowed_ops))
|
||||
allowed_ops = ", ".join(self.__class__.ALLOWED_OPERATIONS)
|
||||
raise ValueError("`operation` must be one of {}".format(allowed_ops))
|
||||
|
||||
# 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)))
|
||||
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'))
|
||||
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)
|
||||
)
|
||||
)
|
||||
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"
|
||||
)
|
||||
)
|
||||
|
||||
if outputs and not isinstance(outputs, list):
|
||||
raise TypeError('`outputs` must be a list instance or None')
|
||||
raise TypeError("`outputs` must be a list instance or None")
|
||||
|
||||
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):
|
||||
raise TypeError('`metadata` must be a dict or None')
|
||||
raise TypeError("`metadata` must be a dict or None")
|
||||
|
||||
self.version = version if version is not None else self.VERSION
|
||||
self.operation = operation
|
||||
@ -141,14 +168,17 @@ class Transaction(object):
|
||||
if self.operation == self.CREATE:
|
||||
self._asset_id = self._id
|
||||
elif self.operation == self.TRANSFER:
|
||||
self._asset_id = self.asset['id']
|
||||
return (UnspentOutput(
|
||||
self._asset_id = self.asset["id"]
|
||||
return (
|
||||
UnspentOutput(
|
||||
transaction_id=self._id,
|
||||
output_index=output_index,
|
||||
amount=output.amount,
|
||||
asset_id=self._asset_id,
|
||||
condition_uri=output.fulfillment.condition_uri,
|
||||
) for output_index, output in enumerate(self.outputs))
|
||||
)
|
||||
for output_index, output in enumerate(self.outputs)
|
||||
)
|
||||
|
||||
@property
|
||||
def spent_outputs(self):
|
||||
@ -156,10 +186,7 @@ class Transaction(object):
|
||||
is represented as a dictionary containing a transaction id and
|
||||
output index.
|
||||
"""
|
||||
return (
|
||||
input_.fulfills.to_dict()
|
||||
for input_ in self.inputs if input_.fulfills
|
||||
)
|
||||
return (input_.fulfills.to_dict() for input_ in self.inputs if input_.fulfills)
|
||||
|
||||
@property
|
||||
def serialized(self):
|
||||
@ -199,9 +226,11 @@ class Transaction(object):
|
||||
# as inputs.
|
||||
indices = indices or range(len(self.outputs))
|
||||
return [
|
||||
Input(self.outputs[idx].fulfillment,
|
||||
Input(
|
||||
self.outputs[idx].fulfillment,
|
||||
self.outputs[idx].public_keys,
|
||||
TransactionLink(self.id, idx))
|
||||
TransactionLink(self.id, idx),
|
||||
)
|
||||
for idx in indices
|
||||
]
|
||||
|
||||
@ -213,7 +242,7 @@ class Transaction(object):
|
||||
Input`): An Input to be added to the Transaction.
|
||||
"""
|
||||
if not isinstance(input_, Input):
|
||||
raise TypeError('`input_` must be a Input instance')
|
||||
raise TypeError("`input_` must be a Input instance")
|
||||
self.inputs.append(input_)
|
||||
|
||||
def add_output(self, output):
|
||||
@ -225,7 +254,7 @@ class Transaction(object):
|
||||
Transaction.
|
||||
"""
|
||||
if not isinstance(output, Output):
|
||||
raise TypeError('`output` must be an Output instance or None')
|
||||
raise TypeError("`output` must be an Output instance or None")
|
||||
self.outputs.append(output)
|
||||
|
||||
def sign(self, private_keys):
|
||||
@ -252,7 +281,7 @@ class Transaction(object):
|
||||
# TODO: Singing should be possible with at least one of all private
|
||||
# keys supplied to this method.
|
||||
if private_keys is None or not isinstance(private_keys, list):
|
||||
raise TypeError('`private_keys` must be a list instance')
|
||||
raise TypeError("`private_keys` must be a list instance")
|
||||
|
||||
# NOTE: Generate public keys from private keys and match them in a
|
||||
# dictionary:
|
||||
@ -269,8 +298,10 @@ class Transaction(object):
|
||||
# to decode to convert the bytestring into a python str
|
||||
return public_key.decode()
|
||||
|
||||
key_pairs = {gen_public_key(PrivateKey(private_key)):
|
||||
PrivateKey(private_key) for private_key in private_keys}
|
||||
key_pairs = {
|
||||
gen_public_key(PrivateKey(private_key)): PrivateKey(private_key)
|
||||
for private_key in private_keys
|
||||
}
|
||||
|
||||
tx_dict = self.to_dict()
|
||||
tx_dict = Transaction._remove_signatures(tx_dict)
|
||||
@ -299,18 +330,16 @@ class Transaction(object):
|
||||
key_pairs (dict): The keys to sign the Transaction with.
|
||||
"""
|
||||
if isinstance(input_.fulfillment, Ed25519Sha256):
|
||||
return cls._sign_simple_signature_fulfillment(input_, message,
|
||||
key_pairs)
|
||||
return cls._sign_simple_signature_fulfillment(input_, message, key_pairs)
|
||||
elif isinstance(input_.fulfillment, ThresholdSha256):
|
||||
return cls._sign_threshold_signature_fulfillment(input_, message,
|
||||
key_pairs)
|
||||
return cls._sign_threshold_signature_fulfillment(input_, message, key_pairs)
|
||||
elif isinstance(input_.fulfillment, ZenroomSha256):
|
||||
return cls._sign_threshold_signature_fulfillment(input_, message,
|
||||
key_pairs)
|
||||
return cls._sign_threshold_signature_fulfillment(input_, message, key_pairs)
|
||||
else:
|
||||
raise ValueError(
|
||||
'Fulfillment couldn\'t be matched to '
|
||||
'Cryptocondition fulfillment type.')
|
||||
"Fulfillment couldn't be matched to "
|
||||
"Cryptocondition fulfillment type."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _sign_zenroom_fulfillment(cls, input_, message, key_pairs):
|
||||
@ -330,18 +359,21 @@ class Transaction(object):
|
||||
public_key = input_.owners_before[0]
|
||||
message = sha3_256(message.encode())
|
||||
if input_.fulfills:
|
||||
message.update('{}{}'.format(
|
||||
input_.fulfills.txid, input_.fulfills.output).encode())
|
||||
message.update(
|
||||
"{}{}".format(input_.fulfills.txid, input_.fulfills.output).encode()
|
||||
)
|
||||
|
||||
try:
|
||||
# cryptoconditions makes no assumptions of the encoding of the
|
||||
# message to sign or verify. It only accepts bytestrings
|
||||
input_.fulfillment.sign(
|
||||
message.digest(), base58.b58decode(key_pairs[public_key].encode()))
|
||||
message.digest(), base58.b58decode(key_pairs[public_key].encode())
|
||||
)
|
||||
except KeyError:
|
||||
raise KeypairMismatchException('Public key {} is not a pair to '
|
||||
'any of the private keys'
|
||||
.format(public_key))
|
||||
raise KeypairMismatchException(
|
||||
"Public key {} is not a pair to "
|
||||
"any of the private keys".format(public_key)
|
||||
)
|
||||
return input_
|
||||
|
||||
@classmethod
|
||||
@ -362,18 +394,21 @@ class Transaction(object):
|
||||
public_key = input_.owners_before[0]
|
||||
message = sha3_256(message.encode())
|
||||
if input_.fulfills:
|
||||
message.update('{}{}'.format(
|
||||
input_.fulfills.txid, input_.fulfills.output).encode())
|
||||
message.update(
|
||||
"{}{}".format(input_.fulfills.txid, input_.fulfills.output).encode()
|
||||
)
|
||||
|
||||
try:
|
||||
# cryptoconditions makes no assumptions of the encoding of the
|
||||
# message to sign or verify. It only accepts bytestrings
|
||||
input_.fulfillment.sign(
|
||||
message.digest(), base58.b58decode(key_pairs[public_key].encode()))
|
||||
message.digest(), base58.b58decode(key_pairs[public_key].encode())
|
||||
)
|
||||
except KeyError:
|
||||
raise KeypairMismatchException('Public key {} is not a pair to '
|
||||
'any of the private keys'
|
||||
.format(public_key))
|
||||
raise KeypairMismatchException(
|
||||
"Public key {} is not a pair to "
|
||||
"any of the private keys".format(public_key)
|
||||
)
|
||||
return input_
|
||||
|
||||
@classmethod
|
||||
@ -389,8 +424,9 @@ class Transaction(object):
|
||||
input_ = deepcopy(input_)
|
||||
message = sha3_256(message.encode())
|
||||
if input_.fulfills:
|
||||
message.update('{}{}'.format(
|
||||
input_.fulfills.txid, input_.fulfills.output).encode())
|
||||
message.update(
|
||||
"{}{}".format(input_.fulfills.txid, input_.fulfills.output).encode()
|
||||
)
|
||||
|
||||
for owner_before in set(input_.owners_before):
|
||||
# TODO: CC should throw a KeypairMismatchException, instead of
|
||||
@ -403,24 +439,24 @@ class Transaction(object):
|
||||
# TODO FOR CC: `get_subcondition` is singular. One would not
|
||||
# expect to get a list back.
|
||||
ccffill = input_.fulfillment
|
||||
subffills = ccffill.get_subcondition_from_vk(
|
||||
base58.b58decode(owner_before))
|
||||
subffills = ccffill.get_subcondition_from_vk(base58.b58decode(owner_before))
|
||||
if not subffills:
|
||||
raise KeypairMismatchException('Public key {} cannot be found '
|
||||
'in the fulfillment'
|
||||
.format(owner_before))
|
||||
raise KeypairMismatchException(
|
||||
"Public key {} cannot be found "
|
||||
"in the fulfillment".format(owner_before)
|
||||
)
|
||||
try:
|
||||
private_key = key_pairs[owner_before]
|
||||
except KeyError:
|
||||
raise KeypairMismatchException('Public key {} is not a pair '
|
||||
'to any of the private keys'
|
||||
.format(owner_before))
|
||||
raise KeypairMismatchException(
|
||||
"Public key {} is not a pair "
|
||||
"to any of the private keys".format(owner_before)
|
||||
)
|
||||
|
||||
# cryptoconditions makes no assumptions of the encoding of the
|
||||
# message to sign or verify. It only accepts bytestrings
|
||||
for subffill in subffills:
|
||||
subffill.sign(
|
||||
message.digest(), base58.b58decode(private_key.encode()))
|
||||
subffill.sign(message.digest(), base58.b58decode(private_key.encode()))
|
||||
return input_
|
||||
|
||||
def inputs_valid(self, outputs=None):
|
||||
@ -445,15 +481,14 @@ class Transaction(object):
|
||||
# to check for outputs, we're just submitting dummy
|
||||
# values to the actual method. This simplifies it's logic
|
||||
# greatly, as we do not have to check against `None` values.
|
||||
return self._inputs_valid(['dummyvalue'
|
||||
for _ in self.inputs])
|
||||
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])
|
||||
return self._inputs_valid(
|
||||
[output.fulfillment.condition_uri for output in outputs]
|
||||
)
|
||||
else:
|
||||
allowed_ops = ', '.join(self.__class__.ALLOWED_OPERATIONS)
|
||||
raise TypeError('`operation` must be one of {}'
|
||||
.format(allowed_ops))
|
||||
allowed_ops = ", ".join(self.__class__.ALLOWED_OPERATIONS)
|
||||
raise TypeError("`operation` must be one of {}".format(allowed_ops))
|
||||
|
||||
def _inputs_valid(self, output_condition_uris):
|
||||
"""Validates an Input against a given set of Outputs.
|
||||
@ -471,21 +506,22 @@ class Transaction(object):
|
||||
"""
|
||||
|
||||
if len(self.inputs) != len(output_condition_uris):
|
||||
raise ValueError('Inputs and '
|
||||
'output_condition_uris must have the same count')
|
||||
raise ValueError(
|
||||
"Inputs and " "output_condition_uris must have the same count"
|
||||
)
|
||||
|
||||
tx_dict = self.tx_dict if self.tx_dict else self.to_dict()
|
||||
tx_dict = Transaction._remove_signatures(tx_dict)
|
||||
tx_dict['id'] = None
|
||||
tx_dict["id"] = None
|
||||
tx_serialized = Transaction._to_str(tx_dict)
|
||||
|
||||
def validate(i, output_condition_uri=None):
|
||||
"""Validate input against output condition URI"""
|
||||
return self._input_valid(self.inputs[i], self.operation,
|
||||
tx_serialized, output_condition_uri)
|
||||
return self._input_valid(
|
||||
self.inputs[i], self.operation, tx_serialized, output_condition_uri
|
||||
)
|
||||
|
||||
return all(validate(i, cond)
|
||||
for i, cond in enumerate(output_condition_uris))
|
||||
return all(validate(i, cond) for i, cond in enumerate(output_condition_uris))
|
||||
|
||||
@lru_cache(maxsize=16384)
|
||||
def _input_valid(self, input_, operation, message, output_condition_uri=None):
|
||||
@ -511,19 +547,19 @@ class Transaction(object):
|
||||
parsed_ffill = Fulfillment.from_uri(ccffill.serialize_uri())
|
||||
except TypeError as e:
|
||||
print(f"Exception TypeError : {e}")
|
||||
return False;
|
||||
return False
|
||||
except ValueError as e:
|
||||
print(f"Exception ValueError : {e}")
|
||||
return False;
|
||||
return False
|
||||
except ParsingError as e:
|
||||
print(f"Exception ParsingError : {e}")
|
||||
return False;
|
||||
return False
|
||||
except ASN1DecodeError as e:
|
||||
print(f"Exception ASN1DecodeError : {e}")
|
||||
return False;
|
||||
return False
|
||||
except ASN1EncodeError as e:
|
||||
print(f"Exception ASN1EncodeError : {e}")
|
||||
return False;
|
||||
return False
|
||||
|
||||
if operation == self.CREATE:
|
||||
# NOTE: In the case of a `CREATE` transaction, the
|
||||
@ -538,8 +574,9 @@ class Transaction(object):
|
||||
else:
|
||||
message = sha3_256(message.encode())
|
||||
if input_.fulfills:
|
||||
message.update('{}{}'.format(
|
||||
input_.fulfills.txid, input_.fulfills.output).encode())
|
||||
message.update(
|
||||
"{}{}".format(input_.fulfills.txid, input_.fulfills.output).encode()
|
||||
)
|
||||
|
||||
# NOTE: We pass a timestamp to `.validate`, as in case of a timeout
|
||||
# condition we'll have to validate against it
|
||||
@ -561,13 +598,13 @@ class Transaction(object):
|
||||
dict: The Transaction as an alternative serialization format.
|
||||
"""
|
||||
return {
|
||||
'inputs': [input_.to_dict() for input_ in self.inputs],
|
||||
'outputs': [output.to_dict() for output in self.outputs],
|
||||
'operation': str(self.operation),
|
||||
'metadata': self.metadata,
|
||||
'asset': self.asset,
|
||||
'version': self.version,
|
||||
'id': self._id,
|
||||
"inputs": [input_.to_dict() for input_ in self.inputs],
|
||||
"outputs": [output.to_dict() for output in self.outputs],
|
||||
"operation": str(self.operation),
|
||||
"metadata": self.metadata,
|
||||
"asset": self.asset,
|
||||
"version": self.version,
|
||||
"id": self._id,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
@ -585,12 +622,12 @@ class Transaction(object):
|
||||
# NOTE: We remove the reference since we need `tx_dict` only for the
|
||||
# transaction's hash
|
||||
tx_dict = deepcopy(tx_dict)
|
||||
for input_ in tx_dict['inputs']:
|
||||
for input_ in tx_dict["inputs"]:
|
||||
# NOTE: Not all Cryptoconditions return a `signature` key (e.g.
|
||||
# ThresholdSha256), so setting it to `None` in any
|
||||
# case could yield incorrect signatures. This is why we only
|
||||
# set it to `None` if it's set in the dict.
|
||||
input_['fulfillment'] = None
|
||||
input_["fulfillment"] = None
|
||||
return tx_dict
|
||||
|
||||
@staticmethod
|
||||
@ -602,7 +639,7 @@ class Transaction(object):
|
||||
return self._id
|
||||
|
||||
def to_hash(self):
|
||||
return self.to_dict()['id']
|
||||
return self.to_dict()["id"]
|
||||
|
||||
@staticmethod
|
||||
def _to_str(value):
|
||||
@ -638,14 +675,19 @@ 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 == tx.CREATE else tx.asset["id"]
|
||||
for tx in transactions
|
||||
}
|
||||
|
||||
# check that all the transasctions have the same asset id
|
||||
if len(asset_ids) > 1:
|
||||
raise AssetIdMismatch(('All inputs of all transactions passed'
|
||||
' need to have the same asset id'))
|
||||
raise AssetIdMismatch(
|
||||
(
|
||||
"All inputs of all transactions passed"
|
||||
" need to have the same asset id"
|
||||
)
|
||||
)
|
||||
return asset_ids.pop()
|
||||
|
||||
@staticmethod
|
||||
@ -660,18 +702,20 @@ class Transaction(object):
|
||||
tx_body = rapidjson.loads(rapidjson.dumps(tx_body))
|
||||
|
||||
try:
|
||||
proposed_tx_id = tx_body['id']
|
||||
proposed_tx_id = tx_body["id"]
|
||||
except KeyError:
|
||||
raise InvalidHash('No transaction id found!')
|
||||
raise InvalidHash("No transaction id found!")
|
||||
|
||||
tx_body['id'] = None
|
||||
tx_body["id"] = None
|
||||
|
||||
tx_body_serialized = Transaction._to_str(tx_body)
|
||||
valid_tx_id = Transaction._to_hash(tx_body_serialized)
|
||||
|
||||
if proposed_tx_id != valid_tx_id:
|
||||
err_msg = ("The transaction's id '{}' isn't equal to "
|
||||
"the hash of its body, i.e. it's not valid.")
|
||||
err_msg = (
|
||||
"The transaction's id '{}' isn't equal to "
|
||||
"the hash of its body, i.e. it's not valid."
|
||||
)
|
||||
raise InvalidHash(err_msg.format(proposed_tx_id))
|
||||
|
||||
@classmethod
|
||||
@ -685,17 +729,29 @@ class Transaction(object):
|
||||
Returns:
|
||||
:class:`~planetmint.transactions.common.transaction.Transaction`
|
||||
"""
|
||||
operation = tx.get('operation', Transaction.CREATE) if isinstance(tx, dict) else Transaction.CREATE
|
||||
operation = (
|
||||
tx.get("operation", Transaction.CREATE)
|
||||
if isinstance(tx, dict)
|
||||
else Transaction.CREATE
|
||||
)
|
||||
cls = Transaction.resolve_class(operation)
|
||||
|
||||
if not skip_schema_validation:
|
||||
cls.validate_id(tx)
|
||||
cls.validate_schema(tx)
|
||||
|
||||
inputs = [Input.from_dict(input_) for input_ in tx['inputs']]
|
||||
outputs = [Output.from_dict(output) for output in tx['outputs']]
|
||||
return cls(tx['operation'], tx['asset'], inputs, outputs,
|
||||
tx['metadata'], tx['version'], hash_id=tx['id'], tx_dict=tx)
|
||||
inputs = [Input.from_dict(input_) for input_ in tx["inputs"]]
|
||||
outputs = [Output.from_dict(output) for output in tx["outputs"]]
|
||||
return cls(
|
||||
tx["operation"],
|
||||
tx["asset"],
|
||||
inputs,
|
||||
outputs,
|
||||
tx["metadata"],
|
||||
tx["version"],
|
||||
hash_id=tx["id"],
|
||||
tx_dict=tx,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_db(cls, planet, tx_dict_list):
|
||||
@ -721,22 +777,22 @@ class Transaction(object):
|
||||
tx_map = {}
|
||||
tx_ids = []
|
||||
for tx in tx_dict_list:
|
||||
tx.update({'metadata': None})
|
||||
tx_map[tx['id']] = tx
|
||||
tx_ids.append(tx['id'])
|
||||
tx.update({"metadata": None})
|
||||
tx_map[tx["id"]] = tx
|
||||
tx_ids.append(tx["id"])
|
||||
|
||||
assets = list(planet.get_assets(tx_ids))
|
||||
for asset in assets:
|
||||
if asset is not None:
|
||||
tx = tx_map[asset['id']]
|
||||
del asset['id']
|
||||
tx['asset'] = asset
|
||||
tx = tx_map[asset["id"]]
|
||||
del asset["id"]
|
||||
tx["asset"] = asset
|
||||
|
||||
tx_ids = list(tx_map.keys())
|
||||
metadata_list = list(planet.get_metadata(tx_ids))
|
||||
for metadata in metadata_list:
|
||||
tx = tx_map[metadata['id']]
|
||||
tx.update({'metadata': metadata.get('metadata')})
|
||||
tx = tx_map[metadata["id"]]
|
||||
tx.update({"metadata": metadata.get("metadata")})
|
||||
|
||||
if return_list:
|
||||
tx_list = []
|
||||
@ -777,14 +833,13 @@ class Transaction(object):
|
||||
input_tx = ctxn
|
||||
|
||||
if input_tx is None:
|
||||
raise InputDoesNotExist("input `{}` doesn't exist"
|
||||
.format(input_txid))
|
||||
raise InputDoesNotExist("input `{}` doesn't exist".format(input_txid))
|
||||
|
||||
spent = planet.get_spent(input_txid, input_.fulfills.output,
|
||||
current_transactions)
|
||||
spent = planet.get_spent(
|
||||
input_txid, input_.fulfills.output, current_transactions
|
||||
)
|
||||
if spent:
|
||||
raise DoubleSpend('input `{}` was already spent'
|
||||
.format(input_txid))
|
||||
raise DoubleSpend("input `{}` was already spent".format(input_txid))
|
||||
|
||||
output = input_tx.outputs[input_.fulfills.output]
|
||||
input_conditions.append(output)
|
||||
@ -797,21 +852,32 @@ class Transaction(object):
|
||||
|
||||
# validate asset id
|
||||
asset_id = self.get_asset_id(input_txs)
|
||||
if asset_id != self.asset['id']:
|
||||
raise AssetIdMismatch(('The asset id of the input does not'
|
||||
' match the asset id of the'
|
||||
' transaction'))
|
||||
if asset_id != self.asset["id"]:
|
||||
raise AssetIdMismatch(
|
||||
(
|
||||
"The asset id of the input does not"
|
||||
" match the asset id of the"
|
||||
" transaction"
|
||||
)
|
||||
)
|
||||
|
||||
input_amount = sum([input_condition.amount for input_condition in input_conditions])
|
||||
output_amount = sum([output_condition.amount for output_condition in self.outputs])
|
||||
input_amount = sum(
|
||||
[input_condition.amount for input_condition in input_conditions]
|
||||
)
|
||||
output_amount = sum(
|
||||
[output_condition.amount for output_condition in self.outputs]
|
||||
)
|
||||
|
||||
if output_amount != input_amount:
|
||||
raise AmountError(('The amount used in the inputs `{}`'
|
||||
' needs to be same as the amount used'
|
||||
' in the outputs `{}`')
|
||||
.format(input_amount, output_amount))
|
||||
raise AmountError(
|
||||
(
|
||||
"The amount used in the inputs `{}`"
|
||||
" needs to be same as the amount used"
|
||||
" in the outputs `{}`"
|
||||
).format(input_amount, output_amount)
|
||||
)
|
||||
|
||||
if not self.inputs_valid(input_conditions):
|
||||
raise InvalidSignature('Transaction signature is invalid.')
|
||||
raise InvalidSignature("Transaction signature is invalid.")
|
||||
|
||||
return True
|
||||
|
||||
@ -10,7 +10,7 @@ import rapidjson
|
||||
|
||||
import planetmint
|
||||
from planetmint.transactions.common.exceptions import ValidationError
|
||||
from cryptoconditions import ThresholdSha256, Ed25519Sha256
|
||||
from cryptoconditions import ThresholdSha256, Ed25519Sha256, ZenroomSha256
|
||||
from planetmint.transactions.common.exceptions import ThresholdTooDeep
|
||||
from cryptoconditions.exceptions import UnsupportedTypeError
|
||||
|
||||
@ -43,8 +43,7 @@ def serialize(data):
|
||||
str: JSON formatted string
|
||||
|
||||
"""
|
||||
return rapidjson.dumps(data, skipkeys=False, ensure_ascii=False,
|
||||
sort_keys=True)
|
||||
return rapidjson.dumps(data, skipkeys=False, ensure_ascii=False, sort_keys=True)
|
||||
|
||||
|
||||
def deserialize(data):
|
||||
@ -76,9 +75,9 @@ def validate_txn_obj(obj_name, obj, key, validation_fun):
|
||||
Raises:
|
||||
ValidationError: `validation_fun` will raise exception on failure
|
||||
"""
|
||||
backend = planetmint.config['database']['backend']
|
||||
backend = planetmint.config["database"]["backend"]
|
||||
|
||||
if backend == 'localmongodb':
|
||||
if backend == "localmongodb":
|
||||
data = obj.get(key, {})
|
||||
if isinstance(data, dict):
|
||||
validate_all_keys_in_obj(obj_name, data, validation_fun)
|
||||
@ -162,10 +161,12 @@ def validate_key(obj_name, key):
|
||||
Raises:
|
||||
ValidationError: will raise exception in case of regex match.
|
||||
"""
|
||||
if re.search(r'^[$]|\.|\x00', key):
|
||||
error_str = ('Invalid key name "{}" in {} object. The '
|
||||
'key name cannot contain characters '
|
||||
'".", "$" or null characters').format(key, obj_name)
|
||||
if re.search(r"^[$]|\.|\x00", key):
|
||||
error_str = (
|
||||
'Invalid key name "{}" in {} object. The '
|
||||
"key name cannot contain characters "
|
||||
'".", "$" or null characters'
|
||||
).format(key, obj_name)
|
||||
raise ValidationError(error_str)
|
||||
|
||||
|
||||
@ -176,27 +177,26 @@ def _fulfillment_to_details(fulfillment):
|
||||
fulfillment: Crypto-conditions Fulfillment object
|
||||
"""
|
||||
|
||||
if fulfillment.type_name == 'ed25519-sha-256':
|
||||
if fulfillment.type_name == "ed25519-sha-256":
|
||||
return {
|
||||
'type': 'ed25519-sha-256',
|
||||
'public_key': base58.b58encode(fulfillment.public_key).decode(),
|
||||
"type": "ed25519-sha-256",
|
||||
"public_key": base58.b58encode(fulfillment.public_key).decode(),
|
||||
}
|
||||
|
||||
if fulfillment.type_name == 'threshold-sha-256':
|
||||
if fulfillment.type_name == "threshold-sha-256":
|
||||
subconditions = [
|
||||
_fulfillment_to_details(cond['body'])
|
||||
for cond in fulfillment.subconditions
|
||||
_fulfillment_to_details(cond["body"]) for cond in fulfillment.subconditions
|
||||
]
|
||||
return {
|
||||
'type': 'threshold-sha-256',
|
||||
'threshold': fulfillment.threshold,
|
||||
'subconditions': subconditions,
|
||||
"type": "threshold-sha-256",
|
||||
"threshold": fulfillment.threshold,
|
||||
"subconditions": subconditions,
|
||||
}
|
||||
if fulfillment.type_name == 'zenroom-sha-256':
|
||||
if fulfillment.type_name == "zenroom-sha-256":
|
||||
return {
|
||||
'type': 'zenroom-sha-256',
|
||||
'public_key': base58.b58encode(fulfillment.public_key).decode(),
|
||||
'script': base58.b58encode(fulfillment.script).decode(),
|
||||
"type": "zenroom-sha-256",
|
||||
"public_key": base58.b58encode(fulfillment.public_key).decode(),
|
||||
"script": base58.b58encode(fulfillment.script).decode(),
|
||||
}
|
||||
|
||||
raise UnsupportedTypeError(fulfillment.type_name)
|
||||
@ -211,20 +211,22 @@ def _fulfillment_from_details(data, _depth=0):
|
||||
if _depth == 100:
|
||||
raise ThresholdTooDeep()
|
||||
|
||||
if data['type'] == 'ed25519-sha-256':
|
||||
public_key = base58.b58decode(data['public_key'])
|
||||
if data["type"] == "ed25519-sha-256":
|
||||
public_key = base58.b58decode(data["public_key"])
|
||||
return Ed25519Sha256(public_key=public_key)
|
||||
|
||||
if data['type'] == 'threshold-sha-256':
|
||||
threshold = ThresholdSha256(data['threshold'])
|
||||
for cond in data['subconditions']:
|
||||
if data["type"] == "threshold-sha-256":
|
||||
threshold = ThresholdSha256(data["threshold"])
|
||||
for cond in data["subconditions"]:
|
||||
cond = _fulfillment_from_details(cond, _depth + 1)
|
||||
threshold.add_subfulfillment(cond)
|
||||
return threshold
|
||||
|
||||
if data['type'] == 'zenroom-sha-256':
|
||||
public_key = base58.b58decode(data['public_key'])
|
||||
script = base58.b58decode(data['script'])
|
||||
zenroom = ZenroomSha256( script= script, data=None , keys= {public_key})
|
||||
if data["type"] == "zenroom-sha-256":
|
||||
public_key = base58.b58decode(data["public_key"])
|
||||
script = base58.b58decode(data["script"])
|
||||
# zenroom = ZenroomSha256(script=script, data=None, keys={public_key})
|
||||
# TODO: assign to zenroom and evaluate the outcome
|
||||
ZenroomSha256(script=script, data=None, keys={public_key})
|
||||
|
||||
raise UnsupportedTypeError(data.get('type'))
|
||||
raise UnsupportedTypeError(data.get("type"))
|
||||
|
||||
@ -2,7 +2,6 @@ import pytest
|
||||
import json
|
||||
import base58
|
||||
from hashlib import sha3_256
|
||||
import cryptoconditions as cc
|
||||
from cryptoconditions.types.ed25519 import Ed25519Sha256
|
||||
from cryptoconditions.types.zenroom import ZenroomSha256
|
||||
from planetmint.transactions.common.crypto import generate_key_pair
|
||||
@ -14,16 +13,14 @@ CONDITION_SCRIPT = """
|
||||
When I create the signature of 'houses'
|
||||
Then print the 'signature'"""
|
||||
|
||||
FULFILL_SCRIPT = \
|
||||
"""Scenario 'ecdh': Bob verifies the signature from Alice
|
||||
FULFILL_SCRIPT = """Scenario 'ecdh': Bob verifies the signature from Alice
|
||||
Given I have a 'ecdh public key' from 'Alice'
|
||||
Given that I have a 'string dictionary' named 'houses' inside 'asset'
|
||||
Given I have a 'signature' named 'signature' inside 'result'
|
||||
When I verify the 'houses' has a signature in 'signature' by 'Alice'
|
||||
Then print the string 'ok'"""
|
||||
|
||||
SK_TO_PK = \
|
||||
"""Scenario 'ecdh': Create the keypair
|
||||
SK_TO_PK = """Scenario 'ecdh': Create the keypair
|
||||
Given that I am known as '{}'
|
||||
Given I have the 'keyring'
|
||||
When I create the ecdh public key
|
||||
@ -31,16 +28,13 @@ SK_TO_PK = \
|
||||
Then print my 'ecdh public key'
|
||||
Then print my 'bitcoin address'"""
|
||||
|
||||
GENERATE_KEYPAIR = \
|
||||
"""Scenario 'ecdh': Create the keypair
|
||||
GENERATE_KEYPAIR = """Scenario 'ecdh': Create the keypair
|
||||
Given that I am known as 'Pippo'
|
||||
When I create the ecdh key
|
||||
When I create the bitcoin key
|
||||
Then print data"""
|
||||
|
||||
ZENROOM_DATA = {
|
||||
'also': 'more data'
|
||||
}
|
||||
ZENROOM_DATA = {"also": "more data"}
|
||||
|
||||
HOUSE_ASSETS = {
|
||||
"data": {
|
||||
@ -52,49 +46,51 @@ HOUSE_ASSETS = {
|
||||
{
|
||||
"name": "Draco",
|
||||
"team": "Slytherin",
|
||||
}
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
metadata = {
|
||||
'units': 300,
|
||||
'type': 'KG'
|
||||
}
|
||||
metadata = {"units": 300, "type": "KG"}
|
||||
|
||||
|
||||
def test_manual_tx_crafting_ext():
|
||||
|
||||
producer, buyer, reseller = generate_key_pair(), generate_key_pair(), generate_key_pair()
|
||||
producer = generate_key_pair()
|
||||
|
||||
producer_ed25519 = Ed25519Sha256(public_key=base58.b58decode(producer.public_key))
|
||||
condition_uri = producer_ed25519.condition.serialize_uri()
|
||||
output = {
|
||||
'amount': '3000',
|
||||
'condition': {
|
||||
'details': {
|
||||
"type": "ed25519-sha-256",
|
||||
"public_key": producer.public_key
|
||||
"amount": "3000",
|
||||
"condition": {
|
||||
"details": {"type": "ed25519-sha-256", "public_key": producer.public_key},
|
||||
"uri": condition_uri,
|
||||
},
|
||||
'uri': condition_uri,
|
||||
|
||||
},
|
||||
'public_keys': [producer.public_key,],
|
||||
"public_keys": [
|
||||
producer.public_key,
|
||||
],
|
||||
}
|
||||
input_ = {
|
||||
'fulfillment': None,
|
||||
'fulfills': None,
|
||||
'owners_before': [producer.public_key,]
|
||||
"fulfillment": None,
|
||||
"fulfills": None,
|
||||
"owners_before": [
|
||||
producer.public_key,
|
||||
],
|
||||
}
|
||||
version = '2.0'
|
||||
version = "2.0"
|
||||
|
||||
prepared_token_tx = {
|
||||
'operation': 'CREATE',
|
||||
'asset': HOUSE_ASSETS,#rfid_token,
|
||||
'metadata': metadata,
|
||||
'outputs': [output,],
|
||||
'inputs': [input_,],
|
||||
'version': version,
|
||||
'id': None,
|
||||
"operation": "CREATE",
|
||||
"asset": HOUSE_ASSETS, # rfid_token,
|
||||
"metadata": metadata,
|
||||
"outputs": [
|
||||
output,
|
||||
],
|
||||
"inputs": [
|
||||
input_,
|
||||
],
|
||||
"version": version,
|
||||
"id": None,
|
||||
}
|
||||
|
||||
print(f"prepared: {prepared_token_tx}")
|
||||
@ -103,7 +99,7 @@ def test_manual_tx_crafting_ext():
|
||||
message = json.dumps(
|
||||
prepared_token_tx,
|
||||
sort_keys=True,
|
||||
separators=(',', ':'),
|
||||
separators=(",", ":"),
|
||||
ensure_ascii=False,
|
||||
)
|
||||
message_hash = sha3_256(message.encode())
|
||||
@ -112,71 +108,77 @@ def test_manual_tx_crafting_ext():
|
||||
|
||||
fulfillment_uri = producer_ed25519.serialize_uri()
|
||||
|
||||
prepared_token_tx['inputs'][0]['fulfillment'] = fulfillment_uri
|
||||
prepared_token_tx["inputs"][0]["fulfillment"] = fulfillment_uri
|
||||
|
||||
json_str_tx = json.dumps(
|
||||
prepared_token_tx,
|
||||
sort_keys=True,
|
||||
separators=(',', ':'),
|
||||
separators=(",", ":"),
|
||||
ensure_ascii=False,
|
||||
)
|
||||
creation_txid = sha3_256(json_str_tx.encode()).hexdigest()
|
||||
|
||||
prepared_token_tx['id'] = creation_txid
|
||||
prepared_token_tx["id"] = creation_txid
|
||||
|
||||
print(f"signed: {prepared_token_tx}")
|
||||
|
||||
from planetmint.transactions.types.assets.create import Create
|
||||
from planetmint.transactions.types.assets.transfer import Transfer
|
||||
from planetmint.models import Transaction
|
||||
from planetmint.transactions.common.exceptions import SchemaValidationError, ValidationError
|
||||
from flask import current_app
|
||||
from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_ASYNC
|
||||
from planetmint.transactions.common.exceptions import (
|
||||
SchemaValidationError,
|
||||
ValidationError,
|
||||
)
|
||||
|
||||
validated = None
|
||||
try:
|
||||
tx_obj = Transaction.from_dict(prepared_token_tx)
|
||||
except SchemaValidationError as e:
|
||||
except SchemaValidationError:
|
||||
assert ()
|
||||
except ValidationError as e:
|
||||
print(e)
|
||||
assert ()
|
||||
|
||||
from planetmint.lib import Planetmint
|
||||
|
||||
planet = Planetmint()
|
||||
validated = planet.validate_transaction(tx_obj)
|
||||
print(f"\n\nVALIDATED =====: {validated}")
|
||||
assert not validated == False
|
||||
assert validated == False is False
|
||||
|
||||
|
||||
def test_manual_tx_crafting_ext_zenroom():
|
||||
producer = generate_key_pair()
|
||||
producer_ed25519 = Ed25519Sha256(public_key=base58.b58decode(producer.public_key))
|
||||
condition_uri = producer_ed25519.condition.serialize_uri()
|
||||
output = {
|
||||
'amount': '3000',
|
||||
'condition': {
|
||||
'details': {
|
||||
"type": "ed25519-sha-256",
|
||||
"public_key": producer.public_key
|
||||
"amount": "3000",
|
||||
"condition": {
|
||||
"details": {"type": "ed25519-sha-256", "public_key": producer.public_key},
|
||||
"uri": condition_uri,
|
||||
},
|
||||
'uri': condition_uri,
|
||||
|
||||
},
|
||||
'public_keys': [producer.public_key,],
|
||||
"public_keys": [
|
||||
producer.public_key,
|
||||
],
|
||||
}
|
||||
input_ = {
|
||||
'fulfillment': None,
|
||||
'fulfills': None,
|
||||
'owners_before': [producer.public_key,]
|
||||
"fulfillment": None,
|
||||
"fulfills": None,
|
||||
"owners_before": [
|
||||
producer.public_key,
|
||||
],
|
||||
}
|
||||
version = '2.0'
|
||||
version = "2.0"
|
||||
prepared_token_tx = {
|
||||
'operation': 'CREATE',
|
||||
'asset': HOUSE_ASSETS,#rfid_token,
|
||||
'metadata': metadata,
|
||||
'outputs': [output,],
|
||||
'inputs': [input_,],
|
||||
'version': version,
|
||||
'id': None,
|
||||
"operation": "CREATE",
|
||||
"asset": HOUSE_ASSETS, # rfid_token,
|
||||
"metadata": metadata,
|
||||
"outputs": [
|
||||
output,
|
||||
],
|
||||
"inputs": [
|
||||
input_,
|
||||
],
|
||||
"version": version,
|
||||
"id": None,
|
||||
}
|
||||
|
||||
print(f"prepared: {prepared_token_tx}")
|
||||
@ -185,7 +187,7 @@ def test_manual_tx_crafting_ext_zenroom():
|
||||
message = json.dumps(
|
||||
prepared_token_tx,
|
||||
sort_keys=True,
|
||||
separators=(',', ':'),
|
||||
separators=(",", ":"),
|
||||
ensure_ascii=False,
|
||||
)
|
||||
message_hash = sha3_256(message.encode())
|
||||
@ -194,97 +196,114 @@ def test_manual_tx_crafting_ext_zenroom():
|
||||
|
||||
fulfillment_uri = producer_ed25519.serialize_uri()
|
||||
|
||||
prepared_token_tx['inputs'][0]['fulfillment'] = fulfillment_uri
|
||||
prepared_token_tx["inputs"][0]["fulfillment"] = fulfillment_uri
|
||||
|
||||
json_str_tx = json.dumps(
|
||||
prepared_token_tx,
|
||||
sort_keys=True,
|
||||
separators=(',', ':'),
|
||||
separators=(",", ":"),
|
||||
ensure_ascii=False,
|
||||
)
|
||||
creation_txid = sha3_256(json_str_tx.encode()).hexdigest()
|
||||
|
||||
prepared_token_tx['id'] = creation_txid
|
||||
prepared_token_tx["id"] = creation_txid
|
||||
|
||||
print(f"signed: {prepared_token_tx}")
|
||||
|
||||
from planetmint.transactions.types.assets.create import Create
|
||||
from planetmint.transactions.types.assets.transfer import Transfer
|
||||
from planetmint.models import Transaction
|
||||
from planetmint.transactions.common.exceptions import SchemaValidationError, ValidationError
|
||||
from flask import current_app
|
||||
from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_ASYNC
|
||||
from planetmint.transactions.common.exceptions import (
|
||||
SchemaValidationError,
|
||||
ValidationError,
|
||||
)
|
||||
|
||||
validated = None
|
||||
try:
|
||||
tx_obj = Transaction.from_dict(prepared_token_tx)
|
||||
except SchemaValidationError as e:
|
||||
except SchemaValidationError:
|
||||
assert ()
|
||||
except ValidationError as e:
|
||||
print(e)
|
||||
assert ()
|
||||
|
||||
from planetmint.lib import Planetmint
|
||||
|
||||
planet = Planetmint()
|
||||
validated = planet.validate_transaction(tx_obj)
|
||||
print(f"\n\nVALIDATED =====: {validated}")
|
||||
assert not validated == False
|
||||
assert validated == False is False
|
||||
|
||||
|
||||
def test_zenroom_signing():
|
||||
|
||||
biolabs = generate_key_pair()
|
||||
version = '2.0'
|
||||
version = "2.0"
|
||||
|
||||
alice = json.loads(ZenroomSha256.run_zenroom(GENERATE_KEYPAIR).output)['keyring']
|
||||
bob = json.loads(ZenroomSha256.run_zenroom(GENERATE_KEYPAIR).output)['keyring']
|
||||
alice = json.loads(ZenroomSha256.run_zenroom(GENERATE_KEYPAIR).output)["keyring"]
|
||||
bob = json.loads(ZenroomSha256.run_zenroom(GENERATE_KEYPAIR).output)["keyring"]
|
||||
|
||||
zen_public_keys = json.loads(ZenroomSha256.run_zenroom(SK_TO_PK.format('Alice'),
|
||||
keys={'keyring': alice}).output)
|
||||
zen_public_keys.update(json.loads(ZenroomSha256.run_zenroom(SK_TO_PK.format('Bob'),
|
||||
keys={'keyring': bob}).output))
|
||||
zen_public_keys = json.loads(
|
||||
ZenroomSha256.run_zenroom(
|
||||
SK_TO_PK.format("Alice"), keys={"keyring": alice}
|
||||
).output
|
||||
)
|
||||
zen_public_keys.update(
|
||||
json.loads(
|
||||
ZenroomSha256.run_zenroom(
|
||||
SK_TO_PK.format("Bob"), keys={"keyring": bob}
|
||||
).output
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
zenroomscpt = ZenroomSha256(script=FULFILL_SCRIPT, data=ZENROOM_DATA, keys=zen_public_keys)
|
||||
print(F'zenroom is: {zenroomscpt.script}')
|
||||
zenroomscpt = ZenroomSha256(
|
||||
script=FULFILL_SCRIPT, data=ZENROOM_DATA, keys=zen_public_keys
|
||||
)
|
||||
print(f"zenroom is: {zenroomscpt.script}")
|
||||
|
||||
# CRYPTO-CONDITIONS: generate the condition uri
|
||||
condition_uri_zen = zenroomscpt.condition.serialize_uri()
|
||||
print(F'\nzenroom condition URI: {condition_uri_zen}')
|
||||
print(f"\nzenroom condition URI: {condition_uri_zen}")
|
||||
|
||||
# CRYPTO-CONDITIONS: construct an unsigned fulfillment dictionary
|
||||
unsigned_fulfillment_dict_zen = {
|
||||
'type': zenroomscpt.TYPE_NAME,
|
||||
'public_key': base58.b58encode(biolabs.public_key).decode(),
|
||||
"type": zenroomscpt.TYPE_NAME,
|
||||
"public_key": base58.b58encode(biolabs.public_key).decode(),
|
||||
}
|
||||
output = {
|
||||
'amount': '10',
|
||||
'condition': {
|
||||
'details': unsigned_fulfillment_dict_zen,
|
||||
'uri': condition_uri_zen,
|
||||
|
||||
"amount": "10",
|
||||
"condition": {
|
||||
"details": unsigned_fulfillment_dict_zen,
|
||||
"uri": condition_uri_zen,
|
||||
},
|
||||
'public_keys': [biolabs.public_key,],
|
||||
"public_keys": [
|
||||
biolabs.public_key,
|
||||
],
|
||||
}
|
||||
input_ = {
|
||||
'fulfillment': None,
|
||||
'fulfills': None,
|
||||
'owners_before': [biolabs.public_key,]
|
||||
"fulfillment": None,
|
||||
"fulfills": None,
|
||||
"owners_before": [
|
||||
biolabs.public_key,
|
||||
],
|
||||
}
|
||||
token_creation_tx = {
|
||||
'operation': 'CREATE',
|
||||
'asset': HOUSE_ASSETS,
|
||||
'metadata': None,
|
||||
'outputs': [output,],
|
||||
'inputs': [input_,],
|
||||
'version': version,
|
||||
'id': None,
|
||||
"operation": "CREATE",
|
||||
"asset": HOUSE_ASSETS,
|
||||
"metadata": None,
|
||||
"outputs": [
|
||||
output,
|
||||
],
|
||||
"inputs": [
|
||||
input_,
|
||||
],
|
||||
"version": version,
|
||||
"id": None,
|
||||
}
|
||||
|
||||
# JSON: serialize the transaction-without-id to a json formatted string
|
||||
message = json.dumps(
|
||||
token_creation_tx,
|
||||
sort_keys=True,
|
||||
separators=(',', ':'),
|
||||
separators=(",", ":"),
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
@ -294,44 +313,38 @@ def test_zenroom_signing():
|
||||
#
|
||||
# the server should ick the fulfill script and recreate the zenroom-sha and verify the signature
|
||||
|
||||
|
||||
|
||||
message = zenroomscpt.sign(message, CONDITION_SCRIPT, alice)
|
||||
assert(zenroomscpt.validate(message=message))
|
||||
assert zenroomscpt.validate(message=message)
|
||||
|
||||
message = json.loads(message)
|
||||
fulfillment_uri_zen = zenroomscpt.serialize_uri()
|
||||
|
||||
message['inputs'][0]['fulfillment'] = fulfillment_uri_zen
|
||||
message["inputs"][0]["fulfillment"] = fulfillment_uri_zen
|
||||
tx = message
|
||||
tx['id'] = None
|
||||
json_str_tx = json.dumps(
|
||||
tx,
|
||||
sort_keys=True,
|
||||
skipkeys=False,
|
||||
separators=(',', ':')
|
||||
)
|
||||
tx["id"] = None
|
||||
json_str_tx = json.dumps(tx, sort_keys=True, skipkeys=False, separators=(",", ":"))
|
||||
# SHA3: hash the serialized id-less transaction to generate the id
|
||||
shared_creation_txid = sha3_256(json_str_tx.encode()).hexdigest()
|
||||
message['id'] = shared_creation_txid
|
||||
message["id"] = shared_creation_txid
|
||||
|
||||
|
||||
from planetmint.transactions.types.assets.create import Create
|
||||
from planetmint.transactions.types.assets.transfer import Transfer
|
||||
from planetmint.models import Transaction
|
||||
from planetmint.transactions.common.exceptions import SchemaValidationError, ValidationError
|
||||
from flask import current_app
|
||||
from planetmint.transactions.common.exceptions import (
|
||||
SchemaValidationError,
|
||||
ValidationError,
|
||||
)
|
||||
from planetmint.transactions.common.transaction_mode_types import BROADCAST_TX_ASYNC
|
||||
|
||||
validated = None
|
||||
try:
|
||||
tx_obj = Transaction.from_dict(message)
|
||||
except SchemaValidationError as e:
|
||||
except SchemaValidationError:
|
||||
assert ()
|
||||
except ValidationError as e:
|
||||
print(e)
|
||||
assert ()
|
||||
|
||||
from planetmint.lib import Planetmint
|
||||
|
||||
planet = Planetmint()
|
||||
validated = planet.validate_transaction(tx_obj)
|
||||
|
||||
@ -339,5 +352,4 @@ def test_zenroom_signing():
|
||||
status_code, message = planet.write_transaction(tx_obj, mode)
|
||||
print(f"\n\nstatus and result : {status_code} + {message}")
|
||||
print(f"VALIDATED : {validated}")
|
||||
|
||||
|
||||
assert (validated == False) is False
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user