79 lines
3.0 KiB
Python
Raw Normal View History

2025-10-30 11:48:34 +01:00
from typing import List, Self
from pydantic import Field
from core.models import NbeSerializer
from models.transactions.transaction import Transaction
2025-12-19 16:48:21 +01:00
from node.api.serializers.fields import BytesFromIntArray
2025-10-30 11:48:34 +01:00
from node.api.serializers.proof import (
OperationProofSerializer,
OperationProofSerializerField,
2025-12-19 16:48:21 +01:00
ZkSignatureComponentsSerializer,
2025-10-30 11:48:34 +01:00
)
from node.api.serializers.transaction import TransactionSerializer
from utils.protocols import FromRandom
from utils.random import random_bytes
class SignedTransactionSerializer(NbeSerializer, FromRandom):
transaction: TransactionSerializer = Field(alias="mantle_tx", description="Transaction.")
operations_proofs: List[OperationProofSerializerField] = Field(
alias="ops_proofs", description="List of OperationProof. Order should match `Self::transaction::operations`."
)
2025-12-19 16:48:21 +01:00
ledger_transaction_proof: ZkSignatureComponentsSerializer = Field(
alias="ledger_tx_proof", description="ZK proof with pi_a, pi_b, pi_c."
2025-10-30 11:48:34 +01:00
)
def into_transaction(self) -> Transaction:
operations_contents = self.transaction.operations_contents
if len(operations_contents) != len(self.operations_proofs):
raise ValueError(
f"Number of operations ({len(operations_contents)}) does not match number of operation proofs ({len(self.operations_proofs)})."
)
operations = [
{
"content": content.into_operation_content(),
"proof": proof.into_operation_proof(),
}
for content, proof in zip(operations_contents, self.operations_proofs)
]
ledger_transaction = self.transaction.ledger_transaction
outputs = [output.into_note() for output in ledger_transaction.outputs]
2025-12-19 16:48:21 +01:00
# Combine pi_a, pi_b, pi_c into single proof bytes
proof_bytes = (
self.ledger_transaction_proof.pi_a +
self.ledger_transaction_proof.pi_b +
self.ledger_transaction_proof.pi_c
)
2025-10-30 11:48:34 +01:00
return Transaction.model_validate(
{
"hash": self.transaction.hash,
"operations": operations,
"inputs": ledger_transaction.inputs,
"outputs": outputs,
2025-12-19 16:48:21 +01:00
"proof": proof_bytes,
2025-10-30 11:48:34 +01:00
"execution_gas_price": self.transaction.execution_gas_price,
"storage_gas_price": self.transaction.storage_gas_price,
}
)
@classmethod
def from_random(cls) -> Self:
transaction = TransactionSerializer.from_random()
n = len(transaction.operations_contents)
operations_proofs = [OperationProofSerializer.from_random() for _ in range(n)]
return cls.model_validate(
2025-12-19 16:48:21 +01:00
{
"mantle_tx": transaction,
"ops_proofs": operations_proofs,
"ledger_tx_proof": {
"pi_a": list(random_bytes(32)),
"pi_b": list(random_bytes(64)),
"pi_c": list(random_bytes(32)),
},
}
)