Skip to content

Commit 77fa04d

Browse files
authored
Merge pull request #51 from rustaceanrob/9-9-mult-acc
Add a multiplication-based aggregate
2 parents 1f19c4b + 33a9241 commit 77fa04d

File tree

2 files changed

+105
-1
lines changed

2 files changed

+105
-1
lines changed

accumulator/src/lib.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,63 @@ impl Default for Accumulator {
127127
}
128128
}
129129

130+
const VOUT_MAX: usize = 16_000;
131+
132+
/// An alternative accumulator than that of the original SwiftSync write-up, intended to remove the
133+
/// hashes required to update elements in the set.
134+
#[derive(Debug)]
135+
pub struct MultAggregate {
136+
memo_table: [[[u8; 16]; 2]; VOUT_MAX],
137+
internal: u128,
138+
}
139+
140+
impl MultAggregate {
141+
pub fn new() -> Self {
142+
let mut memo_table = [[[0u8; 16]; 2]; VOUT_MAX];
143+
for (vout, arr) in memo_table.iter_mut().enumerate() {
144+
let bytes = sha256t::hash::<SwiftSyncTag>(&vout.to_le_bytes()).to_byte_array();
145+
let (left, right) = split_in_half(bytes);
146+
*arr = [left, right];
147+
}
148+
Self {
149+
memo_table,
150+
internal: 0,
151+
}
152+
}
153+
154+
fn compute_salted_value(&self, outpoint: OutPoint) -> u128 {
155+
let branches = self.memo_table[outpoint.vout as usize];
156+
let left = branches[0];
157+
let right = branches[1];
158+
let txid_bytes = outpoint.txid.to_byte_array();
159+
let (tx_left, tx_right) = split_in_half(txid_bytes);
160+
let lhs = u128::from_le_bytes(left).wrapping_mul(u128::from_le_bytes(tx_left));
161+
let rhs = u128::from_le_bytes(right).wrapping_mul(u128::from_le_bytes(tx_right));
162+
lhs.wrapping_add(rhs)
163+
}
164+
165+
/// Add an outpoint to the set
166+
pub fn add(&mut self, outpoint: OutPoint) {
167+
let salted_val = self.compute_salted_value(outpoint);
168+
self.internal = self.internal.wrapping_add(salted_val);
169+
}
170+
171+
/// Remove an outpoint from the set
172+
pub fn spend(&mut self, outpoint: OutPoint) {
173+
let salted_val = self.compute_salted_value(outpoint);
174+
self.internal = self.internal.wrapping_sub(salted_val);
175+
}
176+
177+
pub fn is_zero(&self) -> bool {
178+
self.internal.eq(&0)
179+
}
180+
}
181+
182+
impl Default for MultAggregate {
183+
fn default() -> Self {
184+
Self::new()
185+
}
186+
}
130187
#[cfg(test)]
131188
mod tests {
132189
use bitcoin::{
@@ -264,4 +321,25 @@ mod tests {
264321
acc.update(AccumulatorUpdate::Spent(hash_one));
265322
assert!(acc.is_zero());
266323
}
324+
325+
#[test]
326+
fn test_mult_agg_is_zero() {
327+
let mut acc = MultAggregate::default();
328+
let [outpoint_one, outpoint_two, outpoint_three, outpoint_four, outpoint_five] =
329+
make_five_outpoint();
330+
// Add the members
331+
acc.add(outpoint_one);
332+
acc.add(outpoint_two);
333+
acc.add(outpoint_five);
334+
acc.add(outpoint_four);
335+
acc.add(outpoint_three);
336+
assert!(!acc.is_zero());
337+
// Take away the members
338+
acc.spend(outpoint_two);
339+
acc.spend(outpoint_five);
340+
acc.spend(outpoint_three);
341+
acc.spend(outpoint_four);
342+
acc.spend(outpoint_one);
343+
assert!(acc.is_zero());
344+
}
267345
}

accumulator/tests/test.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use accumulator::Accumulator;
1+
use accumulator::{Accumulator, MultAggregate};
22
use bitcoin::{OutPoint, Txid};
33
use rusqlite::Connection;
44

@@ -29,3 +29,29 @@ fn test_static_utxo_set() {
2929
}
3030
assert!(acc.is_zero());
3131
}
32+
33+
#[test]
34+
fn test_mult_agg() {
35+
let mut acc = MultAggregate::new();
36+
let conn = Connection::open("../contrib/data/signet_outpoints.sqlite").unwrap();
37+
let mut stmt = conn.prepare(SELECT_STMT).unwrap();
38+
let mut rows = stmt.query([]).unwrap();
39+
while let Some(row) = rows.next().unwrap() {
40+
let txid: String = row.get(0).unwrap();
41+
let vout: u32 = row.get(1).unwrap();
42+
let txid = txid.parse::<Txid>().unwrap();
43+
let outpoint = OutPoint { txid, vout };
44+
acc.spend(outpoint);
45+
}
46+
assert!(!acc.is_zero());
47+
let mut stmt = conn.prepare(SELECT_STMT).unwrap();
48+
let mut rows = stmt.query([]).unwrap();
49+
while let Some(row) = rows.next().unwrap() {
50+
let txid: String = row.get(0).unwrap();
51+
let vout: u32 = row.get(1).unwrap();
52+
let txid = txid.parse::<Txid>().unwrap();
53+
let outpoint = OutPoint { txid, vout };
54+
acc.add(outpoint);
55+
}
56+
assert!(acc.is_zero());
57+
}

0 commit comments

Comments
 (0)