Skip to content

Commit

Permalink
New API for fetching server coins
Browse files Browse the repository at this point in the history
  • Loading branch information
Rigidity committed Feb 19, 2024
1 parent 42d317b commit 5705180
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 70 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ clvmr = "0.5.0"
hex = "0.4.3"
hex-literal = "0.4.1"
num-bigint = "0.4.4"
rand = "0.8.5"
thiserror = "1.0.56"
tokio = { version = "1.35.1", features = ["full"] }
native-tls = "0.2.11"
Expand Down
5 changes: 4 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ export class Tls {
}
export class Peer {
static connect(nodeUri: string, networkId: string, tls: Tls): Promise<Peer>
fetchServerCoins(launcherId: Uint8Array, count: number): Promise<Array<ServerCoin>>
fetchServerCoins(launcherId: Uint8Array): Promise<ServerCoinIterator>
}
export class ServerCoinIterator {
next(): Promise<ServerCoin | null>
}
export class Wallet {
static initialSync(peer: Peer, mnemonic: string, aggSigMe: Uint8Array): Promise<Wallet>
Expand Down
3 changes: 2 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -295,10 +295,11 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`)
}

const { Tls, Peer, Wallet, toCoinId, bytesEqual } = nativeBinding
const { Tls, Peer, ServerCoinIterator, Wallet, toCoinId, bytesEqual } = nativeBinding

module.exports.Tls = Tls
module.exports.Peer = Peer
module.exports.ServerCoinIterator = ServerCoinIterator
module.exports.Wallet = Wallet
module.exports.toCoinId = toCoinId
module.exports.bytesEqual = bytesEqual
84 changes: 72 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,24 @@ use std::{str::FromStr, sync::Arc};
use bip39::Mnemonic;
use chia_bls::{SecretKey, Signature};
use chia_client::Peer as RustPeer;
use chia_protocol::{Coin as RustCoin, NodeType, SpendBundle};
use chia_protocol::{Coin as RustCoin, CoinState, NodeType, SpendBundle};
use chia_wallet_sdk::{
connect_peer, create_tls_connector, incremental_sync, load_ssl_cert, sign_spend_bundle,
DerivationStore, MemoryCoinStore, PublicKeyStore, SimpleDerivationStore, SyncConfig,
Condition, DerivationStore, MemoryCoinStore, PublicKeyStore, SimpleDerivationStore, SyncConfig,
};
use clvmr::Allocator;
use clvm_traits::{FromClvm, ToNodePtr};
use clvm_utils::tree_hash;
use clvmr::{cost::Cost, Allocator, NodePtr};
use napi::{bindgen_prelude::Uint8Array, Error, Result};
use native_tls::TlsConnector;

mod server_coin;

use server_coin::{
create_server_coin, delete_server_coins, fetch_server_coins, ServerCoin as RustServerCoin,
create_server_coin, delete_server_coins, morph_launcher_id, urls_from_conditions,
ServerCoin as RustServerCoin,
};
use tokio::sync::mpsc;
use tokio::sync::{mpsc, Mutex};

#[macro_use]
extern crate napi_derive;
Expand Down Expand Up @@ -54,18 +57,75 @@ impl Peer {
}

#[napi]
pub async fn fetch_server_coins(
&self,
launcher_id: Uint8Array,
count: u32,
) -> Result<Vec<ServerCoin>> {
pub async fn fetch_server_coins(&self, launcher_id: Uint8Array) -> Result<ServerCoinIterator> {
let launcher_id = bytes32(launcher_id)?;

let server_coins = fetch_server_coins(&self.0, launcher_id, count as usize)
let hint = morph_launcher_id(launcher_id);
let mut response = self
.0
.register_for_ph_updates(vec![hint.into()], 0)
.await
.map_err(|_| Error::from_reason("could not fetch server coins"))?;
response.retain(|coin_state| coin_state.spent_height.is_none());
response.sort_by_key(|coin_state| coin_state.coin.amount);

Ok(server_coins.into_iter().map(Into::into).collect())
Ok(ServerCoinIterator {
peer: self.0.clone(),
coin_states: Arc::new(Mutex::new(response)),
})
}
}

#[napi]
pub struct ServerCoinIterator {
peer: Arc<RustPeer>,
coin_states: Arc<Mutex<Vec<CoinState>>>,
}

#[napi]
impl ServerCoinIterator {
#[napi]
pub async fn next(&self) -> Result<Option<ServerCoin>> {
loop {
let Some(coin_state) = self.coin_states.lock().await.pop() else {
return Ok(None);
};

let Some(created_height) = coin_state.created_height else {
continue;
};

let spend = self
.peer
.request_puzzle_and_solution(coin_state.coin.parent_coin_info, created_height)
.await
.map_err(|_| Error::from_reason("failed to fetch puzzle and solution"))?;

let mut a = Allocator::new();

let Ok(output) = spend.puzzle.run(&mut a, 0, Cost::MAX, &spend.solution) else {
continue;
};

let Ok(conditions) = Vec::<Condition<NodePtr>>::from_clvm(&a, output.1) else {
continue;
};

let Some(urls) = urls_from_conditions(&coin_state.coin, &conditions) else {
continue;
};

let puzzle = spend.puzzle.to_node_ptr(&mut a).unwrap();

return Ok(Some(
RustServerCoin {
coin: coin_state.coin,
p2_puzzle_hash: tree_hash(&a, puzzle).into(),
memo_urls: urls,
}
.into(),
));
}
}
}

Expand Down
56 changes: 2 additions & 54 deletions src/server_coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ use chia_wallet_sdk::{
Condition, CreateCoin, DerivationStore, SyncConfig,
};
use clvm_traits::{FromClvm, FromNodePtr, ToClvm, ToNodePtr};
use clvm_utils::{curry_tree_hash, tree_hash, tree_hash_atom, CurriedProgram};
use clvmr::{cost::Cost, serde::node_from_bytes, Allocator, NodePtr};
use clvm_utils::{curry_tree_hash, tree_hash_atom, CurriedProgram};
use clvmr::{serde::node_from_bytes, Allocator, NodePtr};
use hex_literal::hex;
use num_bigint::BigInt;
use rand::{seq::SliceRandom, thread_rng};
use thiserror::Error;

#[derive(Debug, Clone, PartialEq, Eq, ToClvm, FromClvm)]
Expand Down Expand Up @@ -105,57 +104,6 @@ pub struct ServerCoin {
pub memo_urls: Vec<String>,
}

pub async fn fetch_server_coins(
peer: &Peer,
launcher_id: [u8; 32],
coin_limit: usize,
) -> Result<Vec<ServerCoin>, chia_client::Error<()>> {
let hint = morph_launcher_id(launcher_id);
let mut response = peer.register_for_ph_updates(vec![hint.into()], 0).await?;
response.retain(|state| state.spent_height.is_none());

response.shuffle(&mut thread_rng());

let mut results = Vec::new();

for coin_state in response.into_iter().take(coin_limit) {
let Some(created_height) = coin_state.created_height else {
continue;
};

let Ok(spend) = peer
.request_puzzle_and_solution(coin_state.coin.parent_coin_info, created_height)
.await
else {
continue;
};

let mut a = Allocator::new();

let Ok(output) = spend.puzzle.run(&mut a, 0, Cost::MAX, &spend.solution) else {
continue;
};

let Ok(conditions) = Vec::<Condition<NodePtr>>::from_clvm(&a, output.1) else {
continue;
};

let Some(urls) = urls_from_conditions(&coin_state.coin, &conditions) else {
continue;
};

let puzzle = spend.puzzle.to_node_ptr(&mut a).unwrap();

results.push(ServerCoin {
coin: coin_state.coin,
p2_puzzle_hash: tree_hash(&a, puzzle).into(),
memo_urls: urls,
});
}

Ok(results)
}

#[derive(Debug, Error)]
pub enum SpendError {
#[error("could not select coins: {0}")]
Expand Down

0 comments on commit 5705180

Please sign in to comment.