lssa/common/src/transaction.rs

107 lines
3.5 KiB
Rust
Raw Normal View History

2025-09-25 11:53:42 +03:00
use borsh::{BorshDeserialize, BorshSerialize};
use log::warn;
2026-02-05 16:21:08 +02:00
use nssa::{AccountId, V02State};
2025-07-21 18:46:50 -03:00
use serde::{Deserialize, Serialize};
2024-10-10 14:09:31 +03:00
use crate::HashType;
2024-12-22 16:14:52 +02:00
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
2025-09-08 10:11:04 +03:00
pub enum NSSATransaction {
Public(nssa::PublicTransaction),
PrivacyPreserving(nssa::PrivacyPreservingTransaction),
ProgramDeployment(nssa::ProgramDeploymentTransaction),
2025-09-08 10:11:04 +03:00
}
impl NSSATransaction {
2026-03-03 23:21:08 +03:00
#[must_use]
pub fn hash(&self) -> HashType {
HashType(match self {
2026-03-09 18:27:56 +03:00
Self::Public(tx) => tx.hash(),
Self::PrivacyPreserving(tx) => tx.hash(),
Self::ProgramDeployment(tx) => tx.hash(),
})
}
2026-02-23 10:55:00 +02:00
2026-03-03 23:21:08 +03:00
#[must_use]
2026-02-23 10:55:00 +02:00
pub fn affected_public_account_ids(&self) -> Vec<AccountId> {
match self {
2026-03-09 18:27:56 +03:00
Self::ProgramDeployment(tx) => tx.affected_public_account_ids(),
Self::Public(tx) => tx.affected_public_account_ids(),
Self::PrivacyPreserving(tx) => tx.affected_public_account_ids(),
2026-02-23 10:55:00 +02:00
}
}
// TODO: Introduce type-safe wrapper around checked transaction, e.g. AuthenticatedTransaction
pub fn transaction_stateless_check(self) -> Result<Self, TransactionMalformationError> {
// Stateless checks here
match self {
2026-03-09 18:27:56 +03:00
Self::Public(tx) => {
2026-02-23 10:55:00 +02:00
if tx.witness_set().is_valid_for(tx.message()) {
2026-03-09 18:27:56 +03:00
Ok(Self::Public(tx))
2026-02-23 10:55:00 +02:00
} else {
Err(TransactionMalformationError::InvalidSignature)
}
}
2026-03-09 18:27:56 +03:00
Self::PrivacyPreserving(tx) => {
2026-02-23 10:55:00 +02:00
if tx.witness_set().signatures_are_valid_for(tx.message()) {
2026-03-09 18:27:56 +03:00
Ok(Self::PrivacyPreserving(tx))
2026-02-23 10:55:00 +02:00
} else {
Err(TransactionMalformationError::InvalidSignature)
}
}
2026-03-09 18:27:56 +03:00
Self::ProgramDeployment(tx) => Ok(Self::ProgramDeployment(tx)),
2026-02-23 10:55:00 +02:00
}
}
pub fn execute_check_on_state(
self,
state: &mut V02State,
) -> Result<Self, nssa::error::NssaError> {
match &self {
2026-03-09 18:27:56 +03:00
Self::Public(tx) => state.transition_from_public_transaction(tx),
Self::PrivacyPreserving(tx) => state.transition_from_privacy_preserving_transaction(tx),
Self::ProgramDeployment(tx) => state.transition_from_program_deployment_transaction(tx),
2026-02-23 10:55:00 +02:00
}
.inspect_err(|err| warn!("Error at transition {err:#?}"))?;
Ok(self)
}
}
2025-09-08 10:11:04 +03:00
impl From<nssa::PublicTransaction> for NSSATransaction {
fn from(value: nssa::PublicTransaction) -> Self {
Self::Public(value)
}
}
impl From<nssa::PrivacyPreservingTransaction> for NSSATransaction {
fn from(value: nssa::PrivacyPreservingTransaction) -> Self {
Self::PrivacyPreserving(value)
}
}
2025-10-15 20:14:19 -03:00
impl From<nssa::ProgramDeploymentTransaction> for NSSATransaction {
fn from(value: nssa::ProgramDeploymentTransaction) -> Self {
Self::ProgramDeployment(value)
}
}
2025-09-25 11:53:42 +03:00
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize,
2025-09-25 11:53:42 +03:00
)]
pub enum TxKind {
Public,
2025-08-28 12:00:04 +03:00
PrivacyPreserving,
ProgramDeployment,
}
2026-03-09 18:27:56 +03:00
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, thiserror::Error)]
2026-01-30 10:25:34 +02:00
pub enum TransactionMalformationError {
#[error("Invalid signature(-s)")]
2026-01-30 10:25:34 +02:00
InvalidSignature,
2026-02-23 10:55:00 +02:00
#[error("Failed to decode transaction with hash: {tx:?}")]
2026-01-30 10:25:34 +02:00
FailedToDecode { tx: HashType },
#[error("Transaction size {size} exceeds maximum allowed size of {max} bytes")]
TransactionTooLarge { size: usize, max: usize },
2026-01-30 10:25:34 +02:00
}