diff --git a/duniterpy/documents/transaction.py b/duniterpy/documents/transaction.py index 3e4e3ea10d085f37a8c8488a1dcbeae9c01244f7..21e4ba106f86ff114293047007b0cd3b26097d43 100644 --- a/duniterpy/documents/transaction.py +++ b/duniterpy/documents/transaction.py @@ -549,7 +549,7 @@ class Transaction(Document): outputs: List[OutputSource], comment: str, time: Optional[int] = None, - signing_key: SigningKey = None, + signing_keys: Optional[Union[SigningKey, List[SigningKey]]] = None, version: int = VERSION, currency: str = G1_CURRENCY_CODENAME, ) -> None: @@ -564,7 +564,7 @@ class Transaction(Document): :param outputs: List of OutputSource instances :param comment: Comment field :param time: time when the transaction enters the blockchain - :param signing_key: SigningKey instance to sign the document (default=None) + :param signing_keys: SigningKey or list of SigningKey instances to sign the document (default=None) :param version: Document version (default=transaction.VERSION) :param currency: Currency codename (default=constants.CURRENCY_CODENAME_G1) """ @@ -579,8 +579,8 @@ class Transaction(Document): self.time = time self.signatures: List[str] = list() - if signing_key is not None: - self.sign(signing_key) + if signing_keys: + self.multi_sign(signing_keys) def __eq__(self, other: Any) -> bool: """ @@ -591,7 +591,6 @@ class Transaction(Document): return ( self.version == other.version and self.currency == other.currency - and self.signature == other.signature and self.signatures == other.signatures and self.blockstamp == other.blockstamp and self.locktime == other.locktime @@ -608,7 +607,6 @@ class Transaction(Document): ( self.version, self.currency, - self.signature, self.signatures, self.blockstamp, self.locktime, @@ -744,10 +742,7 @@ Comment: {comment} ) # return transaction with signatures - if len(signatures) > 1: - transaction.signatures = signatures - else: - transaction.signature = signatures[0] + transaction.signatures = signatures return transaction @classmethod @@ -837,11 +832,7 @@ Comment: {comment} ) # return transaction with signatures - if len(signatures) > 1: - transaction.signatures = signatures - else: - transaction.signature = signatures[0] - + transaction.signatures = signatures return transaction def raw(self) -> str: @@ -917,11 +908,8 @@ Currency: {1} doc += "{0}\n".format(o.inline()) if self.comment != "": doc += "{0}\n".format(self.comment) - if self.signature is not None: - doc += "{0}\n".format(self.signature) - else: - for signature in self.signatures: - doc += "{0}\n".format(signature) + for signature in self.signatures: + doc += "{0}\n".format(signature) return doc @@ -931,44 +919,49 @@ Currency: {1} :return: """ - if self.signature is None and len(self.signatures) == 0: + if not self.signatures: raise MalformedDocumentError("No signature, can not create raw format") - raw = self.raw() - if self.signature is not None: - signed_raw = raw + self.signature + "\n" - else: - signed_raw = raw - for signature in self.signatures: - signed_raw += "{0}\n".format(signature) + signed_raw = self.raw() + for signature in self.signatures: + signed_raw += f"{signature}\n" return signed_raw - def multi_sign(self, keys: List[SigningKey]) -> None: + def sign(self, key: SigningKey) -> None: + raise Exception("sign() is not implemented, use multi_sign()") + + def multi_sign(self, keys: Union[SigningKey, List[SigningKey]]) -> None: """ Sign the current document with multiple keys - Warning : current signatures will be replaced with the new ones. - - :param keys: List of libnacl keys instance + :param keys: Libnacl key or list of them """ - self.signatures = list() + if isinstance(keys, SigningKey): + keys = [keys] + for key in keys: signature = base64.b64encode(key.signature(bytes(self.raw(), "ascii"))) logging.debug("Signature : \n%s", signature.decode("ascii")) self.signatures.append(signature.decode("ascii")) - def check_signatures(self, pubkeys: List[str]): + def check_signature(self, pubkey: str): + raise Exception("check_signature() is not implemented, use check_signatures()") + + def check_signatures(self, pubkeys: Union[str, List[str]]): """ Check if the signatures matches the pubkeys - :param pubkeys: List of Base58 public keys + :param pubkeys: Base58 public key or list of them :return: """ - if len(self.signatures) == 0: + if not self.signatures: raise Exception("No signatures, can not check signatures") + if isinstance(pubkeys, str): + pubkeys = [pubkeys] + if len(self.signatures) != len(pubkeys): raise Exception("Number of pubkeys not equal to number of signatures") @@ -998,7 +991,7 @@ class SimpleTransaction(Transaction): outputs: List[OutputSource], comment: str, time: int = 0, - signing_key: SigningKey = None, + signing_keys: Optional[Union[SigningKey, List[SigningKey]]] = None, version: int = VERSION, currency: str = G1_CURRENCY_CODENAME, ) -> None: @@ -1013,7 +1006,7 @@ class SimpleTransaction(Transaction): :param outputs: List of OutputSource instances :param comment: Comment field :param time: time when the transaction enters the blockchain (default=0) - :param signing_key: SigningKey instance to sign the document (default=None) + :param signing_keys: SigningKey instance to sign the document (default=None) :param version: Document version (default=transaction.VERSION) :param currency: Currency codename (default=constants.CURRENCY_CODENAME_G1) """ @@ -1026,7 +1019,7 @@ class SimpleTransaction(Transaction): outputs, comment, time=time, - signing_key=signing_key, + signing_keys=signing_keys, version=version, currency=currency, ) diff --git a/examples/send_transaction.py b/examples/send_transaction.py index 7560facd53bfb1bf756256b2aa5153dba14d8c0e..1ddf631b459808802502b3c4120ff813324a0ad9 100644 --- a/examples/send_transaction.py +++ b/examples/send_transaction.py @@ -15,6 +15,7 @@ import getpass import urllib +from typing import List, Union from duniterpy.api import bma from duniterpy.api.client import Client @@ -42,7 +43,7 @@ def get_transaction_document( source: dict, from_pubkey: str, to_pubkey: str, - signing_key: SigningKey, + signing_keys: Union[SigningKey, List[SigningKey]], ) -> Transaction: """ Return a Transaction document @@ -96,7 +97,7 @@ def get_transaction_document( unlocks=unlocks, outputs=outputs, comment="", - signing_key=signing_key, + signing_keys=signing_keys, currency=current_block["currency"], ) diff --git a/tests/key/test_verifying_key.py b/tests/key/test_verifying_key.py index c6ffb7aed812312dca076169237216ccf3baf715..38016937b67d00cd8d3ee90b7024d29075aca922 100644 --- a/tests/key/test_verifying_key.py +++ b/tests/key/test_verifying_key.py @@ -147,4 +147,4 @@ Solde huile Millepertuis rgjOmzFH5h+hkDbJLk1b88X7Z83HMgTa5rBckeMSdF/yZtItN3zMn09MphcXjffdrKcK+MebwoisLJqV+jXrDg== """ tx = Transaction.from_compact(transaction_document, "g1") - self.assertTrue(tx.check_signature(tx.issuers[0])) + self.assertTrue(tx.check_signatures(tx.issuers))