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
//! The common types that will be used across a Tuxedo runtime, and not specific to any one piece

use crate::{dynamic_typing::DynamicallyTypedData, ConstraintChecker, Verifier};
use parity_scale_codec::{Decode, Encode};
use scale_info::TypeInfo;
use serde::{Deserialize, Serialize};
use sp_core::H256;
use sp_runtime::{
    traits::{BlakeTwo256, Extrinsic, Hash as HashT},
    transaction_validity::InvalidTransaction,
};
use sp_std::vec::Vec;

// All Tuxedo chains use the same BlakeTwo256 hash.
pub type Hash = BlakeTwo256;
/// Opaque block hash type.
pub type OpaqueHash = <Hash as HashT>::Output;
/// All Tuxedo chains use the same u32 BlockNumber.
pub type BlockNumber = u32;
/// Because all tuxedo chains use the same Blocknumber and Hash types,
/// they also use the same concrete header type.
pub type Header = sp_runtime::generic::Header<BlockNumber, Hash>;
/// An alias for a Tuxedo block with all the common parts filled in.
pub type Block<V, C> = sp_runtime::generic::Block<Header, Transaction<V, C>>;
/// Opaque block type. It has a Standard Tuxedo header, and opaque transactions.
pub type OpaqueBlock = sp_runtime::generic::Block<Header, sp_runtime::OpaqueExtrinsic>;

/// A reference to a output that is expected to exist in the state.
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
pub struct OutputRef {
    /// A hash of the transaction that created this output
    pub tx_hash: H256,
    /// The index of this output among all outputs created by the same transaction
    pub index: u32,
}

/// A UTXO Transaction
///
/// Each transaction consumes some UTXOs (the inputs) and creates some new ones (the outputs).
///
/// The Transaction type is generic over two orthogonal pieces of validation logic:
/// 1. Verifier - A verifier checks that an individual input may be consumed. A typical example
///    of a verifier is checking that there is a signature by the proper owner. Other examples
///    may be that anyone can consume the input or no one can, or that a proof of work is required.
/// 2. ConstraintCheckers - A constraint checker checks that the transaction as a whole meets a set of requirements.
///    For example, that the total output value of a cryptocurrency transaction does not exceed its
///    input value. Or that a cryptokitty was created with the correct genetic material from its parents.
///
/// In the future, there may be additional notions of peeks (inputs that are not consumed)
/// and evictions (inputs that are forcefully consumed.)
/// Existing state to be read and consumed from storage
#[derive(Serialize, Deserialize, Default, Debug, PartialEq, Eq, Clone, TypeInfo)]
pub struct Transaction<V, C> {
    /// Existing pieces of state to be read and consumed from storage
    pub inputs: Vec<Input>,
    /// Existing state to be read, but not consumed, from storage
    pub peeks: Vec<OutputRef>,
    /// New state to be placed into storage
    pub outputs: Vec<Output<V>>,
    /// Which piece of constraint checking logic is used to determine whether this transaction is valid
    pub checker: C,
}

impl<V: Clone, C: Clone> Transaction<V, C> {
    /// A helper function for transforming a transaction generic over one
    /// kind of constraint checker into a transaction generic over another type
    /// of constraint checker. This is useful when moving up and down the aggregation tree.
    pub fn transform<D: From<C>>(&self) -> Transaction<V, D> {
        Transaction {
            inputs: self.inputs.clone(),
            peeks: self.peeks.clone(),
            outputs: self.outputs.clone(),
            checker: self.checker.clone().into(),
        }
    }
}

// Manually implement Encode and Decode for the Transaction type
// so that its encoding is the same as an opaque Vec<u8>.
impl<V: Encode, C: Encode> Encode for Transaction<V, C> {
    fn encode_to<T: parity_scale_codec::Output + ?Sized>(&self, dest: &mut T) {
        let inputs = self.inputs.encode();
        let peeks = self.peeks.encode();
        let outputs = self.outputs.encode();
        let checker = self.checker.encode();

        let total_len = (inputs.len() + outputs.len() + peeks.len() + checker.len()) as u32;
        let size = parity_scale_codec::Compact::<u32>(total_len).encode();

        dest.write(&size);
        dest.write(&inputs);
        dest.write(&peeks);
        dest.write(&outputs);
        dest.write(&checker);
    }
}

impl<V: Decode, C: Decode> Decode for Transaction<V, C> {
    fn decode<I: parity_scale_codec::Input>(
        input: &mut I,
    ) -> Result<Self, parity_scale_codec::Error> {
        // Throw away the length of the vec. We just want the bytes.
        <parity_scale_codec::Compact<u32>>::skip(input)?;

        let inputs = <Vec<Input>>::decode(input)?;
        let peeks = <Vec<OutputRef>>::decode(input)?;
        let outputs = <Vec<Output<V>>>::decode(input)?;
        let checker = C::decode(input)?;

        Ok(Transaction {
            inputs,
            peeks,
            outputs,
            checker,
        })
    }
}

// We must implement this Extrinsic trait to use our Transaction type as the Block's associated Extrinsic type.
// See https://paritytech.github.io/polkadot-sdk/master/sp_runtime/traits/trait.Block.html#associatedtype.Extrinsic
//
// This trait's design has a preference for transactions that will have a single signature over the
// entire transaction, so it is not very useful for us. We still need to implement it to satisfy the bound,
// so we do a minimal implementation.
impl<V, C> Extrinsic for Transaction<V, C>
where
    C: TypeInfo + ConstraintChecker + 'static,
    V: TypeInfo + Verifier + 'static,
{
    type Call = Self;
    type SignaturePayload = ();

    fn new(data: Self, _: Option<Self::SignaturePayload>) -> Option<Self> {
        Some(data)
    }

    // The signature on this function is not the best. Ultimately it is
    // trying to distinguish between three potential types of transactions:
    // 1. Signed user transactions: `Some(true)`
    // 2. Unsigned user transactions: `None`
    // 3. Unsigned inherents: `Some(false)`
    //
    // In Substrate generally, and also in FRAME, all three of these could exist.
    // But in Tuxedo we will never have signed user transactions, and therefore
    // will never return `Some(true)`.
    //
    // Perhaps a dedicated enum makes more sense as the return type?
    // That would be a Substrate PR after this is more tried and true.
    fn is_signed(&self) -> Option<bool> {
        if self.checker.is_inherent() {
            Some(false)
        } else {
            None
        }
    }
}

/// A reference the a utxo that will be consumed along with proof that it may be consumed
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
pub struct Input {
    /// a reference to the output being consumed
    pub output_ref: OutputRef,
    /// A means of showing that this input data can be used.
    /// It is most often a proof such as a signature, but could also be a forceful eviction.
    pub redeemer: RedemptionStrategy,
}

//TODO Consider making this enum generic over the redeemer type so there is not an additional decoding necessary.
// This would percolate up though. For example input would also have to be generic over the redeemer type.
// IDK if it is appropriate to be making so many types non-opaque??
/// An input can be consumed in two way. It can be redeemed normally (probably with some signature, or proof) or it
/// can be evicted. This enum is isomorphic to `Option<Vec<u8>>` but has more meaningful names.
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
pub enum RedemptionStrategy {
    /// The input is being consumed in the normal way with a signature or other proof provided by the spender.
    Redemption(Vec<u8>),
    /// The input is being forcefully evicted without satisfying its Verifier.
    Eviction,
}

