mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
integrate rocksdb into state struct & move the struct to darkfid.rs file
This commit is contained in:
@@ -1,11 +1,118 @@
|
||||
use async_executor::Executor;
|
||||
use async_std::sync::Arc;
|
||||
use easy_parallel::Parallel;
|
||||
use rand::rngs::OsRng;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use drk::service::{ClientProgramOptions, GatewayClient};
|
||||
use drk::Result;
|
||||
use drk::blockchain::{Slab, Rocks};
|
||||
use drk::blockchain::{rocks::columns, Rocks, RocksColumn, Slab, SlabStore};
|
||||
use drk::crypto::{
|
||||
coin::Coin,
|
||||
load_params,
|
||||
merkle::{CommitmentTree, IncrementalWitness},
|
||||
merkle_node::MerkleNode,
|
||||
note::{EncryptedNote, Note},
|
||||
nullifier::Nullifier,
|
||||
save_params, setup_mint_prover, setup_spend_prover,
|
||||
};
|
||||
use drk::serial::{deserialize, Decodable};
|
||||
use drk::service::{ClientProgramOptions, GatewayClient, Subscriber};
|
||||
use drk::state::{state_transition, ProgramState, StateUpdate};
|
||||
use drk::{tx, Result};
|
||||
|
||||
use async_executor::Executor;
|
||||
use bellman::groth16;
|
||||
use bls12_381::Bls12;
|
||||
use easy_parallel::Parallel;
|
||||
use ff::Field;
|
||||
use std::path::Path;
|
||||
|
||||
pub struct State {
|
||||
// The entire merkle tree state
|
||||
tree: CommitmentTree<MerkleNode>,
|
||||
// List of all previous and the current merkle roots
|
||||
// This is the hashed value of all the children.
|
||||
merkle_roots: RocksColumn<columns::MerkleRoots>,
|
||||
// Nullifiers prevent double spending
|
||||
nullifiers: RocksColumn<columns::Nullifiers>,
|
||||
// All received coins
|
||||
own_coins: Vec<(Coin, Note, jubjub::Fr, IncrementalWitness<MerkleNode>)>,
|
||||
// Mint verifying key used by ZK
|
||||
mint_pvk: groth16::PreparedVerifyingKey<Bls12>,
|
||||
// Spend verifying key used by ZK
|
||||
spend_pvk: groth16::PreparedVerifyingKey<Bls12>,
|
||||
// Public key of the cashier
|
||||
cashier_public: jubjub::SubgroupPoint,
|
||||
// List of all our secret keys
|
||||
secrets: Vec<jubjub::Fr>,
|
||||
}
|
||||
|
||||
impl ProgramState for State {
|
||||
fn is_valid_cashier_public_key(&self, _public: &jubjub::SubgroupPoint) -> bool {
|
||||
// TODO
|
||||
true
|
||||
}
|
||||
|
||||
fn is_valid_merkle(&self, merkle_root: &MerkleNode) -> bool {
|
||||
self.merkle_roots.key_exist(*merkle_root).expect("couldn't check if the merkle_root valid")
|
||||
}
|
||||
|
||||
fn nullifier_exists(&self, nullifier: &Nullifier) -> bool {
|
||||
self.nullifiers.key_exist(nullifier.repr).expect("couldn't check if nullifier exists")
|
||||
}
|
||||
|
||||
fn mint_pvk(&self) -> &groth16::PreparedVerifyingKey<Bls12> {
|
||||
&self.mint_pvk
|
||||
}
|
||||
|
||||
fn spend_pvk(&self) -> &groth16::PreparedVerifyingKey<Bls12> {
|
||||
&self.spend_pvk
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
fn apply(&mut self, update: StateUpdate) -> Result<()> {
|
||||
// Extend our list of nullifiers with the ones from the update
|
||||
for nullifier in update.nullifiers {
|
||||
self.nullifiers.put(nullifier, vec![] as Vec<u8>)?;
|
||||
}
|
||||
|
||||
// Update merkle tree and witnesses
|
||||
for (coin, enc_note) in update.coins.into_iter().zip(update.enc_notes.into_iter()) {
|
||||
// Add the new coins to the merkle tree
|
||||
let node = MerkleNode::from_coin(&coin);
|
||||
self.tree.append(node).expect("Append to merkle tree");
|
||||
|
||||
// Keep track of all merkle roots that have existed
|
||||
self.merkle_roots.put(self.tree.root(), vec![] as Vec<u8>)?;
|
||||
|
||||
// own coins is sql
|
||||
// Also update all the coin witnesses
|
||||
for (_, _, _, witness) in self.own_coins.iter_mut() {
|
||||
witness.append(node).expect("append to witness");
|
||||
}
|
||||
|
||||
if let Some((note, secret)) = self.try_decrypt_note(enc_note) {
|
||||
// We need to keep track of the witness for this coin.
|
||||
// This allows us to prove inclusion of the coin in the merkle tree with ZK.
|
||||
// Just as we update the merkle tree with every new coin, so we do the same with
|
||||
// the witness.
|
||||
|
||||
// Derive the current witness from the current tree.
|
||||
// This is done right after we add our coin to the tree (but before any other
|
||||
// coins are added)
|
||||
|
||||
// Make a new witness for this coin
|
||||
let witness = IncrementalWitness::from_tree(&self.tree);
|
||||
self.own_coins.push((coin, note, secret, witness));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// sql
|
||||
fn try_decrypt_note(&self, _ciphertext: EncryptedNote) -> Option<(Note, jubjub::Fr)> {
|
||||
// TODO
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_addr(address: Option<SocketAddr>, default: SocketAddr) -> SocketAddr {
|
||||
match address {
|
||||
@@ -14,6 +121,25 @@ fn setup_addr(address: Option<SocketAddr>, default: SocketAddr) -> SocketAddr {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn subscribe(
|
||||
mut subscriber: Subscriber,
|
||||
slabstore: Arc<SlabStore>,
|
||||
mut state: State,
|
||||
) -> Result<()> {
|
||||
loop {
|
||||
let slab_data: Vec<u8>;
|
||||
slab_data = subscriber.fetch().await?;
|
||||
|
||||
let slab: Slab = deserialize(&slab_data)?;
|
||||
let tx = tx::Transaction::decode(&slab.get_payload()[..])?;
|
||||
|
||||
let update = state_transition(&state, tx)?;
|
||||
state.apply(update)?;
|
||||
|
||||
slabstore.put(slab_data)?;
|
||||
}
|
||||
}
|
||||
|
||||
async fn start(executor: Arc<Executor<'_>>, options: ClientProgramOptions) -> Result<()> {
|
||||
let connect_addr: SocketAddr = setup_addr(options.connect_addr, "127.0.0.1:3333".parse()?);
|
||||
let sub_addr: SocketAddr = setup_addr(options.sub_addr, "127.0.0.1:4444".parse()?);
|
||||
@@ -21,21 +147,54 @@ async fn start(executor: Arc<Executor<'_>>, options: ClientProgramOptions) -> Re
|
||||
|
||||
let rocks = Rocks::new(database_path)?;
|
||||
|
||||
let slabstore = RocksColumn::<columns::Slabs>::new(rocks.clone());
|
||||
// create gateway client
|
||||
let mut client = GatewayClient::new(connect_addr, rocks)?;
|
||||
let mut client = GatewayClient::new(connect_addr, slabstore)?;
|
||||
|
||||
// start gateway client
|
||||
client.start().await?;
|
||||
|
||||
// start subscribe to gateway publisher
|
||||
//
|
||||
// Auto create trusted ceremony parameters if they don't exist
|
||||
if !Path::new("mint.params").exists() {
|
||||
let params = setup_mint_prover();
|
||||
save_params("mint.params", ¶ms)?;
|
||||
}
|
||||
if !Path::new("spend.params").exists() {
|
||||
let params = setup_spend_prover();
|
||||
save_params("spend.params", ¶ms)?;
|
||||
}
|
||||
|
||||
// Load trusted setup parameters
|
||||
let (_mint_params, mint_pvk) = load_params("mint.params")?;
|
||||
let (_spend_params, spend_pvk) = load_params("spend.params")?;
|
||||
|
||||
let cashier_secret = jubjub::Fr::random(&mut OsRng);
|
||||
let cashier_public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * cashier_secret;
|
||||
|
||||
// wallet secret key
|
||||
let secret = jubjub::Fr::random(&mut OsRng);
|
||||
// wallet public key
|
||||
let _public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
|
||||
|
||||
let merkle_roots = RocksColumn::<columns::MerkleRoots>::new(rocks.clone());
|
||||
let nullifiers = RocksColumn::<columns::Nullifiers>::new(rocks);
|
||||
|
||||
let state = State {
|
||||
tree: CommitmentTree::empty(),
|
||||
merkle_roots,
|
||||
nullifiers,
|
||||
own_coins: vec![],
|
||||
mint_pvk,
|
||||
spend_pvk,
|
||||
cashier_public,
|
||||
secrets: vec![secret.clone()],
|
||||
};
|
||||
|
||||
// start subscribe to gateway publisher
|
||||
let subscriber = GatewayClient::start_subscriber(sub_addr).await?;
|
||||
let slabstore = client.get_slabstore();
|
||||
let subscribe_task = executor.spawn(GatewayClient::subscribe(subscriber, slabstore));
|
||||
|
||||
// TEST
|
||||
let _slab = Slab::new("testcoin".to_string(), vec![0, 0, 0, 0]);
|
||||
//client.put_slab(_slab).await?;
|
||||
let subscribe_task = executor.spawn(subscribe(subscriber, slabstore, state));
|
||||
|
||||
subscribe_task.cancel().await;
|
||||
Ok(())
|
||||
@@ -84,62 +243,63 @@ fn main() -> Result<()> {
|
||||
result
|
||||
}
|
||||
|
||||
// $ cargo test --bin darkfid
|
||||
// run 10 clients simultaneously
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
#[test]
|
||||
fn test_darkfid_client() {
|
||||
use std::path::Path;
|
||||
|
||||
use drk::blockchain::{Rocks, Slab};
|
||||
use drk::service::GatewayClient;
|
||||
|
||||
use log::*;
|
||||
use rand::Rng;
|
||||
use simplelog::*;
|
||||
|
||||
let logger_config = ConfigBuilder::new().set_time_format_str("%T%.6f").build();
|
||||
|
||||
CombinedLogger::init(vec![
|
||||
TermLogger::new(LevelFilter::Debug, logger_config, TerminalMode::Mixed).unwrap(),
|
||||
WriteLogger::new(
|
||||
LevelFilter::Debug,
|
||||
Config::default(),
|
||||
std::fs::File::create(Path::new("/tmp/dar.log")).unwrap(),
|
||||
),
|
||||
])
|
||||
.unwrap();
|
||||
|
||||
let mut thread_pools: Vec<std::thread::JoinHandle<()>> = vec![];
|
||||
|
||||
for _ in 0..10 {
|
||||
let thread = std::thread::spawn(|| {
|
||||
smol::future::block_on(async move {
|
||||
let mut rng = rand::thread_rng();
|
||||
let rnd: u32 = rng.gen();
|
||||
|
||||
let path_str = format!("database_{}.db", rnd);
|
||||
let database_path = Path::new(path_str.as_str());
|
||||
let rocks = Rocks::new(database_path.clone()).unwrap();
|
||||
|
||||
// create new client and use different slabstore
|
||||
let mut client =
|
||||
GatewayClient::new("127.0.0.1:3333".parse().unwrap(), rocks).unwrap();
|
||||
|
||||
// start client
|
||||
client.start().await.unwrap();
|
||||
|
||||
// sending slab
|
||||
let _slab = Slab::new("testcoin".to_string(), rnd.to_le_bytes().to_vec());
|
||||
client.put_slab(_slab).await.unwrap();
|
||||
})
|
||||
});
|
||||
thread_pools.push(thread);
|
||||
}
|
||||
for t in thread_pools {
|
||||
t.join().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
//// $ cargo test --bin darkfid
|
||||
//// run 10 clients simultaneously
|
||||
//#[cfg(test)]
|
||||
//mod test {
|
||||
//
|
||||
// #[test]
|
||||
// fn test_darkfid_client() {
|
||||
// use std::path::Path;
|
||||
//
|
||||
// use drk::blockchain::{Rocks, Slab};
|
||||
// use drk::service::GatewayClient;
|
||||
//
|
||||
// use log::*;
|
||||
// use rand::Rng;
|
||||
// use simplelog::*;
|
||||
//
|
||||
// let logger_config = ConfigBuilder::new().set_time_format_str("%T%.6f").build();
|
||||
//
|
||||
// CombinedLogger::init(vec![
|
||||
// TermLogger::new(LevelFilter::Debug, logger_config, TerminalMode::Mixed).unwrap(),
|
||||
// WriteLogger::new(
|
||||
// LevelFilter::Debug,
|
||||
// Config::default(),
|
||||
// std::fs::File::create(Path::new("/tmp/dar.log")).unwrap(),
|
||||
// ),
|
||||
// ])
|
||||
// .unwrap();
|
||||
//
|
||||
// let mut thread_pools: Vec<std::thread::JoinHandle<()>> = vec![];
|
||||
//
|
||||
// for _ in 0..10 {
|
||||
// let thread = std::thread::spawn(|| {
|
||||
// smol::future::block_on(async move {
|
||||
// let mut rng = rand::thread_rng();
|
||||
// let rnd: u32 = rng.gen();
|
||||
//
|
||||
// let path_str = format!("database_{}.db", rnd);
|
||||
// let database_path = Path::new(path_str.as_str());
|
||||
// let rocks = Rocks::new(database_path.clone()).unwrap();
|
||||
//
|
||||
// // create new client and use different slabstore
|
||||
// let mut client =
|
||||
// GatewayClient::new("127.0.0.1:3333".parse().unwrap(), rocks).unwrap();
|
||||
//
|
||||
// // start client
|
||||
// client.start().await.unwrap();
|
||||
//
|
||||
// // sending slab
|
||||
// let _slab = Slab::new("testcoin".to_string(), rnd.to_le_bytes().to_vec());
|
||||
// client.put_slab(_slab).await.unwrap();
|
||||
// })
|
||||
// });
|
||||
// thread_pools.push(thread);
|
||||
// }
|
||||
// for t in thread_pools {
|
||||
// t.join().unwrap();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
Reference in New Issue
Block a user