1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
//! VeChain transactions support.

use crate::address::{Address, AddressConvertible, PrivateKey};
use crate::rlp::{
    lstrip, static_left_pad, AsBytes, AsVec, BufMut, Bytes, BytesMut, Decodable, Encodable, Maybe,
    RLPError,
};
use crate::utils::blake2_256;
use crate::{rlp_encodable, U256};
use secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
use secp256k1::{Message, PublicKey, Secp256k1};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

rlp_encodable! {
    /// Represents a single VeChain transaction.
    #[cfg_attr(feature="serde", serde_with::serde_as)]
    #[cfg_attr(feature="serde", derive(Deserialize, Serialize))]
    #[derive(Clone, Debug, Eq, PartialEq)]
    pub struct Transaction {
        /// Chain tag
        #[cfg_attr(feature="serde", serde(rename="chainTag"))]
        pub chain_tag: u8,
        /// Previous block reference
        ///
        /// First 4 bytes (BE) are block height, the rest is part of referred block ID.
        #[cfg_attr(feature="serde", serde(rename="blockRef"))]
        pub block_ref: u64,
        /// Expiration (in blocks)
        pub expiration: u32,
        /// Vector of clauses
        pub clauses: Vec<Clause>,
        /// Coefficient to calculate the gas price.
        #[cfg_attr(feature="serde", serde(rename="gasPriceCoef"))]
        pub gas_price_coef: u8,
        /// Maximal amount of gas to spend for transaction.
        pub gas: u64,
        /// Hash of transaction on which current transaction depends.
        ///
        /// May be left unspecified if this functionality is not necessary.
        #[cfg_attr(feature="serde", serde(rename="dependsOn"))]
        pub depends_on: Option<U256> => AsBytes<U256>,
        /// Transaction nonce
        pub nonce: u64,
        /// Reserved fields.
        pub reserved: Option<Reserved> => AsVec<Reserved>,
        /// Signature. 65 bytes for regular transactions, 130 - for VIP-191.
        ///
        /// Ignored when making a signing hash.
        ///
        /// For VIP-191 transactions, this would be a simple concatenation
        /// of two signatures.
        #[cfg_attr(feature="serde", serde(with = "serde_with::As::<Option<crate::utils::unhex::Hex>>"))]
        pub signature: Option<Bytes> => Maybe<Bytes>,
    }
}

// TODO: add serde optional support

impl Transaction {
    /// Gas cost for whole transaction execution.
    pub const TRANSACTION_GAS: u64 = 5_000;

    pub fn get_signing_hash(&self) -> [u8; 32] {
        //! Get a signing hash for this transaction.
        let mut encoded = Vec::with_capacity(1024);
        let mut without_signature = self.clone();
        without_signature.signature = None;
        without_signature.encode(&mut encoded);
        blake2_256(&[encoded])
    }

    pub fn get_delegate_signing_hash(&self, delegate_for: &Address) -> [u8; 32] {
        //! Get a signing hash for this transaction with fee delegation.
        //!
        //! `VIP-191 <https://github.com/vechain/VIPs/blob/master/vips/VIP-191.md>`
        let main_hash = self.get_signing_hash();
        blake2_256(&[&main_hash[..], &delegate_for.to_fixed_bytes()[..]])
    }

    pub fn sign(self, private_key: &PrivateKey) -> Self {
        //! Create a copy of transaction with a signature emplaced.
        //!
        //! You can call `.encode()` on the result to get bytes ready to be sent
        //! over wire.
        let hash = self.get_signing_hash();
        let signature = Self::sign_hash(hash, private_key);
        self.with_signature(Bytes::copy_from_slice(&signature))
            .expect("generated signature must be correct")
    }

    fn signature_length_valid(&self) -> bool {
        match &self.signature {
            None => true,
            Some(signature) => {
                self.is_delegated() && signature.len() == 130
                    || !self.is_delegated() && signature.len() == 65
            }
        }
    }

    pub fn with_signature(self, signature: Bytes) -> Result<Self, secp256k1::Error> {
        //! Set a signature for this transaction.
        let copy = Self {
            signature: Some(signature),
            ..self
        };
        if copy.signature_length_valid() {
            Ok(copy)
        } else {
            Err(secp256k1::Error::IncorrectSignature)
        }
    }

