use serde::{Deserialize, Serialize};
use super::super::RebasedError;
use super::super::encoding::Base64;
use super::super::{Intent, IntentMessage};
use super::{
Envelope, GenericSignature, IntentScope, IotaAddress, Message, ObjectRef, ProgrammableTransaction, Signature,
SizeOneVec, TransactionDigest, default_hash,
};
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct EmptySignInfo {}
pub type Transaction = Envelope<SenderSignedData, EmptySignInfo>;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct SenderSignedData(SizeOneVec<SenderSignedTransaction>);
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SenderSignedTransaction {
pub intent_message: IntentMessage<TransactionData>,
pub tx_signatures: Vec<GenericSignature>,
}
impl Serialize for SenderSignedTransaction {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
#[derive(Serialize)]
#[serde(rename = "SenderSignedTransaction")]
struct SignedTxn<'a> {
intent_message: &'a IntentMessage<TransactionData>,
tx_signatures: &'a Vec<GenericSignature>,
}
if self.intent_message().intent != Intent::iota_transaction() {
return Err(serde::ser::Error::custom("invalid Intent for Transaction"));
}
let txn = SignedTxn {
intent_message: self.intent_message(),
tx_signatures: &self.tx_signatures,
};
txn.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for SenderSignedTransaction {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(rename = "SenderSignedTransaction")]
struct SignedTxn {
intent_message: IntentMessage<TransactionData>,
tx_signatures: Vec<GenericSignature>,
}
let SignedTxn {
intent_message,
tx_signatures,
} = Deserialize::deserialize(deserializer)?;
if intent_message.intent != Intent::iota_transaction() {
return Err(serde::de::Error::custom("invalid Intent for Transaction"));
}
Ok(Self {
intent_message,
tx_signatures,
})
}
}
impl SenderSignedTransaction {
pub fn intent_message(&self) -> &IntentMessage<TransactionData> {
&self.intent_message
}
}
impl SenderSignedData {
pub fn new(tx_data: TransactionData, tx_signatures: Vec<GenericSignature>) -> Self {
Self(SizeOneVec::new(SenderSignedTransaction {
intent_message: IntentMessage::new(Intent::iota_transaction(), tx_data),
tx_signatures,
}))
}
pub fn new_from_sender_signature(tx_data: TransactionData, tx_signature: Signature) -> Self {
Self(SizeOneVec::new(SenderSignedTransaction {
intent_message: IntentMessage::new(Intent::iota_transaction(), tx_data),
tx_signatures: vec![tx_signature.into()],
}))
}
pub fn inner(&self) -> &SenderSignedTransaction {
self.0.element()
}
pub fn intent_message(&self) -> &IntentMessage<TransactionData> {
self.inner().intent_message()
}
}
impl Message for SenderSignedData {
type DigestType = TransactionDigest;
const SCOPE: IntentScope = IntentScope::SenderSignedTransaction;
fn digest(&self) -> Self::DigestType {
self.intent_message().value.digest()
}
}
impl Transaction {
pub fn from_data(data: TransactionData, signatures: Vec<Signature>) -> Self {
Self::from_generic_sig_data(data, signatures.into_iter().map(|s| s.into()).collect())
}
pub fn from_generic_sig_data(data: TransactionData, signatures: Vec<GenericSignature>) -> Self {
Self::new(SenderSignedData::new(data, signatures))
}
pub fn to_tx_bytes_and_signatures(&self) -> Result<(Base64, Vec<Base64>), RebasedError> {
Ok((
Base64::from_bytes(&bcs::to_bytes(&self.data().intent_message().value)?),
self.data()
.inner()
.tx_signatures
.iter()
.map(|s| Base64::from_bytes(s.as_ref()))
.collect(),
))
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
pub struct GasData {
pub payment: Vec<ObjectRef>,
pub owner: IotaAddress,
pub price: u64,
pub budget: u64,
}
pub type EpochId = u64;
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Serialize, Deserialize)]
pub enum TransactionExpiration {
None,
Epoch(EpochId),
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
pub enum TransactionData {
V1(TransactionDataV1),
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
pub struct TransactionDataV1 {
pub kind: TransactionKind,
pub sender: IotaAddress,
pub gas_data: GasData,
pub expiration: TransactionExpiration,
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
pub enum TransactionKind {
ProgrammableTransaction(ProgrammableTransaction),
}
impl TransactionData {
pub fn digest(&self) -> TransactionDigest {
TransactionDigest::new(default_hash(self))
}
}