dpp/withdrawal/
core_dust_threshold.rs1use dashcore::Script;
5
6const SPEND_INPUT_SIZE: u64 = 148;
10
11const TX_OUT_VALUE_SIZE: u64 = 8;
13
14pub fn core_dust_threshold_duffs(output_script: &Script, dust_relay_fee_per_kb: u64) -> u64 {
23 if output_script.is_op_return() {
24 return 0;
25 }
26
27 let script_len = output_script.len() as u64;
28 let serialized_size =
29 SPEND_INPUT_SIZE + TX_OUT_VALUE_SIZE + var_int_size(script_len) + script_len;
30
31 let fee = dust_relay_fee_per_kb.saturating_mul(serialized_size) / 1000;
33 if fee == 0 && dust_relay_fee_per_kb > 0 {
34 1
35 } else {
36 fee
37 }
38}
39
40fn var_int_size(value: u64) -> u64 {
42 match value {
43 0..=0xFC => 1,
44 0xFD..=0xFFFF => 3,
45 0x1_0000..=0xFFFF_FFFF => 5,
46 _ => 9,
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 use dashcore::ScriptBuf;
54
55 const CORE_DEFAULT_DUST_RELAY_FEE_PER_KB: u64 = 3000;
56
57 fn p2pkh() -> ScriptBuf {
58 let mut bytes = vec![0x76, 0xa9, 0x14];
59 bytes.extend_from_slice(&[0x11; 20]);
60 bytes.extend_from_slice(&[0x88, 0xac]);
61 ScriptBuf::from_bytes(bytes)
62 }
63
64 fn p2sh() -> ScriptBuf {
65 let mut bytes = vec![0xa9, 0x14];
66 bytes.extend_from_slice(&[0x22; 20]);
67 bytes.push(0x87);
68 ScriptBuf::from_bytes(bytes)
69 }
70
71 #[test]
72 fn should_match_core_default_thresholds() {
73 assert_eq!(
74 core_dust_threshold_duffs(&p2pkh(), CORE_DEFAULT_DUST_RELAY_FEE_PER_KB),
75 546
76 );
77 assert_eq!(
78 core_dust_threshold_duffs(&p2sh(), CORE_DEFAULT_DUST_RELAY_FEE_PER_KB),
79 540
80 );
81 }
82
83 #[test]
84 fn should_agree_with_dashcore_dust_value_at_the_default_rate() {
85 for script in [p2pkh(), p2sh()] {
86 assert_eq!(
87 core_dust_threshold_duffs(&script, CORE_DEFAULT_DUST_RELAY_FEE_PER_KB),
88 script.dust_value().to_sat()
89 );
90 }
91 }
92
93 #[test]
94 fn should_never_treat_unspendable_outputs_as_dust() {
95 let op_return = ScriptBuf::from_bytes(vec![0x6a, 0x03, 0x01, 0x02, 0x03]);
96 assert_eq!(
97 core_dust_threshold_duffs(&op_return, CORE_DEFAULT_DUST_RELAY_FEE_PER_KB),
98 0
99 );
100 }
101
102 #[test]
103 fn should_scale_with_the_relay_fee_and_floor_a_positive_rate_at_one_duff() {
104 assert_eq!(core_dust_threshold_duffs(&p2pkh(), 0), 0);
105 assert_eq!(core_dust_threshold_duffs(&p2pkh(), 1), 1);
106 assert_eq!(core_dust_threshold_duffs(&p2pkh(), 6000), 1092);
107 }
108}