Cache output distribution

Also moves to the expected sanity median
This commit is contained in:
Luke Parker 2022-06-20 23:00:49 -04:00
parent 9d817a00b2
commit f10bd5feee
No known key found for this signature in database
GPG key ID: F9F1386DB1E119B6
2 changed files with 19 additions and 11 deletions

View file

@ -233,7 +233,8 @@ impl Rpc {
Ok(indexes.o_indexes)
}
pub async fn get_output_distribution(&self, height: usize) -> Result<Vec<u64>, RpcError> {
// from and to are inclusive
pub async fn get_output_distribution(&self, from: usize, to: usize) -> Result<Vec<u64>, RpcError> {
#[allow(dead_code)]
#[derive(Deserialize, Debug)]
pub struct Distribution {
@ -252,7 +253,8 @@ impl Rpc {
"binary": false,
"amounts": [0],
"cumulative": true,
"to_height": height
"from_height": from,
"to_height": to
}
}))).await?;

View file

@ -1,4 +1,4 @@
use std::collections::HashSet;
use std::{sync::Mutex, collections::HashSet};
use lazy_static::lazy_static;
@ -20,13 +20,14 @@ const DECOYS: usize = RING_LEN - 1;
lazy_static! {
static ref GAMMA: Gamma<f64> = Gamma::new(19.28, 1.0 / 1.61).unwrap();
static ref DISTRIBUTION: Mutex<Vec<u64>> = Mutex::new(vec![]);
}
async fn select_n<R: RngCore + CryptoRng>(
rng: &mut R,
rpc: &Rpc,
height: usize,
distribution: &[u64],
distribution: &Vec<u64>,
high: u64,
per_second: f64,
used: &mut HashSet<u64>,
@ -107,6 +108,8 @@ impl Decoys {
height: usize,
inputs: &[SpendableOutput]
) -> Result<Vec<Decoys>, RpcError> {
let mut distribution = DISTRIBUTION.lock().unwrap();
// Convert the inputs in question to the raw output data
let mut outputs = Vec::with_capacity(inputs.len());
for input in inputs {
@ -116,7 +119,14 @@ impl Decoys {
));
}
let distribution = rpc.get_output_distribution(height).await?;
if distribution.len() <= height {
let from = distribution.len();
distribution.extend(rpc.get_output_distribution(from, height).await?);
}
// If asked to use an older height than previously asked, truncate to ensure accuracy
// Should never happen, yet risks desyncing if it did
distribution.truncate(height + 1); // height is inclusive, and 0 is a valid height
let high = distribution[distribution.len() - 1];
let per_second = {
let blocks = distribution.len().min(BLOCKS_PER_YEAR);
@ -129,8 +139,7 @@ impl Decoys {
used.insert(o.0);
}
// Panic if not enough decoys are available
// TODO: Simply create a TX with less than the target amount, or at least return an error
// TODO: Simply create a TX with less than the target amount
if (high - MATURITY) < u64::try_from(inputs.len() * RING_LEN).unwrap() {
Err(RpcError::InternalError("not enough decoy candidates".to_string()))?;
}
@ -166,10 +175,7 @@ impl Decoys {
// small chains
if high > 500 {
// Make sure the TX passes the sanity check that the median output is within the last 40%
// This actually checks the median is within the last third, a slightly more aggressive
// boundary, as the height used in this calculation will be slightly under the height this
// is sanity checked against
let target_median = high * 2 / 3;
let target_median = high * 3 / 5;
while ring[RING_LEN / 2].0 < target_median {
// If it's not, update the bottom half with new values to ensure the median only moves up
for removed in ring.drain(0 .. (RING_LEN / 2)).collect::<Vec<_>>() {