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
//! Relayed (forced) transaction entity types

use crate::{
    blockchain::primitives::DaBlockHeight,
    fuel_crypto,
    fuel_types::{
        BlockHeight,
        Bytes32,
        Nonce,
    },
};

/// Transaction sent from the DA layer to fuel by the relayer
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum RelayedTransaction {
    /// V1 version of the relayed transaction
    V1(RelayedTransactionV1),
}

impl Default for RelayedTransaction {
    fn default() -> Self {
        Self::V1(Default::default())
    }
}

/// The V1 version of the relayed transaction
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct RelayedTransactionV1 {
    /// Unique nonce for this FTI event
    pub nonce: Nonce,
    /// The max gas that this transaction can consume
    pub max_gas: u64,
    /// The serialized transaction transmitted from the bridge
    pub serialized_transaction: Vec<u8>,
    /// The block height from the parent da layer that originated this transaction
    pub da_height: DaBlockHeight,
}

/// The hash of a relayed transaction
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(
    Debug,
    Clone,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
    Hash,
    derive_more::Display,
    derive_more::From,
    derive_more::Into,
)]
pub struct RelayedTransactionId(Bytes32);

impl RelayedTransaction {
    /// The hash of the relayed transaction
    pub fn id(&self) -> RelayedTransactionId {
        match &self {
            RelayedTransaction::V1(tx) => tx.id(),
        }
    }

    /// The unique nonce associated with this relayed transaction
    pub fn nonce(&self) -> Nonce {
        match &self {
            RelayedTransaction::V1(tx) => tx.nonce,
        }
    }

    #[cfg(any(test, feature = "test-helpers"))]
    /// Set the nonce
    pub fn set_nonce(&mut self, nonce: Nonce) {
        match self {
            RelayedTransaction::V1(transaction) => {
                transaction.nonce = nonce;
            }
        }
    }

    /// Get the DA height that originated this transaction from L1
    pub fn da_height(&self) -> DaBlockHeight {
        match self {
            RelayedTransaction::V1(transaction) => transaction.da_height,
        }
    }

    /// Get the max gas
    pub fn max_gas(&self) -> u64 {
        match self {
            RelayedTransaction::V1(transaction) => transaction.max_gas,
        }
    }

    #[cfg(any(test, feature = "test-helpers"))]
    /// Set the da height
    pub fn set_da_height(&mut self, height: DaBlockHeight) {
        match self {
            RelayedTransaction::V1(transaction) => {
                transaction.da_height = height;
            }
        }
    }

    #[cfg(any(test, feature = "test-helpers"))]
    /// Set the max gas
    pub fn set_max_gas(&mut self, max_gas: u64) {
        match self {
            RelayedTransaction::V1(transaction) => {
                transaction.max_gas = max_gas;
            }
        }
    }

    /// Get the canonically serialized transaction
    pub fn serialized_transaction(&self) -> &[u8] {
        match self {
            RelayedTransaction::V1(transaction) => &transaction.serialized_transaction,
        }
    }

    #[cfg(any(test, feature = "test-helpers"))]
    /// Set the serialized transaction bytes
    pub fn set_serialized_transaction(&mut self, serialized_bytes: Vec<u8>) {
        match self {
            RelayedTransaction::V1(transaction) => {
                transaction.serialized_transaction = serialized_bytes;
            }
        }
    }
}

impl RelayedTransactionV1 {
    /// The hash of the relayed transaction (max_gas (big endian) || serialized_transaction)
    pub fn id(&self) -> RelayedTransactionId {
        let hasher = fuel_crypto::Hasher::default()
            .chain(self.nonce.as_slice())
            .chain(self.max_gas.to_be_bytes())
            .chain(self.serialized_transaction.as_slice());
        RelayedTransactionId((*hasher.finalize()).into())
    }
}

impl From<RelayedTransactionV1> for RelayedTransaction {
    fn from(relayed_transaction: RelayedTransactionV1) -> Self {
        RelayedTransaction::V1(relayed_transaction)
    }
}

#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq)]
/// Potential states for the relayed transaction
pub enum RelayedTransactionStatus {
    /// Transaction was included in a block, but the execution was reverted
    Failed {
        /// The height of the block that processed this transaction
        block_height: BlockHeight,
        /// The actual failure reason for why the forced transaction was not included
        failure: String,
    },
}