Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/example_get_node_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
1 change: 1 addition & 0 deletions examples/example_multisig.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from pactus.crypto.bls.signature import Signature


def main() -> None:
sig1 = Signature.from_string(
"a628a8709fe00366d7150244447cc43e8637d76a20674b006b00f7a61109dab53ba5f1f66cd07219fd1e4a6bc7299d2d"
Expand Down
2 changes: 1 addition & 1 deletion examples/example_transfer_transaction_bls.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__":
Expand Down
2 changes: 1 addition & 1 deletion examples/example_transfer_transaction_ed25519.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__":
Expand Down
36 changes: 31 additions & 5 deletions pactus/transaction/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
20 changes: 16 additions & 4 deletions tests/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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__":
Expand Down