mirror of
https://github.com/serai-dex/serai.git
synced 2024-11-17 09:27:36 +00:00
This commit is contained in:
parent
00d61286b1
commit
577fe99a08
2 changed files with 35 additions and 10 deletions
|
@ -326,7 +326,7 @@ impl Rpc {
|
||||||
Ok(distributions.result.distributions.swap_remove(0).distribution)
|
Ok(distributions.result.distributions.swap_remove(0).distribution)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_outputs(
|
pub async fn get_unlocked_outputs(
|
||||||
&self,
|
&self,
|
||||||
indexes: &[u64],
|
indexes: &[u64],
|
||||||
height: usize,
|
height: usize,
|
||||||
|
@ -370,6 +370,7 @@ impl Rpc {
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// TODO: Support time based lock times. These shouldn't be needed, and it may be painful to
|
// TODO: Support time based lock times. These shouldn't be needed, and it may be painful to
|
||||||
// get the median time for the given height, yet we do need to in order to be complete
|
// get the median time for the given height, yet we do need to in order to be complete
|
||||||
outs
|
outs
|
||||||
|
|
|
@ -26,17 +26,20 @@ lazy_static! {
|
||||||
static ref DISTRIBUTION: Mutex<Vec<u64>> = Mutex::new(Vec::with_capacity(3000000));
|
static ref DISTRIBUTION: Mutex<Vec<u64>> = Mutex::new(Vec::with_capacity(3000000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
async fn select_n<R: RngCore + CryptoRng>(
|
async fn select_n<R: RngCore + CryptoRng>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
rpc: &Rpc,
|
rpc: &Rpc,
|
||||||
height: usize,
|
height: usize,
|
||||||
high: u64,
|
high: u64,
|
||||||
per_second: f64,
|
per_second: f64,
|
||||||
|
real: &[u64],
|
||||||
used: &mut HashSet<u64>,
|
used: &mut HashSet<u64>,
|
||||||
count: usize,
|
count: usize,
|
||||||
) -> Result<Vec<(u64, [EdwardsPoint; 2])>, RpcError> {
|
) -> Result<Vec<(u64, [EdwardsPoint; 2])>, RpcError> {
|
||||||
let mut iters = 0;
|
let mut iters = 0;
|
||||||
let mut confirmed = Vec::with_capacity(count);
|
let mut confirmed = Vec::with_capacity(count);
|
||||||
|
// Retries on failure. Retries are obvious as decoys, yet should be minimal
|
||||||
while confirmed.len() != count {
|
while confirmed.len() != count {
|
||||||
let remaining = count - confirmed.len();
|
let remaining = count - confirmed.len();
|
||||||
let mut candidates = Vec::with_capacity(remaining);
|
let mut candidates = Vec::with_capacity(remaining);
|
||||||
|
@ -73,9 +76,28 @@ async fn select_n<R: RngCore + CryptoRng>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let outputs = rpc.get_outputs(&candidates, height).await?;
|
// If this is the first time we're requesting these outputs, include the real one as well
|
||||||
for i in 0 .. outputs.len() {
|
// Prevents the node we're connected to from having a list of known decoys and then seeing a
|
||||||
if let Some(output) = outputs[i] {
|
// TX which uses all of them, with one additional output (the true spend)
|
||||||
|
let mut real_indexes = HashSet::with_capacity(real.len());
|
||||||
|
if confirmed.is_empty() {
|
||||||
|
for real in real {
|
||||||
|
candidates.push(*real);
|
||||||
|
}
|
||||||
|
// Sort candidates so the real spends aren't the ones at the end
|
||||||
|
candidates.sort();
|
||||||
|
for real in real {
|
||||||
|
real_indexes.insert(candidates.binary_search(real).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, output) in rpc.get_unlocked_outputs(&candidates, height).await?.iter_mut().enumerate() {
|
||||||
|
// Don't include the real spend as a decoy, despite requesting it
|
||||||
|
if real_indexes.contains(&i) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(output) = output.take() {
|
||||||
confirmed.push((candidates[i], output));
|
confirmed.push((candidates[i], output));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,12 +137,11 @@ impl Decoys {
|
||||||
let decoy_count = ring_len - 1;
|
let decoy_count = ring_len - 1;
|
||||||
|
|
||||||
// Convert the inputs in question to the raw output data
|
// Convert the inputs in question to the raw output data
|
||||||
|
let mut real = Vec::with_capacity(inputs.len());
|
||||||
let mut outputs = Vec::with_capacity(inputs.len());
|
let mut outputs = Vec::with_capacity(inputs.len());
|
||||||
for input in inputs {
|
for input in inputs {
|
||||||
outputs.push((
|
real.push(rpc.get_o_indexes(input.tx).await?[usize::from(input.o)]);
|
||||||
rpc.get_o_indexes(input.tx).await?[usize::from(input.o)],
|
outputs.push((real[real.len() - 1], [input.key, input.commitment.calculate()]));
|
||||||
[input.key, input.commitment.calculate()],
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let distribution_len = {
|
let distribution_len = {
|
||||||
|
@ -162,7 +183,9 @@ impl Decoys {
|
||||||
// We should almost never naturally generate an insane transaction, hence why this doesn't
|
// We should almost never naturally generate an insane transaction, hence why this doesn't
|
||||||
// bother with an overage
|
// bother with an overage
|
||||||
let mut decoys =
|
let mut decoys =
|
||||||
select_n(rng, rpc, height, high, per_second, &mut used, inputs.len() * decoy_count).await?;
|
select_n(rng, rpc, height, high, per_second, &real, &mut used, inputs.len() * decoy_count)
|
||||||
|
.await?;
|
||||||
|
real.zeroize();
|
||||||
|
|
||||||
let mut res = Vec::with_capacity(inputs.len());
|
let mut res = Vec::with_capacity(inputs.len());
|
||||||
for o in outputs {
|
for o in outputs {
|
||||||
|
@ -199,7 +222,8 @@ impl Decoys {
|
||||||
|
|
||||||
// Select new outputs until we have a full sized ring again
|
// Select new outputs until we have a full sized ring again
|
||||||
ring.extend(
|
ring.extend(
|
||||||
select_n(rng, rpc, height, high, per_second, &mut used, ring_len - ring.len()).await?,
|
select_n(rng, rpc, height, high, per_second, &[], &mut used, ring_len - ring.len())
|
||||||
|
.await?,
|
||||||
);
|
);
|
||||||
ring.sort_by(|a, b| a.0.cmp(&b.0));
|
ring.sort_by(|a, b| a.0.cmp(&b.0));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue