diff --git a/examples/example_get_node_info.py b/examples/example_get_node_info.py index 2ef479d..b32420a 100644 --- a/examples/example_get_node_info.py +++ b/examples/example_get_node_info.py @@ -10,7 +10,7 @@ def main() -> None: # Creating a stub from channel stub = NetworkStub(channel) - # Initialize a request and call get consensus info method + # Initialize a request and call get node info method req = GetNodeInfoRequest() res = stub.GetNodeInfo(req) diff --git a/examples/example_multisig.py b/examples/example_multisig.py index f25dc8b..84f3b91 100644 --- a/examples/example_multisig.py +++ b/examples/example_multisig.py @@ -1,5 +1,6 @@ from pactus.crypto.bls.signature import Signature + def main() -> None: sig1 = Signature.from_string( "a628a8709fe00366d7150244447cc43e8637d76a20674b006b00f7a61109dab53ba5f1f66cd07219fd1e4a6bc7299d2d" diff --git a/examples/example_transfer_transaction_bls.py b/examples/example_transfer_transaction_bls.py index d9b4926..f03d86f 100644 --- a/examples/example_transfer_transaction_bls.py +++ b/examples/example_transfer_transaction_bls.py @@ -22,7 +22,7 @@ def main() -> None: tx = Transaction.create_transfer_tx(lock_time, sender, receiver, amount, fee, memo) signed_tx = tx.sign(sec) - print(f"Signed transaction hex: {signed_tx}") + print(f"Signed transaction hex: {signed_tx.hex()}") if __name__ == "__main__": diff --git a/examples/example_transfer_transaction_ed25519.py b/examples/example_transfer_transaction_ed25519.py index c89abe3..f1c9d5a 100644 --- a/examples/example_transfer_transaction_ed25519.py +++ b/examples/example_transfer_transaction_ed25519.py @@ -22,7 +22,7 @@ def main() -> None: tx = Transaction.create_transfer_tx(lock_time, sender, receiver, amount, fee, memo) signed_tx = tx.sign(sec) - print(f"Signed transaction hex: {signed_tx}") + print(f"Signed transaction hex: {signed_tx.hex()}") if __name__ == "__main__": diff --git a/pactus/transaction/transaction.py b/pactus/transaction/transaction.py index 039f027..55e82fe 100644 --- a/pactus/transaction/transaction.py +++ b/pactus/transaction/transaction.py @@ -79,7 +79,13 @@ def create_withdraw_tx( return cls(lock_time, fee, memo, payload) def _get_unsigned_bytes(self, buf: bytes) -> bytes: - """Get unsigned bytes of the transaction, including the payload.""" + """ + Generate the unsigned representation of the transaction, + including flags and payload. + + This method appends various transaction components to the buffer + in a specific order, ensuring correct serialization. + """ encoding.append_uint8(buf, self.flags) encoding.append_uint8(buf, self.version) encoding.append_uint32(buf, self.lock_time) @@ -90,17 +96,37 @@ def _get_unsigned_bytes(self, buf: bytes) -> bytes: return buf - def sign(self, private_key: PrivateKey) -> str: - """Make a raw transaction, sign it and return the signed bytes.""" + def sign_bytes(self) -> bytes: + """ + Generate the transaction data that needs to be signed. + + The signature should be computed over this data, excluding the + transaction flags, which are removed before returning. + """ + buf = bytearray() + sign_bytes = self._get_unsigned_bytes(buf) + + return sign_bytes[1:] # flags is not part of the sign bytes. + + def sign(self, private_key: PrivateKey) -> bytes: + """ + Generate the signed representation of the transaction, + including the flags, payload, and cryptographic signature. + + This method first generates the data needs to be signed, + signs it using the provided private key, and then appends + both the signature and the corresponding public key to ensure + verifiability. + """ buf = bytearray() sign_bytes = self._get_unsigned_bytes(buf) sig = private_key.sign( bytes(sign_bytes[1:]), - ) # flags is not part of the sign bytes. + ) pub = private_key.public_key() encoding.append_fixed_bytes(buf, sig.raw_bytes()) encoding.append_fixed_bytes(buf, pub.raw_bytes()) - return buf.hex() + return buf diff --git a/tests/test_transaction.py b/tests/test_transaction.py index 7a465c6..34bd113 100644 --- a/tests/test_transaction.py +++ b/tests/test_transaction.py @@ -20,9 +20,9 @@ def test_sign_transfer(self): tx = Transaction.create_transfer_tx( lock_time, sender, receiver, amount, fee, memo ) - signed_data = tx.sign(prv) - expected_data = ( + signed_data = tx.sign(prv) + expected_signed_data = ( "00" # Flags "01" # Version "56341200" # LockTime @@ -36,9 +36,21 @@ def test_sign_transfer(self): + "af0f74917f5065af94727ae9541b0ddcfb5b828a9e016b02498f477ed37fb44d5d882495afb6fd4f9773e4ea9deee436" # Public Key + "030c4d61c6e3a1151585e1d838cae1444a438d089ce77e10c492a55f6908125c5be9b236a246e4082d08de564e111e65" ) - self.maxDiff = None - self.assertEqual(expected_data, signed_data) + self.assertEqual(expected_signed_data, signed_data.hex()) + + sign_bytes = tx.sign_bytes() + expected_sign_bytes = ( + "01" # Version + "56341200" # LockTime + "c0843d" # Fee + "0474657374" # Memo + "01" # PayloadType + + "02a195d7fecba4c636832f1db0cd0ea14db6db8c71" # Sender + + "025e81869376b54f8a360f48930ea741e3b8771db2" # Receiver + + "8094ebdc03" # Amount + ) + self.assertEqual(expected_sign_bytes, sign_bytes.hex()) if __name__ == "__main__":