mirror of
https://github.com/planetmint/planetmint.git
synced 2025-06-08 15:16:37 +00:00
Added Create and Transfer as separate transactions
This commit is contained in:
parent
64f5ec01f1
commit
a421533e16
@ -25,13 +25,13 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
from sha3 import sha3_256
|
from sha3 import sha3_256
|
||||||
|
|
||||||
from planetmint.common.crypto import PrivateKey, hash_data
|
from planetmint.transactions.common.crypto import PrivateKey, hash_data
|
||||||
from planetmint.common.exceptions import (KeypairMismatchException,
|
from planetmint.transactions.common.exceptions import (KeypairMismatchException,
|
||||||
InputDoesNotExist, DoubleSpend,
|
InputDoesNotExist, DoubleSpend,
|
||||||
InvalidHash, InvalidSignature,
|
InvalidHash, InvalidSignature,
|
||||||
AmountError, AssetIdMismatch,
|
AmountError, AssetIdMismatch,
|
||||||
ThresholdTooDeep)
|
ThresholdTooDeep)
|
||||||
from planetmint.common.utils import serialize
|
from planetmint.transactions.common.utils import serialize
|
||||||
from .memoize import memoize_from_dict, memoize_to_dict
|
from .memoize import memoize_from_dict, memoize_to_dict
|
||||||
|
|
||||||
|
|
||||||
|
78
planetmint/transactions/types/assets/create.py
Normal file
78
planetmint/transactions/types/assets/create.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
# Copyright © 2020 Interplanetary Database Association e.V.,
|
||||||
|
# Planetmint and IPDB software contributors.
|
||||||
|
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||||
|
# Code is Apache-2.0 and docs are CC-BY-4.0
|
||||||
|
|
||||||
|
from planetmint.transactions.common.transaction import (Transaction, Input, Output)
|
||||||
|
|
||||||
|
class Create(Transaction):
|
||||||
|
|
||||||
|
OPERATION = 'CREATE'
|
||||||
|
# NOTE: This class inherits TRANSFER txn type. The `TRANSFER` property is
|
||||||
|
# overriden to re-use methods from parent class
|
||||||
|
TRANSFER = OPERATION
|
||||||
|
ALLOWED_OPERATIONS = (OPERATION,)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def validate(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 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')
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate(cls, tx_signers, recipients, metadata=None, asset=None):
|
||||||
|
"""A simple way to generate a `CREATE` transaction.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
This method currently supports the following Cryptoconditions
|
||||||
|
use cases:
|
||||||
|
- Ed25519
|
||||||
|
- ThresholdSha256
|
||||||
|
|
||||||
|
Additionally, it provides support for the following Planetmint
|
||||||
|
use cases:
|
||||||
|
- Multiple inputs and outputs.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tx_signers (:obj:`list` of :obj:`str`): A list of keys that
|
||||||
|
represent the signers of the CREATE Transaction.
|
||||||
|
recipients (:obj:`list` of :obj:`tuple`): A list of
|
||||||
|
([keys],amount) that represent the recipients of this
|
||||||
|
Transaction.
|
||||||
|
metadata (dict): The metadata to be stored along with the
|
||||||
|
Transaction.
|
||||||
|
asset (dict): The metadata associated with the asset that will
|
||||||
|
be created in this Transaction.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:class:`~planetmint.common.transaction.Transaction`
|
||||||
|
"""
|
||||||
|
|
||||||
|
(inputs, outputs) = cls.validate(tx_signers, recipients, asset, metadata)
|
||||||
|
return cls(cls.OPERATION, {'data': asset}, inputs, outputs, metadata)
|
85
planetmint/transactions/types/assets/transfer.py
Normal file
85
planetmint/transactions/types/assets/transfer.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
# Copyright © 2020 Interplanetary Database Association e.V.,
|
||||||
|
# Planetmint and IPDB software contributors.
|
||||||
|
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||||
|
# Code is Apache-2.0 and docs are CC-BY-4.0
|
||||||
|
|
||||||
|
from planetmint.transactions.common.transaction import (Transaction, Input, Output)
|
||||||
|
from planetmint.transactions.common.schema import (_validate_schema,
|
||||||
|
TX_SCHEMA_COMMON,
|
||||||
|
TX_SCHEMA_TRANSFER)
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
class Transfer(Transaction):
|
||||||
|
|
||||||
|
OPERATION = 'TRANSFER'
|
||||||
|
# NOTE: This class inherits TRANSFER txn type. The `TRANSFER` property is
|
||||||
|
# overriden to re-use methods from parent class
|
||||||
|
TRANSFER = OPERATION
|
||||||
|
ALLOWED_OPERATIONS = (OPERATION,)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def validate(cls, inputs, recipients, asset_id, metadata):
|
||||||
|
if not isinstance(inputs, list):
|
||||||
|
raise TypeError('`inputs` must be a list instance')
|
||||||
|
if len(inputs) == 0:
|
||||||
|
raise ValueError('`inputs` must contain at least one item')
|
||||||
|
if not isinstance(recipients, list):
|
||||||
|
raise TypeError('`recipients` must be a list instance')
|
||||||
|
if len(recipients) == 0:
|
||||||
|
raise ValueError('`recipients` list cannot be empty')
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
if not isinstance(asset_id, str):
|
||||||
|
raise TypeError('`asset_id` must be a string')
|
||||||
|
|
||||||
|
return (deepcopy(inputs), outputs)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate(cls, inputs, recipients, asset_id, metadata=None):
|
||||||
|
"""A simple way to generate a `TRANSFER` transaction.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Different cases for threshold conditions:
|
||||||
|
|
||||||
|
Combining multiple `inputs` with an arbitrary number of
|
||||||
|
`recipients` can yield interesting cases for the creation of
|
||||||
|
threshold conditions we'd like to support. The following
|
||||||
|
notation is proposed:
|
||||||
|
|
||||||
|
1. The index of a `recipient` corresponds to the index of
|
||||||
|
an input:
|
||||||
|
e.g. `transfer([input1], [a])`, means `input1` would now be
|
||||||
|
owned by user `a`.
|
||||||
|
|
||||||
|
2. `recipients` can (almost) get arbitrary deeply nested,
|
||||||
|
creating various complex threshold conditions:
|
||||||
|
e.g. `transfer([inp1, inp2], [[a, [b, c]], d])`, means
|
||||||
|
`a`'s signature would have a 50% weight on `inp1`
|
||||||
|
compared to `b` and `c` that share 25% of the leftover
|
||||||
|
weight respectively. `inp2` is owned completely by `d`.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
inputs (:obj:`list` of :class:`~planetmint.common.transaction.
|
||||||
|
Input`): Converted `Output`s, intended to
|
||||||
|
be used as inputs in the transfer to generate.
|
||||||
|
recipients (:obj:`list` of :obj:`tuple`): A list of
|
||||||
|
([keys],amount) that represent the recipients of this
|
||||||
|
Transaction.
|
||||||
|
asset_id (str): The asset ID of the asset to be transferred in
|
||||||
|
this Transaction.
|
||||||
|
metadata (dict): Python dictionary to be stored along with the
|
||||||
|
Transaction.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:class:`~planetmint.common.transaction.Transaction`
|
||||||
|
"""
|
||||||
|
(inputs, outputs) = cls.validate_transfer(inputs, recipients, asset_id, metadata)
|
||||||
|
return cls(cls.OPERATION, {'id': asset_id}, inputs, outputs, metadata)
|
0
planetmint/transactions/types/elections/__init__.py
Normal file
0
planetmint/transactions/types/elections/__init__.py
Normal file
@ -8,16 +8,18 @@ import base58
|
|||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from planetmint import backend
|
from planetmint import backend
|
||||||
from planetmint.elections.vote import Vote
|
from planetmint.transactions.types.assets.create import Create
|
||||||
from planetmint.common.exceptions import (InvalidSignature,
|
from planetmint.transactions.types.assets.transfer import Transfer
|
||||||
|
from planetmint.transactions.types.elections.vote import Vote
|
||||||
|
from planetmint.transactions.common.exceptions import (InvalidSignature,
|
||||||
MultipleInputsError,
|
MultipleInputsError,
|
||||||
InvalidProposer,
|
InvalidProposer,
|
||||||
UnequalValidatorSet,
|
UnequalValidatorSet,
|
||||||
DuplicateTransaction)
|
DuplicateTransaction)
|
||||||
from planetmint.tendermint_utils import key_from_base64, public_key_to_base64
|
from planetmint.tendermint_utils import key_from_base64, public_key_to_base64
|
||||||
from planetmint.common.crypto import (public_key_from_ed25519_key)
|
from planetmint.transactions.common.crypto import (public_key_from_ed25519_key)
|
||||||
from planetmint.common.transaction import Transaction
|
from planetmint.transactions.common.transaction import Transaction
|
||||||
from planetmint.common.schema import (_validate_schema,
|
from planetmint.transactions.common.schema import (_validate_schema,
|
||||||
TX_SCHEMA_COMMON,
|
TX_SCHEMA_COMMON,
|
||||||
TX_SCHEMA_CREATE)
|
TX_SCHEMA_CREATE)
|
||||||
|
|
||||||
@ -161,11 +163,11 @@ class Election(Transaction):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, tx_signers, recipients, metadata=None, asset=None):
|
def create(cls, tx_signers, recipients, metadata=None, asset=None):
|
||||||
raise NotImplementedError
|
Create.generate(tx_signers, recipients, metadata=None, asset=None)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def transfer(cls, tx_signers, recipients, metadata=None, asset=None):
|
def transfer(cls, tx_signers, recipients, metadata=None, asset=None):
|
||||||
raise NotImplementedError
|
Transfer.generate(tx_signers, recipients, metadata=None, asset=None)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def to_public_key(cls, election_id):
|
def to_public_key(cls, election_id):
|
@ -3,8 +3,10 @@
|
|||||||
# 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 planetmint.common.transaction import Transaction
|
from planetmint.transactions.types.assets.create import Create
|
||||||
from planetmint.common.schema import (_validate_schema,
|
from planetmint.transactions.types.assets.transfer import Transfer
|
||||||
|
from planetmint.transactions.common.transaction import Transaction
|
||||||
|
from planetmint.transactions.common.schema import (_validate_schema,
|
||||||
TX_SCHEMA_COMMON,
|
TX_SCHEMA_COMMON,
|
||||||
TX_SCHEMA_TRANSFER,
|
TX_SCHEMA_TRANSFER,
|
||||||
TX_SCHEMA_VOTE)
|
TX_SCHEMA_VOTE)
|
||||||
@ -57,8 +59,8 @@ class Vote(Transaction):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, tx_signers, recipients, metadata=None, asset=None):
|
def create(cls, tx_signers, recipients, metadata=None, asset=None):
|
||||||
raise NotImplementedError
|
return Create.generate(tx_signers, recipients, metadata=None, asset=None)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def transfer(cls, tx_signers, recipients, metadata=None, asset=None):
|
def transfer(cls, tx_signers, recipients, metadata=None, asset=None):
|
||||||
raise NotImplementedError
|
return Transfer.generate(tx_signers, recipients, metadata=None, asset=None)
|
Loading…
x
Reference in New Issue
Block a user