kaspa_p2p_lib/convert/
tx.rs

1use super::{error::ConversionError, option::TryIntoOptionEx};
2use crate::pb as protowire;
3use kaspa_consensus_core::{
4    subnets::SubnetworkId,
5    tx::{ScriptPublicKey, Transaction, TransactionId, TransactionInput, TransactionOutpoint, TransactionOutput, UtxoEntry},
6};
7use kaspa_hashes::Hash;
8
9// ----------------------------------------------------------------------------
10// consensus_core to protowire
11// ----------------------------------------------------------------------------
12
13impl From<Hash> for protowire::TransactionId {
14    fn from(hash: Hash) -> Self {
15        Self { bytes: Vec::from(hash.as_bytes()) }
16    }
17}
18
19impl From<&Hash> for protowire::TransactionId {
20    fn from(hash: &Hash) -> Self {
21        Self { bytes: Vec::from(hash.as_bytes()) }
22    }
23}
24
25impl From<&SubnetworkId> for protowire::SubnetworkId {
26    fn from(id: &SubnetworkId) -> Self {
27        Self { bytes: Vec::from(<SubnetworkId as AsRef<[u8]>>::as_ref(id)) }
28    }
29}
30
31impl From<&TransactionOutpoint> for protowire::Outpoint {
32    fn from(outpoint: &TransactionOutpoint) -> Self {
33        Self { transaction_id: Some(outpoint.transaction_id.into()), index: outpoint.index }
34    }
35}
36
37impl From<&ScriptPublicKey> for protowire::ScriptPublicKey {
38    fn from(script_public_key: &ScriptPublicKey) -> Self {
39        Self { script: script_public_key.script().to_vec(), version: script_public_key.version() as u32 }
40    }
41}
42
43impl From<&TransactionInput> for protowire::TransactionInput {
44    fn from(input: &TransactionInput) -> Self {
45        Self {
46            previous_outpoint: Some((&input.previous_outpoint).into()),
47            signature_script: input.signature_script.clone(),
48            sequence: input.sequence,
49            sig_op_count: input.sig_op_count as u32,
50        }
51    }
52}
53
54impl From<&TransactionOutput> for protowire::TransactionOutput {
55    fn from(output: &TransactionOutput) -> Self {
56        Self { value: output.value, script_public_key: Some((&output.script_public_key).into()) }
57    }
58}
59
60impl From<&Transaction> for protowire::TransactionMessage {
61    fn from(tx: &Transaction) -> Self {
62        Self {
63            version: tx.version as u32,
64            inputs: tx.inputs.iter().map(|input| input.into()).collect(),
65            outputs: tx.outputs.iter().map(|output| output.into()).collect(),
66            lock_time: tx.lock_time,
67            subnetwork_id: Some((&tx.subnetwork_id).into()),
68            gas: tx.gas,
69            payload: tx.payload.clone(),
70            mass: tx.mass(),
71        }
72    }
73}
74
75// ----------------------------------------------------------------------------
76// protowire to consensus_core
77// ----------------------------------------------------------------------------
78
79impl TryFrom<protowire::TransactionId> for TransactionId {
80    type Error = ConversionError;
81
82    fn try_from(value: protowire::TransactionId) -> Result<Self, Self::Error> {
83        Ok(Self::from_bytes(value.bytes.as_slice().try_into()?))
84    }
85}
86
87impl TryFrom<protowire::Outpoint> for TransactionOutpoint {
88    type Error = ConversionError;
89
90    fn try_from(item: protowire::Outpoint) -> Result<Self, Self::Error> {
91        Ok(Self::new(item.transaction_id.try_into_ex()?, item.index))
92    }
93}
94
95impl TryFrom<protowire::ScriptPublicKey> for ScriptPublicKey {
96    type Error = ConversionError;
97
98    fn try_from(value: protowire::ScriptPublicKey) -> Result<Self, Self::Error> {
99        Ok(Self::from_vec(value.version.try_into()?, value.script))
100    }
101}
102
103impl TryFrom<protowire::UtxoEntry> for UtxoEntry {
104    type Error = ConversionError;
105
106    fn try_from(value: protowire::UtxoEntry) -> Result<Self, Self::Error> {
107        Ok(Self::new(value.amount, value.script_public_key.try_into_ex()?, value.block_daa_score, value.is_coinbase))
108    }
109}
110
111impl TryFrom<protowire::OutpointAndUtxoEntryPair> for (TransactionOutpoint, UtxoEntry) {
112    type Error = ConversionError;
113
114    fn try_from(value: protowire::OutpointAndUtxoEntryPair) -> Result<Self, Self::Error> {
115        Ok((value.outpoint.try_into_ex()?, value.utxo_entry.try_into_ex()?))
116    }
117}
118
119impl TryFrom<protowire::TransactionInput> for TransactionInput {
120    type Error = ConversionError;
121
122    fn try_from(value: protowire::TransactionInput) -> Result<Self, Self::Error> {
123        Ok(Self::new(value.previous_outpoint.try_into_ex()?, value.signature_script, value.sequence, value.sig_op_count.try_into()?))
124    }
125}
126
127impl TryFrom<protowire::TransactionOutput> for TransactionOutput {
128    type Error = ConversionError;
129
130    fn try_from(output: protowire::TransactionOutput) -> Result<Self, Self::Error> {
131        Ok(Self::new(output.value, output.script_public_key.try_into_ex()?))
132    }
133}
134
135impl TryFrom<protowire::TransactionMessage> for Transaction {
136    type Error = ConversionError;
137
138    fn try_from(tx: protowire::TransactionMessage) -> Result<Self, Self::Error> {
139        let transaction = Self::new(
140            tx.version.try_into()?,
141            tx.inputs.into_iter().map(|i| i.try_into()).collect::<Result<Vec<TransactionInput>, Self::Error>>()?,
142            tx.outputs.into_iter().map(|i| i.try_into()).collect::<Result<Vec<TransactionOutput>, Self::Error>>()?,
143            tx.lock_time,
144            tx.subnetwork_id.try_into_ex()?,
145            tx.gas,
146            tx.payload,
147        );
148        transaction.set_mass(tx.mass);
149        Ok(transaction)
150    }
151}