6
6
use support:: { decl_module, decl_storage, decl_event, ensure, dispatch:: Result , StorageValue , traits:: Get } ;
7
7
use system:: ensure_signed;
8
8
use codec:: { Encode , Decode } ;
9
- use accumulator:: { U2048 , Witness } ;
9
+ use accumulator:: * ;
10
10
pub mod binary;
11
11
pub mod vc;
12
12
@@ -34,7 +34,7 @@ pub trait Trait: system::Trait {
34
34
decl_storage ! {
35
35
trait Store for Module <T : Trait > as StatelessAccounts {
36
36
State get( get_state) : U2048 = U2048 :: from( 2 ) ; // Use 2 as an arbitrary generator with "unknown" order.
37
- WitnessData : Vec <( U2048 , U2048 ) >;
37
+ WitnessData get ( get_witness_data ) : Vec <( U2048 , U2048 ) >;
38
38
NewKeyValuePairs : Vec <( u8 , u8 ) >;
39
39
}
40
40
}
@@ -53,6 +53,8 @@ decl_module! {
53
53
fn deposit_event( ) = default ;
54
54
const KeySpace : u8 = T :: KeySpace :: get( ) ;
55
55
56
+ /// Arbitrarily add a new key-value store to the accumulator.
57
+ /// NOTE: The key must not exist initially.
56
58
pub fn mint( origin, key: u8 , amount: u8 ) -> Result {
57
59
ensure_signed( origin) ?;
58
60
let ( state, product) = vc:: commit( State :: get( ) , & [ key as usize ] , & [ amount] ) ;
@@ -61,10 +63,15 @@ decl_module! {
61
63
Ok ( ( ) )
62
64
}
63
65
66
+ /// Submit a transaction to the chain.
67
+ /// NOTE: All transactions must be referenced from the same previous "state". In practice,
68
+ /// this might be the state of the previous block for example. This is a workaround to
69
+ /// prevent having to pass in the product of all of the elements in the accumulator.
64
70
pub fn add_transaction( origin, transaction: Transaction , old_state: U2048 ) -> Result {
65
71
ensure_signed( origin) ?;
66
72
// Get the opening of the sender
67
73
let ( pi_i_sender, pi_e_sender) = transaction. sender_opening;
74
+
68
75
// Verify that it is valid
69
76
ensure!( vc:: verify_at_key( old_state, State :: get( ) , transaction. sender_key as usize ,
70
77
transaction. sender_balance, pi_i_sender, pi_e_sender) , "Opening is invalid." ) ;
@@ -88,9 +95,9 @@ decl_module! {
88
95
89
96
// Currently omitting non-membership proofs for simplicity
90
97
91
- // Temporarily store the existing key-value pairs
92
- NewKeyValuePairs :: append( & vec![ ( transaction. sender_key, transaction. sender_balance) ] ) ;
93
- NewKeyValuePairs :: append( & vec![ ( transaction. receiver_key, transaction. receiver_balance) ] ) ;
98
+ // Temporarily store the new key-value pairs
99
+ NewKeyValuePairs :: append( & vec![ ( transaction. sender_key, transaction. sender_balance-transaction . amount ) ] ) ;
100
+ NewKeyValuePairs :: append( & vec![ ( transaction. receiver_key, transaction. receiver_balance+transaction . amount ) ] ) ;
94
101
Ok ( ( ) )
95
102
}
96
103
@@ -99,6 +106,7 @@ decl_module! {
99
106
let ( state, product, proof) = accumulator:: batch_delete( State :: get( ) , & WitnessData :: get( ) ) ;
100
107
Self :: deposit_event( Event :: Deletion ( state, product, proof) ) ;
101
108
109
+ // Get the integer representations of the new key-value pairs.
102
110
let elems: Vec <U2048 > = NewKeyValuePairs :: get( )
103
111
. into_iter( )
104
112
. enumerate( )
@@ -128,10 +136,11 @@ decl_module! {
128
136
mod tests {
129
137
use super :: * ;
130
138
139
+ use runtime_io:: with_externalities;
131
140
use primitives:: { H256 , Blake2Hasher } ;
132
141
use support:: { impl_outer_origin, assert_ok, parameter_types} ;
133
142
use sr_primitives:: {
134
- traits:: { BlakeTwo256 , IdentityLookup } , testing:: Header , weights:: Weight , Perbill ,
143
+ traits:: { BlakeTwo256 , IdentityLookup , OnFinalize } , testing:: Header , weights:: Weight , Perbill ,
135
144
} ;
136
145
137
146
impl_outer_origin ! {
@@ -174,11 +183,94 @@ mod tests {
174
183
type Event = ( ) ;
175
184
type KeySpace = KeySpace ;
176
185
}
186
+
177
187
type StatelessAccounts = Module < Test > ;
188
+ type System = system:: Module < Test > ;
178
189
179
190
// This function basically just builds a genesis storage key/value store according to
180
191
// our desired mockup.
181
192
fn new_test_ext ( ) -> runtime_io:: TestExternalities < Blake2Hasher > {
182
193
system:: GenesisConfig :: default ( ) . build_storage :: < Test > ( ) . unwrap ( ) . into ( )
183
194
}
195
+
196
+ #[ test]
197
+ fn test_mint ( ) {
198
+ with_externalities ( & mut new_test_ext ( ) , || {
199
+ let key: u8 = 1 ;
200
+ let value: u8 = 10 ;
201
+ StatelessAccounts :: mint ( Origin :: signed ( 1 ) , key, value) ;
202
+
203
+ let ( binary_vec, indices) = vc:: convert_key_value ( & [ key as usize ] , & [ value] ) ;
204
+ let ( p_ones, _) = binary:: get_bit_elems ( & binary_vec, & indices) ;
205
+ assert_eq ! ( StatelessAccounts :: get_state( ) , subroutines:: mod_exp( U2048 :: from( 2 ) , p_ones, U2048 :: from_dec_str( MODULUS ) . unwrap( ) ) ) ;
206
+ } ) ;
207
+ }
208
+
209
+ #[ test]
210
+ fn test_transaction ( ) {
211
+ with_externalities ( & mut new_test_ext ( ) , || {
212
+ let generator = StatelessAccounts :: get_state ( ) ;
213
+
214
+ // Define keys for alice and bob
215
+ let alice_key: u8 = 12 ;
216
+ let bob_key: u8 = 58 ;
217
+
218
+ // Define balances for alice and bob
219
+ let alice_balance: u8 = 10 ;
220
+ let bob_balance: u8 = 5 ;
221
+
222
+ // Mint tokens for each user
223
+ StatelessAccounts :: mint ( Origin :: signed ( 1 ) , alice_key, alice_balance) ;
224
+ StatelessAccounts :: mint ( Origin :: signed ( 1 ) , bob_key, bob_balance) ;
225
+
226
+ // Derive integer representations for manual testing
227
+ let alice_elem = vc:: get_key_value_elem ( alice_key as usize , alice_balance) ; // This value would be received from the emitted event.
228
+ let bob_elem = vc:: get_key_value_elem ( bob_key as usize , bob_balance) ; // This value would be received from the emitted event.
229
+ let product = alice_elem * bob_elem;
230
+
231
+ // Get state after minting
232
+ let state_after_mint = StatelessAccounts :: get_state ( ) ;
233
+
234
+ // Get openings for each user
235
+ let ( alice_pi_i, alice_pi_e) = vc:: open_at_key ( generator, product, alice_key as usize , alice_balance) ;
236
+ let ( bob_pi_i, bob_pi_e) = vc:: open_at_key ( generator, product, bob_key as usize , bob_balance) ;
237
+
238
+ // Construct transaction
239
+ let transaction = Transaction {
240
+ sender_key : alice_key,
241
+ sender_balance : alice_balance,
242
+ sender_elem : alice_elem,
243
+ sender_opening : ( alice_pi_i, alice_pi_e) ,
244
+ receiver_key : bob_key,
245
+ receiver_balance : bob_balance,
246
+ receiver_elem : bob_elem,
247
+ receiver_opening : ( bob_pi_i, bob_pi_e) ,
248
+ amount : 3 ,
249
+ } ;
250
+
251
+ // Submit transaction
252
+ StatelessAccounts :: add_transaction ( Origin :: signed ( 1 ) , transaction, generator) ;
253
+
254
+ // Manually get the state after deletion for manual testing
255
+ let ( state_after_del, _, _) = batch_delete ( state_after_mint, & StatelessAccounts :: get_witness_data ( ) ) ;
256
+
257
+ // Finalize block
258
+ StatelessAccounts :: on_finalize ( System :: block_number ( ) ) ;
259
+
260
+ // Get the new state
261
+ let new_state = StatelessAccounts :: get_state ( ) ;
262
+
263
+ // Derive integer representations for alice and bob's new key-value stores
264
+ let new_alice_elem = vc:: get_key_value_elem ( alice_key as usize , alice_balance-3 ) ; // This value would be received from the emitted event.
265
+ let new_bob_elem = vc:: get_key_value_elem ( bob_key as usize , bob_balance+3 ) ; // This value would be received from the emitted event.
266
+
267
+ // Create openings with the new balances
268
+ let ( alice_pi_i_new, alice_pi_e_new) = vc:: open_at_key ( state_after_del, new_alice_elem* new_bob_elem, alice_key as usize , alice_balance-3 ) ;
269
+ let ( bob_pi_i_new, bob_pi_e_new) = vc:: open_at_key ( state_after_del, new_alice_elem* new_bob_elem, bob_key as usize , bob_balance+3 ) ;
270
+
271
+ // Verify that the openings are valid
272
+ assert_eq ! ( vc:: verify_at_key( state_after_del, new_state, alice_key as usize , alice_balance-3 , alice_pi_i_new, alice_pi_e_new) , true ) ;
273
+ assert_eq ! ( vc:: verify_at_key( state_after_del, new_state, bob_key as usize , bob_balance+3 , bob_pi_i_new, bob_pi_e_new) , true ) ;
274
+ } ) ;
275
+ }
184
276
}
0 commit comments