Byron Hambly 796863359f
upgrade secp256kfun (#1466)
* ci: add cargo check on rust stable

* refactor: upgrade secp256kfun and fix resulting issues

* build(deps): update sigma_fun and ecdsa_fun to a52142cf7f

 #1520
 #1521

* chore: fix clippy issue

* update to 91112f80b24

* bump to 294de1721add

* chore(deps): remove spectral

spectral fails to compile on rust stable 1.76 due to dep on deprecated
rustc-serialize

* secp256kfun: update to 7da9d277 and set rev in manifest

* update to 6fdc5d8

* switch to crates.io versions of ecdsa_fun and sigma_fun

* ci: update toolchain to 1.74 and fix draft action

* clippy fixes

---------

Co-authored-by: binarybaron <86064887+binarybaron@users.noreply.github.com>
2024-05-27 11:03:20 +02:00

93 lines
3.2 KiB
Rust

use anyhow::{Context, Result};
use monero::consensus::encode::VarInt;
use monero::cryptonote::hash::Hashable;
use monero_rpc::monerod;
use monero_rpc::monerod::{GetBlockResponse, MonerodRpc as _};
use rand::Rng;
pub struct Wallet {
client: monerod::Client,
}
impl Wallet {
/// Chooses 10 random key offsets for use within a new confidential
/// transactions.
///
/// Choosing these offsets randomly is not ideal for privacy, instead they
/// should be chosen in a way that mimics a real spending pattern as much as
/// possible.
pub async fn choose_ten_random_key_offsets(&self) -> Result<[VarInt; 10]> {
let latest_block = self.client.get_block_count().await?;
let latest_spendable_block = latest_block.count - 10;
let block: GetBlockResponse = self.client.get_block(latest_spendable_block).await?;
let tx_hash = block
.blob
.tx_hashes
.first()
.copied()
.unwrap_or_else(|| block.blob.miner_tx.hash());
let indices = self.client.get_o_indexes(tx_hash).await?;
let last_index = indices
.o_indexes
.into_iter()
.max()
.context("Expected at least one output index")?;
let oldest_index = last_index - (last_index / 100) * 40; // oldest index must be within last 40% TODO: CONFIRM THIS
let mut rng = rand::thread_rng();
Ok([
VarInt(rng.gen_range(oldest_index, last_index)),
VarInt(rng.gen_range(oldest_index, last_index)),
VarInt(rng.gen_range(oldest_index, last_index)),
VarInt(rng.gen_range(oldest_index, last_index)),
VarInt(rng.gen_range(oldest_index, last_index)),
VarInt(rng.gen_range(oldest_index, last_index)),
VarInt(rng.gen_range(oldest_index, last_index)),
VarInt(rng.gen_range(oldest_index, last_index)),
VarInt(rng.gen_range(oldest_index, last_index)),
VarInt(rng.gen_range(oldest_index, last_index)),
])
}
}
#[cfg(test)]
mod tests {
use super::*;
use monero_harness::image::Monerod;
use monero_rpc::monerod::{Client, GetOutputsOut};
use testcontainers::clients::Cli;
#[tokio::test]
async fn get_outs_for_key_offsets() {
let cli = Cli::default();
let container = cli.run(Monerod);
let rpc_client = Client::localhost(container.get_host_port_ipv4(18081)).unwrap();
rpc_client.generateblocks(150, "498AVruCDWgP9Az9LjMm89VWjrBrSZ2W2K3HFBiyzzrRjUJWUcCVxvY1iitfuKoek2FdX6MKGAD9Qb1G1P8QgR5jPmmt3Vj".to_owned()).await.unwrap();
let wallet = Wallet {
client: rpc_client.clone(),
};
let key_offsets = wallet.choose_ten_random_key_offsets().await.unwrap();
let result = rpc_client
.get_outs(
key_offsets
.iter()
.cloned()
.map(|varint| GetOutputsOut {
amount: 0,
index: varint.0,
})
.collect(),
)
.await
.unwrap();
assert_eq!(result.outs.len(), 10);
}
}