impl Default for RedemptionStrategy {
    fn default() -> Self {
        Self::Redemption(Vec::new())
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum UtxoError<ConstraintCheckerError> {
    /// This transaction defines the same input multiple times
    DuplicateInput,
    /// This transaction defines an output that already existed in the UTXO set
    PreExistingOutput,
    /// The constraint checker errored.
    ConstraintCheckerError(ConstraintCheckerError),
    /// The Verifier errored.
    /// TODO determine whether it is useful to relay an inner error from the verifier.
    /// So far, I haven't seen a case, although it seems reasonable to think there might be one.
    VerifierError,
    /// One or more of the inputs required by this transaction is not present in the UTXO set
    MissingInput,
}

// Substrate requires this supposedly reusable error type, but it is actually tied pretty tightly
// to the accounts model and some specific FRAME signed extensions. We map it the best we can.
impl<ConstraintCheckerError> From<UtxoError<ConstraintCheckerError>> for InvalidTransaction {
    fn from(utxo_error: UtxoError<ConstraintCheckerError>) -> Self {
        match utxo_error {
            UtxoError::DuplicateInput => InvalidTransaction::Custom(255),
            UtxoError::PreExistingOutput => InvalidTransaction::Custom(254),
            UtxoError::ConstraintCheckerError(_) => InvalidTransaction::Custom(0),
            UtxoError::VerifierError => InvalidTransaction::BadProof,
            UtxoError::MissingInput => InvalidTransaction::Future,
        }
    }
}

/// The Result of dispatching a UTXO transaction.
pub type DispatchResult<ConstraintCheckerError> = Result<(), UtxoError<ConstraintCheckerError>>;

/// An opaque piece of Transaction output data. This is how the data appears at the Runtime level. After
/// the verifier is checked, strongly typed data will be extracted and passed to the constraint checker.
/// In a cryptocurrency, the data represents a single coin. In Tuxedo, the type of
/// the contained data is generic.
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
pub struct Output<V> {
    pub payload: DynamicallyTypedData,
    pub verifier: V,
}

impl<V: Default> From<DynamicallyTypedData> for Output<V> {
    fn from(payload: DynamicallyTypedData) -> Self {
        Self {
            payload,
            verifier: Default::default(),
        }
    }
}

impl<V, V1: Into<V>, P: Into<DynamicallyTypedData>> From<(P, V1)> for Output<V> {
    fn from(values: (P, V1)) -> Self {
        Self {
            payload: values.0.into(),
            verifier: values.1.into(),
        }
    }
}

#[cfg(test)]
pub mod tests {

    use crate::{constraint_checker::testing::TestConstraintChecker, verifier::TestVerifier};

    use super::*;

    #[test]
    fn extrinsic_no_signed_payload() {
        let checker = TestConstraintChecker {
            checks: true,
            inherent: false,
        };
        let tx: Transaction<TestVerifier, TestConstraintChecker> = Transaction {
            inputs: Vec::new(),
            peeks: Vec::new(),
            outputs: Vec::new(),
            checker,
        };
        let e = Transaction::new(tx.clone(), None).unwrap();

        assert_eq!(e, tx);
        assert_eq!(e.is_signed(), None);
    }

    #[test]
    fn extrinsic_is_signed_works() {
        let checker = TestConstraintChecker {
            checks: true,
            inherent: false,
        };
        let tx: Transaction<TestVerifier, TestConstraintChecker> = Transaction {
            inputs: Vec::new(),
            peeks: Vec::new(),
            outputs: Vec::new(),
            checker,
        };
        let e = Transaction::new(tx.clone(), Some(())).unwrap();

        assert_eq!(e, tx);
        assert_eq!(e.is_signed(), None);
    }

    #[test]
    fn extrinsic_is_signed_works_for_inherents() {
        let checker = TestConstraintChecker {
            checks: true,
            inherent: true,
        };
        let tx: Transaction<TestVerifier, TestConstraintChecker> = Transaction {
            inputs: Vec::new(),
            peeks: Vec::new(),
            outputs: Vec::new(),
            checker,
        };
        let e = Transaction::new(tx.clone(), Some(())).unwrap();

        assert_eq!(e, tx);
        assert_eq!(e.is_signed(), Some(false));
    }
}