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