1use crate::address::{Address, AddressConvertible, PrivateKey};
4#[cfg(feature = "builder")]
5use crate::network::ThorNode;
6use crate::rlp::{
7 lstrip, static_left_pad, AsBytes, AsVec, BufMut, Bytes, BytesMut, Decodable, Encodable, Maybe,
8 RLPError,
9};
10#[cfg(feature = "builder")]
11pub use crate::transaction_builder::{TransactionBuilder, TransactionBuilderError};
12use crate::utils::blake2_256;
13use crate::{rlp_encodable, U256};
14use secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
15use secp256k1::{Message, PublicKey, Secp256k1};
16#[cfg(feature = "serde")]
17use serde::{Deserialize, Serialize};
18
19rlp_encodable! {
20 #[cfg_attr(feature="serde", serde_with::serde_as)]
22 #[cfg_attr(feature="serde", derive(Deserialize, Serialize))]
23 #[derive(Clone, Debug, Eq, PartialEq)]
24 pub struct Transaction {
25 #[cfg_attr(feature="serde", serde(rename="chainTag"))]
27 pub chain_tag: u8,
28 #[cfg_attr(feature="serde", serde(rename="blockRef"))]
32 pub block_ref: u64,
33 pub expiration: u32,
35 pub clauses: Vec<Clause>,
37 #[cfg_attr(feature="serde", serde(rename="gasPriceCoef"))]
39 pub gas_price_coef: u8,
40 pub gas: u64,
42 #[cfg_attr(feature="serde", serde(rename="dependsOn"))]
46 pub depends_on: Option<U256> => AsBytes<U256>,
47 pub nonce: u64,
49 pub reserved: Option<Reserved> => AsVec<Reserved>,
51 #[cfg_attr(feature="serde", serde(with = "serde_with::As::<Option<crate::utils::unhex::Hex>>"))]
58 pub signature: Option<Bytes> => Maybe<Bytes>,
59 }
60}
61
62impl Transaction {
63 pub const TRANSACTION_GAS: u64 = 5_000;
65
66 pub fn get_signing_hash(&self) -> [u8; 32] {
67 let mut encoded = Vec::with_capacity(1024);
69 let mut without_signature = self.clone();
70 without_signature.signature = None;
71 without_signature.encode(&mut encoded);
72 blake2_256(&[encoded])
73 }
74
75 pub fn get_delegate_signing_hash(&self, delegate_for: &Address) -> [u8; 32] {
76 let main_hash = self.get_signing_hash();
80 blake2_256(&[&main_hash[..], &delegate_for.to_fixed_bytes()[..]])
81 }
82
83 pub fn sign(self, private_key: &PrivateKey) -> Self {
84 let hash = self.get_signing_hash();
89 let signature = Self::sign_hash(hash, private_key);
90 self.with_signature(Bytes::copy_from_slice(&signature))
91 .expect("generated signature must be correct")
92 }
93
94 const fn signature_length_valid(&self) -> bool {
95 match &self.signature {
96 None => true,
97 Some(signature) => {
98 self.is_delegated() && signature.len() == 130
99 || !self.is_delegated() && signature.len() == 65
100 }
101 }
102 }
103
104 pub fn with_signature(self, signature: Bytes) -> Result<Self, secp256k1::Error> {
105 let copy = Self {
107 signature: Some(signature),
108 ..self
109 };
110 if copy.signature_length_valid() {
111 Ok(copy)
112 } else {
113 Err(secp256k1::Error::IncorrectSignature)
114 }
115 }
116
117 pub fn sign_hash(hash: [u8; 32], private_key: &PrivateKey) -> [u8; 65] {
118 let secp = Secp256k1::signing_only();
120 let signature =
121 secp.sign_ecdsa_recoverable(&Message::from_slice(&hash).unwrap(), private_key);
122 let (recovery_id, bytes) = signature.serialize_compact();
123 bytes
124 .into_iter()
125 .chain([recovery_id.to_i32() as u8])
126 .collect::<Vec<_>>()
127 .try_into()
128 .unwrap()
129 }
130
131 pub fn intrinsic_gas(&self) -> u64 {
132 let clauses_cost = if self.clauses.is_empty() {
137 Clause::REGULAR_CLAUSE_GAS
138 } else {
139 self.clauses.iter().map(Clause::intrinsic_gas).sum()
140 };
141 clauses_cost + Self::TRANSACTION_GAS
142 }
143
144 pub fn origin(&self) -> Result<Option<PublicKey>, secp256k1::Error> {
145 match &self.signature {
149 None => Ok(None),
150 Some(signature) if self.signature_length_valid() => {
151 let hash = self.get_signing_hash();
152 let secp = Secp256k1::verification_only();
153
154 Ok(Some(secp.recover_ecdsa(
155 &Message::from_slice(&hash)?,
156 &RecoverableSignature::from_compact(
157 &signature[..64],
158 RecoveryId::from_i32(signature[64] as i32)?,
159 )?,
160 )?))
161 }
162 _ => Err(secp256k1::Error::IncorrectSignature),
163 }
164 }
165
166 pub fn delegator(&self) -> Result<Option<PublicKey>, secp256k1::Error> {
167 if !self.is_delegated() {
171 return Ok(None);
172 }
173 match &self.signature {
174 None => Ok(None),
175 Some(signature) if self.signature_length_valid() => {
176 let hash = self.get_delegate_signing_hash(
177 &self
178 .origin()?
179 .expect("Must be set, already checked signature")
180 .address(),
181 );
182 let secp = Secp256k1::verification_only();
183
184 Ok(Some(secp.recover_ecdsa(
185 &Message::from_slice(&hash)?,
186 &RecoverableSignature::from_compact(
187 &signature[65..129],
188 RecoveryId::from_i32(signature[129] as i32)?,
189 )?,
190 )?))
191 }
192 _ => Err(secp256k1::Error::IncorrectSignature),
193 }
194 }
195
196 pub const fn is_delegated(&self) -> bool {
197 if let Some(reserved) = &self.reserved {
199 reserved.is_delegated()
200 } else {
201 false
202 }
203 }
204
205 pub fn id(&self) -> Result<Option<[u8; 32]>, secp256k1::Error> {
206 match self.origin()? {
210 None => Ok(None),
211 Some(origin) => Ok(Some(blake2_256(&[
212 &self.get_signing_hash()[..],
213 &origin.address().to_fixed_bytes()[..],
214 ]))),
215 }
216 }
217
218 pub fn has_valid_signature(&self) -> bool {
219 self._has_valid_signature().unwrap_or(false)
221 }
222
223 fn _has_valid_signature(&self) -> Result<bool, secp256k1::Error> {
224 if !self.signature_length_valid() {
226 return Ok(false);
227 }
228 match &self.signature {
229 None => Ok(false),
230 Some(signature) => {
231 let hash = self.get_signing_hash();
232 let secp = Secp256k1::verification_only();
233 Ok(secp
234 .recover_ecdsa(
235 &Message::from_slice(&hash)?,
236 &RecoverableSignature::from_compact(
237 &signature[..64],
238 RecoveryId::from_i32(signature[64] as i32)?,
239 )?,
240 )
241 .is_ok())
242 }
243 }
244 }
245
246 pub fn to_broadcastable_bytes(&self) -> Result<Bytes, secp256k1::Error> {
247 if self.signature.is_some() {
251 let mut buf = BytesMut::new();
252 self.encode(&mut buf);
253 Ok(buf.into())
254 } else {
255 Err(secp256k1::Error::IncorrectSignature)
256 }
257 }
258
259 #[cfg(feature = "builder")]
260 pub fn build(node: ThorNode) -> TransactionBuilder {
261 TransactionBuilder::new(node)
263 }
264}
265
266rlp_encodable! {
267 #[cfg_attr(feature="serde", serde_with::serde_as)]
269 #[cfg_attr(feature="serde", derive(Deserialize, Serialize))]
270 #[derive(Clone, Debug, Eq, PartialEq)]
271 pub struct Clause {
272 pub to: Option<Address> => AsBytes<Address>,
274 pub value: U256,
276 #[cfg_attr(feature="serde", serde(with = "serde_with::As::<crate::utils::unhex::Hex>"))]
278 pub data: Bytes,
279 }
280}
281
282impl Clause {
283 pub const REGULAR_CLAUSE_GAS: u64 = 16_000;
285 pub const CONTRACT_CREATION_CLAUSE_GAS: u64 = 48_000;
287 pub const ZERO_DATA_BYTE_GAS_COST: u64 = 4;
289 pub const NONZERO_DATA_BYTE_GAS_COST: u64 = 68;
291
292 pub fn intrinsic_gas(&self) -> u64 {
293 let clause_gas = if self.to.is_some() {
298 Self::REGULAR_CLAUSE_GAS
299 } else {
300 Self::CONTRACT_CREATION_CLAUSE_GAS
301 };
302 let data_gas: u64 = self
303 .data
304 .iter()
305 .map(|&b| {
306 if b == 0 {
307 Self::ZERO_DATA_BYTE_GAS_COST
308 } else {
309 Self::NONZERO_DATA_BYTE_GAS_COST
310 }
311 })
312 .sum();
313 clause_gas + data_gas
314 }
315}
316
317#[cfg_attr(feature = "serde", serde_with::serde_as)]
319#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
320#[derive(Clone, Debug, Eq, PartialEq)]
321pub struct Reserved {
322 pub features: u32,
324 #[cfg_attr(
326 feature = "serde",
327 serde(with = "serde_with::As::<Vec<crate::utils::unhex::Hex>>")
328 )]
329 pub unused: Vec<Bytes>,
330}
331
332impl Encodable for Reserved {
333 fn encode(&self, out: &mut dyn BufMut) {
334 let mut buf = vec![];
335 self.features.to_be_bytes().encode(&mut buf);
336 let mut stripped_buf: Vec<_> = [lstrip(&buf[1..])]
337 .into_iter()
338 .map(Bytes::from)
339 .chain(self.unused.clone())
340 .rev()
341 .skip_while(Bytes::is_empty)
342 .collect();
343 stripped_buf.reverse();
344 stripped_buf.encode(out)
345 }
346}
347
348impl Decodable for Reserved {
349 fn decode(buf: &mut &[u8]) -> Result<Self, RLPError> {
350 if let Some((feature_bytes, unused)) = Vec::<Bytes>::decode(buf)?.split_first() {
351 Ok(Self {
352 features: u32::from_be_bytes(static_left_pad(feature_bytes)?),
353 unused: unused.to_vec(),
354 })
355 } else {
356 Ok(Self::new_empty())
357 }
358 }
359}
360
361impl Reserved {
362 pub const DELEGATED_BIT: u32 = 1;
364
365 pub const fn new_delegated() -> Self {
366 Self {
368 features: Self::DELEGATED_BIT,
369 unused: vec![],
370 }
371 }
372 pub const fn new_empty() -> Self {
373 Self {
375 features: 0,
376 unused: vec![],
377 }
378 }
379 pub const fn is_delegated(&self) -> bool {
380 self.features & Self::DELEGATED_BIT != 0
382 }
383 pub fn is_empty(&self) -> bool {
384 self.features == 0 && self.unused.is_empty()
386 }
387}