    pub fn sign_hash(hash: [u8; 32], private_key: &PrivateKey) -> [u8; 65] {
        //! Sign a hash obtained from `Transaction::get_signing_hash`.
        let secp = Secp256k1::signing_only();
        let signature =
            secp.sign_ecdsa_recoverable(&Message::from_slice(&hash).unwrap(), private_key);
        let (recovery_id, bytes) = signature.serialize_compact();
        bytes
            .into_iter()
            .chain([recovery_id.to_i32() as u8])
            .collect::<Vec<_>>()
            .try_into()
            .unwrap()
    }

    pub fn intrinsic_gas(&self) -> u64 {
        //! Calculate the intrinsic gas amount required for this transaction.
        //!
        //! This amount is always less than actual amount of gas necessary.
        //! `More info <https://docs.vechain.org/core-concepts/transactions/transaction-calculation>`
        let clauses_cost = if self.clauses.is_empty() {
            Clause::REGULAR_CLAUSE_GAS
        } else {
            self.clauses.iter().map(Clause::intrinsic_gas).sum()
        };
        clauses_cost + Self::TRANSACTION_GAS
    }

    pub fn origin(&self) -> Result<Option<PublicKey>, secp256k1::Error> {
        //! Recover origin public key using the signature.
        //!
        //! Returns `Ok(None)` if signature is unset.
        match &self.signature {
            None => Ok(None),
            Some(signature) if self.signature_length_valid() => {
                let hash = self.get_signing_hash();
                let secp = Secp256k1::verification_only();

                Ok(Some(secp.recover_ecdsa(
                    &Message::from_slice(&hash)?,
                    &RecoverableSignature::from_compact(
                        &signature[..64],
                        RecoveryId::from_i32(signature[64] as i32)?,
                    )?,
                )?))
            }
            _ => Err(secp256k1::Error::IncorrectSignature),
        }
    }

    pub fn delegator(&self) -> Result<Option<PublicKey>, secp256k1::Error> {
        //! Recover delegator public key using the signature.
        //!
        //! Returns `Ok(None)` if signature is unset or transaction is not delegated.
        if !self.is_delegated() {
            return Ok(None);
        }
        match &self.signature {
            None => Ok(None),
            Some(signature) if self.signature_length_valid() => {
                let hash = self.get_delegate_signing_hash(
                    &self
                        .origin()?
                        .expect("Must be set, already checked signature")
                        .address(),
                );
                let secp = Secp256k1::verification_only();

                Ok(Some(secp.recover_ecdsa(
                    &Message::from_slice(&hash)?,
                    &RecoverableSignature::from_compact(
                        &signature[65..129],
                        RecoveryId::from_i32(signature[129] as i32)?,
                    )?,
                )?))
            }
            _ => Err(secp256k1::Error::IncorrectSignature),
        }
    }

    pub fn is_delegated(&self) -> bool {
        //! Check if transaction is VIP-191 delegated.
        if let Some(reserved) = &self.reserved {
            reserved.is_delegated()
        } else {
            false
        }
    }

    pub fn id(&self) -> Result<Option<[u8; 32]>, secp256k1::Error> {
        //! Calculate transaction ID using the signature.
        //!
        //! Returns `Ok(None)` if signature is unset.
        match self.origin()? {
            None => Ok(None),
            Some(origin) => Ok(Some(blake2_256(&[
                &self.get_signing_hash()[..],
                &origin.address().to_fixed_bytes()[..],
            ]))),
        }
    }

    pub fn has_valid_signature(&self) -> bool {
        //! Check wheter the signature is valid.
        self._has_valid_signature().unwrap_or(false)
    }

    fn _has_valid_signature(&self) -> Result<bool, secp256k1::Error> {
        //! Check wheter the signature is valid.
        if !self.signature_length_valid() {
            return Ok(false);
        }
        match &self.signature {
            None => Ok(false),
            Some(signature) => {
                let hash = self.get_signing_hash();
                let secp = Secp256k1::verification_only();
                Ok(secp
                    .recover_ecdsa(
                        &Message::from_slice(&hash)?,
                        &RecoverableSignature::from_compact(
                            &signature[..64],
                            RecoveryId::from_i32(signature[64] as i32)?,
                        )?,
                    )
                    .is_ok())
            }
        }
    }

    pub fn to_broadcastable_bytes(&self) -> Result<Bytes, secp256k1::Error> {
        //! Create a binary representation.
        //!
        //! Returns `Err(secp256k1::Error::IncorrectSignature)` if signature is not set.
        if self.signature.is_some() {
            let mut buf = BytesMut::new();
            self.encode(&mut buf);
            Ok(buf.into())
        } else {
            Err(secp256k1::Error::IncorrectSignature)
        }
    }
}

