1use serde::Deserialize;
2
3use crate::prelude::*;
4use core::cmp::min;
5use core::fmt::{self, Debug, Formatter};
6
7#[derive(Clone)]
12pub struct VelocityControl {
13 pub start_sec: u64,
15 pub bucket_interval: u32,
17 pub buckets: Vec<u64>,
19 pub limit: u64,
21}
22
23impl Debug for VelocityControl {
24 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
25 f.debug_struct("VelocityControl")
26 .field("start_sec", &self.start_sec)
27 .field("bucket_interval", &self.bucket_interval)
28 .field("buckets", &format_args!("{:?}", self.buckets))
29 .field("limit", &self.limit)
30 .finish()
31 }
32}
33
34#[derive(Clone, Copy, Debug, Deserialize)]
36pub enum VelocityControlIntervalType {
37 Hourly,
39 Daily,
41 Unlimited,
43}
44
45#[derive(Clone, Copy, Debug, Deserialize)]
47pub struct VelocityControlSpec {
48 pub limit_msat: u64,
50 pub interval_type: VelocityControlIntervalType,
52}
53
54impl VelocityControlSpec {
55 pub const UNLIMITED: VelocityControlSpec = VelocityControlSpec {
57 limit_msat: 0,
58 interval_type: VelocityControlIntervalType::Unlimited,
59 };
60}
61
62impl VelocityControl {
63 pub fn new_with_intervals(limit_msat: u64, bucket_interval: u32, num_buckets: usize) -> Self {
69 assert!(bucket_interval > 0 && num_buckets > 0);
70 let mut buckets = Vec::new();
71 buckets.resize(num_buckets, 0);
72 VelocityControl { start_sec: 0, bucket_interval, buckets, limit: limit_msat }
73 }
74
75 pub fn new_unlimited(bucket_interval: u32, num_buckets: usize) -> Self {
77 assert!(bucket_interval > 0 && num_buckets > 0);
78 let mut buckets = Vec::new();
79 buckets.resize(num_buckets, 0);
80 VelocityControl { start_sec: 0, bucket_interval, buckets, limit: u64::MAX }
81 }
82
83 pub fn new(spec: VelocityControlSpec) -> Self {
85 let (limit, bucket_interval, num_buckets) = Self::spec_to_triple(&spec);
86 Self::new_with_intervals(limit, bucket_interval, num_buckets)
87 }
88
89 pub fn spec_matches(&self, spec: &VelocityControlSpec) -> bool {
91 let (limit, bucket_interval, num_buckets) = Self::spec_to_triple(spec);
92 self.limit == limit
93 && self.bucket_interval == bucket_interval
94 && self.buckets.len() == num_buckets
95 }
96
97 pub fn update_spec(&mut self, spec: &VelocityControlSpec) {
100 if !self.spec_matches(spec) {
101 let (limit, bucket_interval, num_buckets) = Self::spec_to_triple(spec);
102 self.limit = limit;
103 self.bucket_interval = bucket_interval;
104 self.buckets = Vec::new();
105 self.buckets.resize(num_buckets, 0);
106 self.start_sec = 0;
107 }
108 }
109
110 fn spec_to_triple(spec: &VelocityControlSpec) -> (u64, u32, usize) {
112 match spec.interval_type {
113 VelocityControlIntervalType::Hourly => (spec.limit_msat, 300, 12),
114 VelocityControlIntervalType::Daily => (spec.limit_msat, 3600, 24),
115 VelocityControlIntervalType::Unlimited => (u64::MAX, 300, 12),
116 }
117 }
118
119 pub fn load_from_state(spec: VelocityControlSpec, state: (u64, Vec<u64>)) -> Self {
121 let control = Self::new(spec);
122 control.with_state(state)
123 }
124
125 fn with_state(mut self, state: (u64, Vec<u64>)) -> VelocityControl {
126 self.start_sec = state.0;
127 self.buckets = state.1;
128 self
129 }
130
131 pub fn get_state(&self) -> (u64, Vec<u64>) {
133 (self.start_sec, self.buckets.clone())
134 }
135
136 pub fn is_unlimited(&self) -> bool {
138 self.limit == u64::MAX
139 }
140
141 pub fn insert(&mut self, current_sec: u64, velocity_msat: u64) -> bool {
145 let nshift = (current_sec - self.start_sec) / self.bucket_interval as u64;
146 let len = self.buckets.len();
147 let nshift = min(len, nshift as usize);
148 self.buckets.resize(len - nshift, 0);
149 for _ in 0..nshift {
150 self.buckets.insert(0, 0);
151 }
152 self.start_sec = current_sec - (current_sec % self.bucket_interval as u64);
153 let current_velocity = self.velocity();
154 if current_velocity.saturating_add(velocity_msat) > self.limit {
155 false
156 } else {
157 self.buckets[0] = self.buckets[0].saturating_add(velocity_msat);
158 true
159 }
160 }
161
162 pub fn clear(&mut self) {
164 for bucket in self.buckets.iter_mut() {
165 *bucket = 0;
166 }
167 }
168
169 pub fn velocity(&self) -> u64 {
173 let mut sum = 0u64;
174 for bucket in self.buckets.iter() {
175 sum = sum.saturating_add(*bucket)
176 }
177 sum
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use crate::util::velocity::VelocityControl;
184
185 #[test]
186 fn test_velocity() {
187 let mut c = VelocityControl::new_with_intervals(100, 10, 4);
188 assert_eq!(c.velocity(), 0);
189 assert!(c.insert(1100, 90));
190 assert_eq!(c.velocity(), 90);
191 assert!(!c.insert(1101, 11));
192 assert_eq!(c.velocity(), 90);
193 assert!(c.insert(1101, 10));
194 assert_eq!(c.velocity(), 100);
195 assert!(!c.insert(1139, 90));
196 assert_eq!(c.velocity(), 100);
197 assert!(c.insert(1140, 90));
198 assert_eq!(c.velocity(), 90);
199 assert!(c.insert(1150, 5));
200 assert_eq!(c.velocity(), 95);
201 assert!(c.insert(1180, 80));
202 assert_eq!(c.velocity(), 85);
203 assert!(c.insert(1190, 1));
204 assert_eq!(c.velocity(), 81);
205 }
206
207 #[test]
208 fn test_unlimited() {
209 let mut c = VelocityControl::new_unlimited(10, 4);
210 assert!(c.insert(0, u64::MAX - 1));
211 assert_eq!(c.velocity(), u64::MAX - 1);
212 assert!(c.insert(0, 1));
213 assert_eq!(c.velocity(), u64::MAX);
214 assert!(c.insert(0, 1));
215 assert_eq!(c.velocity(), u64::MAX);
216 }
217}