@@ -47,7 +47,7 @@ use crate::{
47
47
transaction:: {
48
48
CommitTransaction , DRTransaction , DRTransactionBody , Memoized , MintTransaction ,
49
49
RevealTransaction , StakeTransaction , TallyTransaction , Transaction , TxInclusionProof ,
50
- VTTransaction ,
50
+ UnstakeTransaction , VTTransaction ,
51
51
} ,
52
52
transaction:: {
53
53
MemoHash , MemoizedHashable , BETA , COMMIT_WEIGHT , OUTPUT_SIZE , REVEAL_WEIGHT , TALLY_WEIGHT ,
@@ -419,6 +419,8 @@ pub struct BlockTransactions {
419
419
pub tally_txns : Vec < TallyTransaction > ,
420
420
/// A list of signed stake transactions
421
421
pub stake_txns : Vec < StakeTransaction > ,
422
+ /// A list of signed unstake transactions
423
+ pub unstake_txns : Vec < UnstakeTransaction > ,
422
424
}
423
425
424
426
impl Block {
@@ -448,6 +450,7 @@ impl Block {
448
450
reveal_txns : vec ! [ ] ,
449
451
tally_txns : vec ! [ ] ,
450
452
stake_txns : vec ! [ ] ,
453
+ unstake_txns : vec ! [ ] ,
451
454
} ;
452
455
453
456
/// Function to calculate a merkle tree from a transaction vector
@@ -473,6 +476,7 @@ impl Block {
473
476
reveal_hash_merkle_root : merkle_tree_root ( & txns. reveal_txns ) ,
474
477
tally_hash_merkle_root : merkle_tree_root ( & txns. tally_txns ) ,
475
478
stake_hash_merkle_root : merkle_tree_root ( & txns. stake_txns ) ,
479
+ unstake_hash_merkle_root : merkle_tree_root ( & txns. unstake_txns ) ,
476
480
} ;
477
481
478
482
Block :: new (
@@ -515,8 +519,16 @@ impl Block {
515
519
st_weight
516
520
}
517
521
522
+ pub fn ut_weight ( & self ) -> u32 {
523
+ let mut ut_weight = 0 ;
524
+ for ut_txn in self . txns . unstake_txns . iter ( ) {
525
+ ut_weight += ut_txn. weight ( ) ;
526
+ }
527
+ ut_weight
528
+ }
529
+
518
530
pub fn weight ( & self ) -> u32 {
519
- self . dr_weight ( ) + self . vt_weight ( ) + self . st_weight ( )
531
+ self . dr_weight ( ) + self . vt_weight ( ) + self . st_weight ( ) + self . ut_weight ( )
520
532
}
521
533
}
522
534
@@ -531,6 +543,7 @@ impl BlockTransactions {
531
543
+ self . reveal_txns . len ( )
532
544
+ self . tally_txns . len ( )
533
545
+ self . stake_txns . len ( )
546
+ + self . unstake_txns . len ( )
534
547
}
535
548
536
549
/// Returns true if this block contains no transactions
@@ -543,6 +556,7 @@ impl BlockTransactions {
543
556
&& self . reveal_txns . is_empty ( )
544
557
&& self . tally_txns . is_empty ( )
545
558
&& self . stake_txns . is_empty ( )
559
+ && self . unstake_txns . is_empty ( )
546
560
}
547
561
548
562
/// Get a transaction given the `TransactionPointer`
@@ -579,6 +593,11 @@ impl BlockTransactions {
579
593
. get ( i as usize )
580
594
. cloned ( )
581
595
. map ( Transaction :: Stake ) ,
596
+ TransactionPointer :: Unstake ( i) => self
597
+ . unstake_txns
598
+ . get ( i as usize )
599
+ . cloned ( )
600
+ . map ( Transaction :: Unstake ) ,
582
601
}
583
602
}
584
603
@@ -626,6 +645,11 @@ impl BlockTransactions {
626
645
TransactionPointer :: Stake ( u32:: try_from ( i) . unwrap ( ) ) ;
627
646
items_to_add. push ( ( tx. hash ( ) , pointer_to_block. clone ( ) ) ) ;
628
647
}
648
+ for ( i, tx) in self . unstake_txns . iter ( ) . enumerate ( ) {
649
+ pointer_to_block. transaction_index =
650
+ TransactionPointer :: Unstake ( u32:: try_from ( i) . unwrap ( ) ) ;
651
+ items_to_add. push ( ( tx. hash ( ) , pointer_to_block. clone ( ) ) ) ;
652
+ }
629
653
630
654
items_to_add
631
655
}
@@ -709,6 +733,8 @@ pub struct BlockMerkleRoots {
709
733
pub tally_hash_merkle_root : Hash ,
710
734
/// A 256-bit hash based on all of the stake transactions committed to this block
711
735
pub stake_hash_merkle_root : Hash ,
736
+ /// A 256-bit hash based on all of the unstake transactions committed to this block
737
+ pub unstake_hash_merkle_root : Hash ,
712
738
}
713
739
714
740
/// Function to calculate a merkle tree from a transaction vector
@@ -738,6 +764,7 @@ impl BlockMerkleRoots {
738
764
reveal_hash_merkle_root : merkle_tree_root ( & txns. reveal_txns ) ,
739
765
tally_hash_merkle_root : merkle_tree_root ( & txns. tally_txns ) ,
740
766
stake_hash_merkle_root : merkle_tree_root ( & txns. stake_txns ) ,
767
+ unstake_hash_merkle_root : merkle_tree_root ( & txns. unstake_txns ) ,
741
768
}
742
769
}
743
770
}
@@ -2026,6 +2053,7 @@ type PrioritizedHash = (OrderedFloat<f64>, Hash);
2026
2053
type PrioritizedVTTransaction = ( OrderedFloat < f64 > , VTTransaction ) ;
2027
2054
type PrioritizedDRTransaction = ( OrderedFloat < f64 > , DRTransaction ) ;
2028
2055
type PrioritizedStakeTransaction = ( OrderedFloat < f64 > , StakeTransaction ) ;
2056
+ type PrioritizedUnstakeTransaction = ( OrderedFloat < f64 > , UnstakeTransaction ) ;
2029
2057
2030
2058
#[ derive( Debug , Clone , Default ) ]
2031
2059
struct UnconfirmedTransactions {
@@ -2084,6 +2112,8 @@ pub struct TransactionsPool {
2084
2112
total_dr_weight : u64 ,
2085
2113
// Total size of all stake transactions inside the pool in weight units
2086
2114
total_st_weight : u64 ,
2115
+ // Total size of all unstake transactions inside the pool in weight units
2116
+ total_ut_weight : u64 ,
2087
2117
// TransactionsPool size limit in weight units
2088
2118
weight_limit : u64 ,
2089
2119
// Ratio of value transfer transaction to data request transaction that should be in the
@@ -2109,9 +2139,14 @@ pub struct TransactionsPool {
2109
2139
// first query the index for the hash, and then using the hash to find the actual data)
2110
2140
st_transactions : HashMap < Hash , PrioritizedStakeTransaction > ,
2111
2141
sorted_st_index : BTreeSet < PrioritizedHash > ,
2142
+ ut_transactions : HashMap < Hash , PrioritizedUnstakeTransaction > ,
2143
+ sorted_ut_index : BTreeSet < PrioritizedHash > ,
2112
2144
// Minimum fee required to include a Stake Transaction into a block. We check for this fee in the
2113
2145
// TransactionPool so we can choose not to insert a transaction we will not mine anyway.
2114
2146
minimum_st_fee : u64 ,
2147
+ // Minimum fee required to include a Unstake Transaction into a block. We check for this fee in the
2148
+ // TransactionPool so we can choose not to insert a transaction we will not mine anyway.
2149
+ minimum_ut_fee : u64 ,
2115
2150
}
2116
2151
2117
2152
impl Default for TransactionsPool {
@@ -2129,6 +2164,7 @@ impl Default for TransactionsPool {
2129
2164
total_vt_weight : 0 ,
2130
2165
total_dr_weight : 0 ,
2131
2166
total_st_weight : 0 ,
2167
+ total_ut_weight : 0 ,
2132
2168
// Unlimited by default
2133
2169
weight_limit : u64:: MAX ,
2134
2170
// Try to keep the same amount of value transfer weight and data request weight
@@ -2137,13 +2173,17 @@ impl Default for TransactionsPool {
2137
2173
minimum_vtt_fee : 0 ,
2138
2174
// Default is to include all transactions into the pool and blocks
2139
2175
minimum_st_fee : 0 ,
2176
+ // Default is to include all transactions into the pool and blocks
2177
+ minimum_ut_fee : 0 ,
2140
2178
// Collateral minimum from consensus constants
2141
2179
collateral_minimum : 0 ,
2142
2180
// Required minimum reward to collateral percentage is defined as a consensus constant
2143
2181
required_reward_collateral_ratio : u64:: MAX ,
2144
2182
unconfirmed_transactions : Default :: default ( ) ,
2145
2183
st_transactions : Default :: default ( ) ,
2146
2184
sorted_st_index : Default :: default ( ) ,
2185
+ ut_transactions : Default :: default ( ) ,
2186
+ sorted_ut_index : Default :: default ( ) ,
2147
2187
}
2148
2188
}
2149
2189
}
@@ -2216,6 +2256,7 @@ impl TransactionsPool {
2216
2256
&& self . co_transactions . is_empty ( )
2217
2257
&& self . re_transactions . is_empty ( )
2218
2258
&& self . st_transactions . is_empty ( )
2259
+ && self . ut_transactions . is_empty ( )
2219
2260
}
2220
2261
2221
2262
/// Remove all the transactions but keep the allocated memory for reuse.
@@ -2233,15 +2274,19 @@ impl TransactionsPool {
2233
2274
total_vt_weight,
2234
2275
total_dr_weight,
2235
2276
total_st_weight,
2277
+ total_ut_weight,
2236
2278
weight_limit : _,
2237
2279
vt_to_dr_factor : _,
2238
2280
minimum_vtt_fee : _,
2239
2281
minimum_st_fee : _,
2282
+ minimum_ut_fee : _,
2240
2283
collateral_minimum : _,
2241
2284
required_reward_collateral_ratio : _,
2242
2285
unconfirmed_transactions,
2243
2286
st_transactions,
2244
2287
sorted_st_index,
2288
+ ut_transactions,
2289
+ sorted_ut_index,
2245
2290
} = self ;
2246
2291
2247
2292
vt_transactions. clear ( ) ;
@@ -2256,9 +2301,12 @@ impl TransactionsPool {
2256
2301
* total_vt_weight = 0 ;
2257
2302
* total_dr_weight = 0 ;
2258
2303
* total_st_weight = 0 ;
2304
+ * total_ut_weight = 0 ;
2259
2305
unconfirmed_transactions. clear ( ) ;
2260
2306
st_transactions. clear ( ) ;
2261
2307
sorted_st_index. clear ( ) ;
2308
+ ut_transactions. clear ( ) ;
2309
+ sorted_ut_index. clear ( ) ;
2262
2310
}
2263
2311
2264
2312
/// Returns the number of value transfer transactions in the pool.
@@ -2324,6 +2372,27 @@ impl TransactionsPool {
2324
2372
self . st_transactions . len ( )
2325
2373
}
2326
2374
2375
+ /// Returns the number of unstake transactions in the pool.
2376
+ ///
2377
+ /// # Examples:
2378
+ ///
2379
+ /// ```
2380
+ /// # use witnet_data_structures::chain::{TransactionsPool, Hash};
2381
+ /// # use witnet_data_structures::transaction::{Transaction, StakeTransaction};
2382
+ /// let mut pool = TransactionsPool::new();
2383
+ ///
2384
+ /// let transaction = Transaction::Stake(StakeTransaction::default());
2385
+ ///
2386
+ /// assert_eq!(pool.st_len(), 0);
2387
+ ///
2388
+ /// pool.insert(transaction, 0);
2389
+ ///
2390
+ /// assert_eq!(pool.st_len(), 1);
2391
+ /// ```
2392
+ pub fn ut_len ( & self ) -> usize {
2393
+ self . ut_transactions . len ( )
2394
+ }
2395
+
2327
2396
/// Clear commit transactions in TransactionsPool
2328
2397
pub fn clear_commits ( & mut self ) {
2329
2398
self . co_transactions . clear ( ) ;
@@ -2365,7 +2434,8 @@ impl TransactionsPool {
2365
2434
// be impossible for nodes to broadcast these kinds of transactions.
2366
2435
Transaction :: Tally ( _tt) => Err ( TransactionError :: NotValidTransaction ) ,
2367
2436
Transaction :: Mint ( _mt) => Err ( TransactionError :: NotValidTransaction ) ,
2368
- Transaction :: Stake ( _mt) => Ok ( self . st_contains ( & tx_hash) ) ,
2437
+ Transaction :: Stake ( _st) => Ok ( self . st_contains ( & tx_hash) ) ,
2438
+ Transaction :: Unstake ( _ut) => Ok ( self . ut_contains ( & tx_hash) ) ,
2369
2439
}
2370
2440
}
2371
2441
@@ -2481,6 +2551,30 @@ impl TransactionsPool {
2481
2551
self . st_transactions . contains_key ( key)
2482
2552
}
2483
2553
2554
+ /// Returns `true` if the pool contains an unstake transaction for the
2555
+ /// specified hash.
2556
+ ///
2557
+ /// The `key` may be any borrowed form of the hash, but `Hash` and
2558
+ /// `Eq` on the borrowed form must match those for the key type.
2559
+ ///
2560
+ /// # Examples:
2561
+ /// ```
2562
+ /// # use witnet_data_structures::chain::{TransactionsPool, Hash, Hashable};
2563
+ /// # use witnet_data_structures::transaction::{Transaction, UnstakeTransaction};
2564
+ /// let mut pool = TransactionsPool::new();
2565
+ ///
2566
+ /// let transaction = Transaction::Stake(UnstakeTransaction::default());
2567
+ /// let hash = transaction.hash();
2568
+ /// assert!(!pool.ut_contains(&hash));
2569
+ ///
2570
+ /// pool.insert(transaction, 0);
2571
+ ///
2572
+ /// assert!(pool.t_contains(&hash));
2573
+ /// ```
2574
+ pub fn ut_contains ( & self , key : & Hash ) -> bool {
2575
+ self . ut_transactions . contains_key ( key)
2576
+ }
2577
+
2484
2578
/// Remove a value transfer transaction from the pool and make sure that other transactions
2485
2579
/// that may try to spend the same UTXOs are also removed.
2486
2580
/// This should be used to remove transactions that got included in a consolidated block.
@@ -2725,13 +2819,12 @@ impl TransactionsPool {
2725
2819
transaction
2726
2820
}
2727
2821
2728
- /// Remove a stake transaction from the pool but do not remove other transactions that
2729
- /// may try to spend the same UTXOs.
2822
+ /// Remove a stake from the pool but do not remove other transactions that may try to spend the
2823
+ /// same UTXOs.
2730
2824
/// This should be used to remove transactions that did not get included in a consolidated
2731
2825
/// block.
2732
2826
/// If the transaction did get included in a consolidated block, use `st_remove` instead.
2733
2827
fn st_remove_inner ( & mut self , key : & Hash , consolidated : bool ) -> Option < StakeTransaction > {
2734
- // TODO: is this taking into account the change and the stake output?
2735
2828
self . st_transactions
2736
2829
. remove ( key)
2737
2830
. map ( |( weight, transaction) | {
@@ -2744,6 +2837,21 @@ impl TransactionsPool {
2744
2837
} )
2745
2838
}
2746
2839
2840
+ /// Remove an unstake transaction from the pool but do not remove other transactions that
2841
+ /// may try to spend the same UTXOs, because this kind of transactions spend no UTXOs.
2842
+ /// This should be used to remove transactions that did not get included in a consolidated
2843
+ /// block.
2844
+ fn ut_remove_inner ( & mut self , key : & Hash ) -> Option < UnstakeTransaction > {
2845
+ self . ut_transactions
2846
+ . remove ( key)
2847
+ . map ( |( weight, transaction) | {
2848
+ self . sorted_ut_index . remove ( & ( weight, * key) ) ;
2849
+ self . total_ut_weight -= u64:: from ( transaction. weight ( ) ) ;
2850
+
2851
+ transaction
2852
+ } )
2853
+ }
2854
+
2747
2855
/// Returns a tuple with a vector of reveal transactions and the value
2748
2856
/// of all the fees obtained with those reveals
2749
2857
pub fn get_reveals ( & self , dr_pool : & DataRequestPool ) -> ( Vec < & RevealTransaction > , u64 ) {
@@ -2957,6 +3065,27 @@ impl TransactionsPool {
2957
3065
self . sorted_st_index . insert ( ( priority, key) ) ;
2958
3066
}
2959
3067
}
3068
+ Transaction :: Unstake ( ut_tx) => {
3069
+ let weight = f64:: from ( ut_tx. weight ( ) ) ;
3070
+ let priority = OrderedFloat ( fee as f64 / weight) ;
3071
+
3072
+ if fee < self . minimum_ut_fee {
3073
+ return vec ! [ Transaction :: Unstake ( ut_tx) ] ;
3074
+ } else {
3075
+ self . total_st_weight += u64:: from ( ut_tx. weight ( ) ) ;
3076
+
3077
+ // TODO
3078
+ // for input in &ut_tx.body.inputs {
3079
+ // self.output_pointer_map
3080
+ // .entry(input.output_pointer)
3081
+ // .or_insert_with(Vec::new)
3082
+ // .push(ut_tx.hash());
3083
+ // }
3084
+
3085
+ self . ut_transactions . insert ( key, ( priority, ut_tx) ) ;
3086
+ self . sorted_ut_index . insert ( ( priority, key) ) ;
3087
+ }
3088
+ }
2960
3089
tx => {
2961
3090
panic ! (
2962
3091
"Transaction kind not supported by TransactionsPool: {:?}" ,
@@ -3014,6 +3143,15 @@ impl TransactionsPool {
3014
3143
. filter_map ( move |( _, h) | self . st_transactions . get ( h) . map ( |( _, t) | t) )
3015
3144
}
3016
3145
3146
+ /// An iterator visiting all the unstake transactions
3147
+ /// in the pool
3148
+ pub fn ut_iter ( & self ) -> impl Iterator < Item = & UnstakeTransaction > {
3149
+ self . sorted_ut_index
3150
+ . iter ( )
3151
+ . rev ( )
3152
+ . filter_map ( move |( _, h) | self . ut_transactions . get ( h) . map ( |( _, t) | t) )
3153
+ }
3154
+
3017
3155
/// Returns a reference to the value corresponding to the key.
3018
3156
///
3019
3157
/// Examples:
@@ -3108,11 +3246,16 @@ impl TransactionsPool {
3108
3246
self . re_hash_index
3109
3247
. get ( hash)
3110
3248
. map ( |rt| Transaction :: Reveal ( rt. clone ( ) ) )
3111
- . or_else ( || {
3112
- self . st_transactions
3113
- . get ( hash)
3114
- . map ( |( _, st) | Transaction :: Stake ( st. clone ( ) ) )
3115
- } )
3249
+ } )
3250
+ . or_else ( || {
3251
+ self . st_transactions
3252
+ . get ( hash)
3253
+ . map ( |( _, st) | Transaction :: Stake ( st. clone ( ) ) )
3254
+ } )
3255
+ . or_else ( || {
3256
+ self . ut_transactions
3257
+ . get ( hash)
3258
+ . map ( |( _, ut) | Transaction :: Unstake ( ut. clone ( ) ) )
3116
3259
} )
3117
3260
}
3118
3261
@@ -3141,6 +3284,9 @@ impl TransactionsPool {
3141
3284
Transaction :: Stake ( _) => {
3142
3285
let _x = self . st_remove_inner ( & hash, false ) ;
3143
3286
}
3287
+ Transaction :: Unstake ( _) => {
3288
+ let _x = self . ut_remove_inner ( & hash) ;
3289
+ }
3144
3290
_ => continue ,
3145
3291
}
3146
3292
@@ -3253,6 +3399,8 @@ pub enum TransactionPointer {
3253
3399
Mint ,
3254
3400
// Stake
3255
3401
Stake ( u32 ) ,
3402
+ // Unstake
3403
+ Unstake ( u32 ) ,
3256
3404
}
3257
3405
3258
3406
/// This is how transactions are stored in the database: hash of the containing block, plus index
0 commit comments