rlp_encodable! {
    /// Represents a single transaction clause (recipient, value and data).
    #[cfg_attr(feature="serde", serde_with::serde_as)]
    #[cfg_attr(feature="serde", derive(Deserialize, Serialize))]
    #[derive(Clone, Debug, Eq, PartialEq)]
    pub struct Clause {
        /// Recipient
        pub to: Option<Address> => AsBytes<Address>,
        /// Amount of funds to spend.
        pub value: U256,
        /// Contract code or other data.
        #[cfg_attr(feature="serde", serde(with = "serde_with::As::<crate::utils::unhex::Hex>"))]
        pub data: Bytes,
    }
}

impl Clause {
    /// Gas spent for one regular clause execution.
    pub const REGULAR_CLAUSE_GAS: u64 = 16_000;
    /// Gas spent for one contract creation (without `to`) clause execution.
    pub const CONTRACT_CREATION_CLAUSE_GAS: u64 = 48_000;
    /// Intrinsic gas usage for a single zero byte of data.
    pub const ZERO_DATA_BYTE_GAS_COST: u64 = 4;
    /// Intrinsic gas usage for a single non-zero byte of data.
    pub const NONZERO_DATA_BYTE_GAS_COST: u64 = 68;

    pub fn intrinsic_gas(&self) -> u64 {
        //! Calculate the intrinsic gas amount required for executing this clause.
        //!
        //! This amount is always less than actual amount of gas necessary.
        //! `More info <https://docs.vechain.org/core-concepts/transactions/transaction-calculation>`
        let clause_gas = if self.to.is_some() {
            Self::REGULAR_CLAUSE_GAS
        } else {
            Self::CONTRACT_CREATION_CLAUSE_GAS
        };
        let data_gas: u64 = self
            .data
            .iter()
            .map(|&b| {
                if b == 0 {
                    Self::ZERO_DATA_BYTE_GAS_COST
                } else {
                    Self::NONZERO_DATA_BYTE_GAS_COST
                }
            })
            .sum();
        clause_gas + data_gas
    }
}

/// Represents a transaction's ``reserved`` field.
#[cfg_attr(feature = "serde", serde_with::serde_as)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Reserved {
    /// Features to enable (bitmask).
    pub features: u32,
    /// Currently unused field.
    #[cfg_attr(
        feature = "serde",
        serde(with = "serde_with::As::<Vec<crate::utils::unhex::Hex>>")
    )]
    pub unused: Vec<Bytes>,
}

impl Encodable for Reserved {
    fn encode(&self, out: &mut dyn BufMut) {
        let mut buf = vec![];
        self.features.to_be_bytes().encode(&mut buf);
        let mut stripped_buf: Vec<_> = [lstrip(&buf[1..])]
            .into_iter()
            .map(Bytes::from)
            .chain(self.unused.clone())
            .rev()
            .skip_while(Bytes::is_empty)
            .collect();
        stripped_buf.reverse();
        stripped_buf.encode(out)
    }
}

impl Decodable for Reserved {
    fn decode(buf: &mut &[u8]) -> Result<Self, RLPError> {
        if let Some((feature_bytes, unused)) = Vec::<Bytes>::decode(buf)?.split_first() {
            Ok(Self {
                features: u32::from_be_bytes(static_left_pad(feature_bytes)?),
                unused: unused.to_vec(),
            })
        } else {
            Ok(Self::new_empty())
        }
    }
}

impl Reserved {
    /// Features bitmask for delegated transaction.
    pub const DELEGATED_BIT: u32 = 1;

    pub fn new_delegated() -> Self {
        //! Create reserved structure kind for VIP-191 delegation.
        Self {
            features: Self::DELEGATED_BIT,
            unused: vec![],
        }
    }
    pub fn new_empty() -> Self {
        //! Create reserved structure kind for regular transaction.
        Self {
            features: 0,
            unused: vec![],
        }
    }
    pub fn is_delegated(&self) -> bool {
        //! Belongs to delegated transaction?
        self.features & Self::DELEGATED_BIT != 0
    }
    pub fn is_empty(&self) -> bool {
        //! Belongs to delegated transaction?
        self.features == 0 && self.unused.is_empty()
    }
}