use super::{BlockHeight, Data, TxId};
use crate::TxBlockPosition;
use anyhow::{Context, Result};
use bc_envelope::prelude::*;
#[derive(Debug, Clone, PartialEq)]
pub struct Transaction {
txid: TxId,
raw: Option<Data>,
target_height: Option<BlockHeight>,
mined_height: Option<BlockHeight>,
block_position: Option<TxBlockPosition>,
attachments: Attachments,
}
bc_envelope::impl_attachable!(Transaction);
impl Transaction {
pub fn new(txid: TxId) -> Self {
Self {
txid,
raw: None,
target_height: None,
mined_height: None,
block_position: None,
attachments: Attachments::new(),
}
}
pub fn txid(&self) -> TxId {
self.txid
}
pub fn set_txid(&mut self, txid: TxId) {
self.txid = txid;
}
pub fn raw(&self) -> Option<&Data> {
self.raw.as_ref()
}
pub fn set_raw(&mut self, raw: Data) {
self.raw = Some(raw);
}
pub fn target_height(&self) -> Option<&BlockHeight> {
self.target_height.as_ref()
}
pub fn set_target_height(&mut self, height: BlockHeight) {
self.target_height = Some(height);
}
pub fn mined_height(&self) -> Option<&BlockHeight> {
self.mined_height.as_ref()
}
pub fn set_mined_height(&mut self, height: BlockHeight) {
self.mined_height = Some(height);
}
pub fn block_position(&self) -> Option<&TxBlockPosition> {
self.block_position.as_ref()
}
pub fn set_block_position(&mut self, block_position: Option<TxBlockPosition>) {
self.block_position = block_position;
}
}
#[rustfmt::skip]
impl From<Transaction> for Envelope {
fn from(value: Transaction) -> Self {
let e = Envelope::new(value.txid)
.add_type("Transaction")
.add_optional_assertion("raw", value.raw)
.add_optional_assertion("target_height", value.target_height)
.add_optional_assertion("mined_height", value.mined_height)
.add_optional_assertion("block_position", value.block_position);
value.attachments.add_to_envelope(e)
}
}
impl TryFrom<Envelope> for Transaction {
type Error = anyhow::Error;
fn try_from(envelope: Envelope) -> Result<Self, Self::Error> {
envelope.check_type_envelope("Transaction")?;
let txid = envelope.extract_subject().context("txid")?;
let raw = envelope
.try_optional_object_for_predicate("raw")
.context("raw")?;
let target_height = envelope
.try_optional_object_for_predicate("target_height")
.context("target_height")?;
let mined_height = envelope
.try_optional_object_for_predicate("mined_height")
.context("mined_height")?;
let block_position = envelope
.try_optional_object_for_predicate("block_position")
.context("block_position")?;
let attachments = Attachments::try_from_envelope(&envelope).context("attachments")?;
Ok(Self {
txid,
raw,
target_height,
mined_height,
block_position,
attachments,
})
}
}
#[cfg(test)]
mod tests {
use bc_envelope::Attachments;
use super::Transaction;
use crate::{BlockHeight, Data, TxBlockPosition, TxId, test_envelope_roundtrip};
impl crate::RandomInstance for Transaction {
fn random() -> Self {
Self {
txid: TxId::random(),
raw: Data::opt_random(),
target_height: BlockHeight::opt_random(),
mined_height: BlockHeight::opt_random(),
block_position: TxBlockPosition::opt_random(),
attachments: Attachments::random(),
}
}
}
test_envelope_roundtrip!(Transaction);
}