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
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[cfg(not(feature = "std"))]
use core::result::Result;
use bitvec::prelude::BitVec;
use crate::transaction::{PlasmaCashTxn, TxnCmp};
#[derive(Debug, PartialEq)]
pub enum TokenStatus {
RootChain,
Deposit,
PlasmaChain,
Withdrawal,
}
pub struct Token<TxnType, HashType>
where
TxnType: PlasmaCashTxn,
HashType: AsRef<[u8]>,
{
pub uid: BitVec,
pub status: TokenStatus,
pub history: Vec<TxnType>,
pub proofs: Vec<Vec<HashType>>,
}
impl<TxnType, HashType> Token<TxnType, HashType>
where
TxnType: PlasmaCashTxn,
HashType: AsRef<[u8]>,
{
pub fn new(uid: BitVec) -> Token<TxnType, HashType> {
Token {
uid,
status: TokenStatus::RootChain,
history: Vec::new(),
proofs: Vec::new(),
}
}
pub fn is_valid(&self) -> bool {
is_history_valid(&self.history)
}
pub fn add_transaction(&mut self, txn: TxnType) -> Result<(), &'static str> {
match self.history.last() {
Some(last_txn) if txn.compare(last_txn) != TxnCmp::Child =>
Err("Transaction is not a child of previous transaction."),
_ => {
self.history.push(txn);
Ok(())
},
}
}
}
fn is_history_valid<TxnType>(
history: &[TxnType],
) -> bool
where
TxnType: PlasmaCashTxn,
{
if history.is_empty() {
return true;
}
if !history.iter().all(|txn| txn.valid()) {
return false;
}
let mut history_iter = history.iter().peekable();
while let Some(prev_txn) = history_iter.next() {
if let Some(txn) = history_iter.peek() {
match txn.compare(&prev_txn) {
TxnCmp::Child => { },
_ => { return false },
}
}
}
true
}