iota_core/authority/
transaction_deferral.rs1use iota_types::base_types::{CommitRound, ObjectID};
6use serde::{Deserialize, Serialize};
7
8#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
9pub enum DeferralKey {
10 Randomness {
13 deferred_from_round: CommitRound,
14 },
15 ConsensusRound {
20 future_round: CommitRound,
21 deferred_from_round: CommitRound,
22 },
23}
24
25impl DeferralKey {
26 pub fn new_for_randomness(deferred_from_round: CommitRound) -> Self {
27 Self::Randomness {
28 deferred_from_round,
29 }
30 }
31
32 pub fn new_for_consensus_round(
33 future_round: CommitRound,
34 deferred_from_round: CommitRound,
35 ) -> Self {
36 Self::ConsensusRound {
37 future_round,
38 deferred_from_round,
39 }
40 }
41
42 pub fn full_range_for_randomness() -> (Self, Self) {
43 (
44 Self::Randomness {
45 deferred_from_round: 0,
46 },
47 Self::Randomness {
48 deferred_from_round: u64::MAX,
49 },
50 )
51 }
52
53 pub fn range_for_up_to_consensus_round(consensus_round: CommitRound) -> (Self, Self) {
56 (
57 Self::ConsensusRound {
58 future_round: 0,
59 deferred_from_round: 0,
60 },
61 Self::ConsensusRound {
62 future_round: consensus_round.checked_add(1).unwrap(),
63 deferred_from_round: 0,
64 },
65 )
66 }
67
68 pub fn deferred_from_round(&self) -> CommitRound {
69 match self {
70 Self::Randomness {
71 deferred_from_round,
72 } => *deferred_from_round,
73 Self::ConsensusRound {
74 deferred_from_round,
75 ..
76 } => *deferred_from_round,
77 }
78 }
79}
80
81#[derive(Debug)]
82pub enum DeferralReason {
83 RandomnessNotReady,
84
85 SharedObjectCongestion(Vec<ObjectID>),
87}
88
89pub fn transaction_deferral_within_limit(
90 deferral_key: &DeferralKey,
91 max_deferral_rounds_for_congestion_control: u64,
92) -> bool {
93 if let DeferralKey::ConsensusRound {
94 future_round,
95 deferred_from_round,
96 } = deferral_key
97 {
98 return (future_round - deferred_from_round) <= max_deferral_rounds_for_congestion_control;
99 }
100
101 true
104}
105
106#[cfg(test)]
107mod object_cost_tests {
108 use typed_store::{
109 DBMapUtils, Map,
110 rocks::{DBMap, MetricConf},
111 traits::{TableSummary, TypedStoreDebug},
112 };
113
114 use super::*;
115
116 #[tokio::test]
117 async fn test_deferral_key_sort_order() {
118 use rand::prelude::*;
119
120 #[derive(DBMapUtils)]
121 struct TestDB {
122 deferred_certs: DBMap<DeferralKey, ()>,
123 }
124
125 let tempdir = tempfile::tempdir().unwrap();
127
128 let db = TestDB::open_tables_read_write(
129 tempdir.path().to_owned(),
130 MetricConf::new("test_db"),
131 None,
132 None,
133 );
134
135 for _ in 0..10000 {
136 let future_round = rand::thread_rng().gen_range(0..u64::MAX);
137 let current_round = rand::thread_rng().gen_range(0..u64::MAX);
138
139 let key = DeferralKey::new_for_consensus_round(future_round, current_round);
140 db.deferred_certs.insert(&key, &()).unwrap();
141 }
142
143 let mut previous_future_round = 0;
144 for (key, _) in db.deferred_certs.unbounded_iter() {
145 match key {
146 DeferralKey::Randomness { .. } => (),
147 DeferralKey::ConsensusRound { future_round, .. } => {
148 assert!(previous_future_round <= future_round);
149 previous_future_round = future_round;
150 }
151 }
152 }
153 }
154
155 #[tokio::test]
158 async fn test_fetching_deferred_txs() {
159 use rand::prelude::*;
160
161 #[derive(DBMapUtils)]
162 struct TestDB {
163 deferred_certs: DBMap<DeferralKey, ()>,
164 }
165
166 let tempdir = tempfile::tempdir().unwrap();
168
169 let db = TestDB::open_tables_read_write(
170 tempdir.path().to_owned(),
171 MetricConf::new("test_db"),
172 None,
173 None,
174 );
175
176 let min_future_round = 100;
178 let max_future_round = 300;
179 for _ in 0..10000 {
180 let future_round = rand::thread_rng().gen_range(min_future_round..=max_future_round);
181 let current_round = rand::thread_rng().gen_range(0..u64::MAX);
182
183 db.deferred_certs
184 .insert(
185 &DeferralKey::new_for_consensus_round(future_round, current_round),
186 &(),
187 )
188 .unwrap();
189 db.deferred_certs
192 .insert(&DeferralKey::new_for_randomness(current_round), &())
193 .unwrap();
194 }
195
196 let (min, max) = DeferralKey::range_for_up_to_consensus_round(200);
198 let mut previous_future_round = 0;
199 let mut result_count = 0;
200 for result in db
201 .deferred_certs
202 .safe_iter_with_bounds(Some(min), Some(max))
203 {
204 let (key, _) = result.unwrap();
205 match key {
206 DeferralKey::Randomness { .. } => {
207 panic!("Should not receive randomness deferral txn.")
208 }
209 DeferralKey::ConsensusRound { future_round, .. } => {
210 assert!(previous_future_round <= future_round);
211 previous_future_round = future_round;
212 assert!(future_round <= 200);
213 result_count += 1;
214 }
215 }
216 }
217 assert!(result_count > 0);
218 }
219}