Skip to content

Commit 6ab073c

Browse files
committed
Fix incorrect calculation of sidechain wealth
1 parent c0c106a commit 6ab073c

1 file changed

Lines changed: 122 additions & 1 deletion

File tree

lib/state/mod.rs

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ impl State {
467467
.ok_or(AmountOverflowError)?;
468468
}
469469
if let InPoint::Withdrawal { .. } = spent_output.inpoint {
470-
total_withdrawal_stxo_value = total_deposit_stxo_value
470+
total_withdrawal_stxo_value = total_withdrawal_stxo_value
471471
.checked_add(spent_output.output.get_value())
472472
.ok_or(AmountOverflowError)?;
473473
}
@@ -568,3 +568,124 @@ impl Watchable<()> for State {
568568
tokio_stream::wrappers::WatchStream::new(self.tip.watch().clone())
569569
}
570570
}
571+
572+
#[cfg(test)]
573+
mod test {
574+
use crate::{
575+
state::State,
576+
types::{
577+
Address, InPoint, OutPoint, OutPointKey, Output, OutputContent,
578+
SpentOutput,
579+
},
580+
};
581+
582+
fn temp_env_path(test_name: &str) -> anyhow::Result<std::path::PathBuf> {
583+
let mut path = std::env::temp_dir();
584+
let nanos = std::time::SystemTime::now()
585+
.duration_since(std::time::UNIX_EPOCH)?
586+
.as_nanos();
587+
path.push(format!(
588+
"photon-{test_name}-{}-{nanos}",
589+
std::process::id()
590+
));
591+
Ok(path)
592+
}
593+
594+
// open a fresh state-backed env in a unique temp dir
595+
fn temp_env(test_name: &str) -> anyhow::Result<sneed::Env> {
596+
let path = temp_env_path(test_name)?;
597+
std::fs::create_dir_all(&path)?;
598+
let mut opts = heed::EnvOpenOptions::new();
599+
opts.map_size(16 * 1024 * 1024).max_dbs(State::NUM_DBS);
600+
let res = unsafe { sneed::Env::open(&opts, &path) }?;
601+
Ok(res)
602+
}
603+
604+
fn fresh_state(test_name: &str) -> anyhow::Result<(sneed::Env, State)> {
605+
let env = temp_env(test_name)?;
606+
let state = State::new(&env)?;
607+
Ok((env, state))
608+
}
609+
610+
#[test]
611+
fn sidechain_wealth() -> anyhow::Result<()> {
612+
use std::str::FromStr;
613+
614+
use bitcoin::hashes::Hash as _;
615+
616+
let value_output = |sats: u64| Output {
617+
address: Address::ALL_ZEROS,
618+
content: OutputContent::Value(bitcoin::Amount::from_sat(sats)),
619+
};
620+
let (env, state) = fresh_state("sidechain-wealth")?;
621+
{
622+
let mut rwtxn = env.write_txn()?;
623+
624+
// One unspent DEPOSIT UTXO: 50 sats.
625+
let deposit_utxo_op = OutPoint::Deposit(bitcoin::OutPoint {
626+
txid: bitcoin::Txid::from_str(
627+
"0000000000000000000000000000000000000000000000000000000000000001",
628+
)?,
629+
vout: 0,
630+
});
631+
state.utxos.put(
632+
&mut rwtxn,
633+
&OutPointKey::from(&deposit_utxo_op),
634+
&value_output(50),
635+
)?;
636+
637+
// Two spent DEPOSIT STXOs: 100 + 100 sats.
638+
for (i, sats) in [(2u8, 100u64), (3u8, 100u64)] {
639+
let op = OutPoint::Deposit(bitcoin::OutPoint {
640+
txid: bitcoin::Txid::from_byte_array([i; 32]),
641+
vout: 0,
642+
});
643+
let stxo = SpentOutput {
644+
output: value_output(sats),
645+
inpoint: InPoint::Regular {
646+
txid: [i; 32].into(),
647+
vin: 0,
648+
},
649+
};
650+
state
651+
.stxos
652+
.put(&mut rwtxn, &OutPointKey::from(&op), &stxo)?;
653+
}
654+
655+
// Two WITHDRAWAL STXOs: 10 + 10 sats
656+
for (i, sats) in [(4u8, 10u64), (5u8, 10u64)] {
657+
let op = OutPoint::Regular {
658+
txid: [i; 32].into(),
659+
vout: 0,
660+
};
661+
let stxo = SpentOutput {
662+
output: value_output(sats),
663+
inpoint: InPoint::Withdrawal {
664+
m6id: crate::types::M6id(
665+
bitcoin::Txid::from_byte_array([i; 32]),
666+
),
667+
},
668+
};
669+
state
670+
.stxos
671+
.put(&mut rwtxn, &OutPointKey::from(&op), &stxo)?;
672+
}
673+
674+
rwtxn.commit()?;
675+
}
676+
677+
let rotxn = env.read_txn()?;
678+
let sidechain_wealth = state.sidechain_wealth(&rotxn)?;
679+
680+
// Correct value: deposit UTXO 50 + deposit STXOs 200 - withdrawal
681+
// STXOs 20 = 230 sats.
682+
let expected_sidechain_wealth = bitcoin::Amount::from_sat(230);
683+
anyhow::ensure!(
684+
sidechain_wealth == expected_sidechain_wealth,
685+
"Expected sidechain wealth ({}), but computed ({})",
686+
expected_sidechain_wealth,
687+
sidechain_wealth,
688+
);
689+
Ok(())
690+
}
691+
}

0 commit comments

Comments
 (0)