Skip to content

Commit

Permalink
Merge pull request #55 from SethDusek/indexallboxes
Browse files Browse the repository at this point in the history
Index all boxes + add notes/byPubkey endpoint
  • Loading branch information
SethDusek authored Sep 4, 2024
2 parents 91bfe9c + 65fe6da commit 49ddcf9
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 56 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions crates/chaincash_server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ hyper = { version = "0.14.27", features = ["full"] }
tracing = { workspace = true }
tokio = { workspace = true }
thiserror = { workspace = true }
ergo-lib = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
ergo_client = { workspace = true }
18 changes: 14 additions & 4 deletions crates/chaincash_server/src/notes.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::sync::Arc;

use axum::extract::State;
use axum::extract::{Path, State};
use axum::response::{IntoResponse, Response};
use axum::routing::{get, post};
use axum::{Json, Router};
Expand All @@ -9,6 +9,7 @@ use chaincash_offchain::transactions::notes::{
};
use chaincash_services::transaction::SpendNoteRequest;
use chaincash_services::ServerState;
use ergo_lib::ergo_chain_types::EcPoint;
use serde_json::json;

use crate::api::ApiError;
Expand Down Expand Up @@ -40,15 +41,24 @@ async fn spend_note(
Ok(response.into_response())
}

async fn list_notes(State(state): State<Arc<ServerState>>) -> Result<Response, ApiError> {
let notes = state.store.notes().notes()?;
async fn list_wallet_notes(State(state): State<Arc<ServerState>>) -> Result<Response, ApiError> {
let pubkeys = state.wallet_pubkeys().await?;
let notes = state.store.notes().notes_by_pubkeys(&pubkeys)?;
let response = Json(notes);
Ok(response.into_response())
}

async fn by_pubkey(
State(state): State<Arc<ServerState>>,
Path(pubkey): Path<EcPoint>,
) -> Result<Response, ApiError> {
Ok(Json(state.store.notes().notes_by_pubkeys(&[pubkey])?).into_response())
}

pub fn router() -> Router<Arc<ServerState>> {
Router::new()
.route("/", get(list_notes))
.route("/wallet", get(list_wallet_notes))
.route("/byPubkey/:pubkey", get(by_pubkey))
.route("/spend", post(spend_note))
.route("/mint", post(mint_note))
}
12 changes: 9 additions & 3 deletions crates/chaincash_server/src/reserves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,19 @@ async fn top_up_reserve(
Ok(response.into_response())
}

async fn list_reserves(State(state): State<Arc<ServerState>>) -> Result<Response, ApiError> {
Ok(Json(state.store.reserves().reserve_boxes()?).into_response())
async fn list_wallet_reserves(State(state): State<Arc<ServerState>>) -> Result<Response, ApiError> {
Ok(Json(
state
.store
.reserves()
.reserve_boxes_by_pubkeys(&state.wallet_pubkeys().await?)?,
)
.into_response())
}

pub fn router() -> Router<Arc<ServerState>> {
Router::new()
.route("/mint", post(mint_reserve))
.route("/topup", post(top_up_reserve))
.route("/", get(list_reserves))
.route("/wallet", get(list_wallet_reserves))
}
19 changes: 18 additions & 1 deletion crates/chaincash_services/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use chaincash_predicate::predicates::Predicate;
use chaincash_store::ChainCashStore;
use compiler::Compiler;
use ergo_client::node::NodeClient;
use transaction::TransactionService;
use ergo_lib::{ergo_chain_types::EcPoint, ergotree_ir::chain::address::Address};
use transaction::{TransactionService, TransactionServiceError};

pub mod compiler;
pub mod scanner;
Expand All @@ -25,6 +26,22 @@ impl ServerState {
predicates,
}
}

pub async fn wallet_pubkeys(&self) -> Result<Vec<EcPoint>, TransactionServiceError> {
Ok(self
.node
.endpoints()
.wallet()?
.get_addresses()
.await?
.into_iter()
.filter_map(|addr| match addr.address() {
Address::P2Pk(provedlog) => Some(*provedlog.h),
_ => None,
})
.collect())
}

pub fn tx_service(&self) -> TransactionService {
TransactionService::new(&self.node, &self.store, &self.compiler)
}
Expand Down
54 changes: 9 additions & 45 deletions crates/chaincash_services/src/scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ use ergo_client::node::{
};
use ergo_lib::{
chain::transaction::{ergo_transaction::ErgoTransaction, Transaction, TxId},
ergo_chain_types::EcPoint,
ergotree_ir::{
chain::{
address::Address,
ergo_box::{ErgoBox, NonMandatoryRegisterId, RegisterId},
token::TokenId,
},
Expand Down Expand Up @@ -49,12 +47,8 @@ struct ContractScan<'a> {
}

impl<'a> ContractScan<'a> {
async fn new(
state: &ServerState,
scan_type: ScanType,
public_keys: &[EcPoint],
) -> Result<Self, ScannerError> {
let (contract, register) = match scan_type {
async fn new(state: &ServerState, scan_type: ScanType) -> Result<Self, ScannerError> {
let (contract, _) = match scan_type {
ScanType::Reserves => (
state.compiler.reserve_contract().await?,
NonMandatoryRegisterId::R4,
Expand All @@ -68,40 +62,22 @@ impl<'a> ContractScan<'a> {
NonMandatoryRegisterId::R7,
),
};
let scan = Self::pubkey_scan(
format!("Chaincash {} scan", scan_type.to_str()),
contract,
register,
public_keys,
);
let scan = Self::contract_scan(format!("Chaincash {} scan", scan_type.to_str()), contract);
Ok(Self { scan_type, scan })
}

fn pubkey_scan(
fn contract_scan(
scan_name: impl Into<std::borrow::Cow<'a, str>>,
contract: &ErgoTree,
pubkey_register: NonMandatoryRegisterId,
public_keys: &[EcPoint],
) -> Scan<'a> {
Scan {
scan_name: scan_name.into(),
wallet_interaction: "off".into(),
tracking_rule: TrackingRule::And {
args: vec![
TrackingRule::Contains {
register: Some(RegisterId::R1),
value: contract.sigma_serialize_bytes().unwrap().into(),
},
TrackingRule::Or {
args: public_keys
.iter()
.map(|pubkey| TrackingRule::Equals {
register: Some(pubkey_register.into()),
value: pubkey.clone().into(),
})
.collect(),
},
],
args: vec![TrackingRule::Contains {
register: Some(RegisterId::R1),
value: contract.sigma_serialize_bytes().unwrap().into(),
}],
},
remove_offchain: true,
}
Expand Down Expand Up @@ -148,19 +124,7 @@ async fn load_scan(
scan_type: ScanType,
node_scans: &[RegisteredScan<'_>],
) -> Result<(bool, i32), ScannerError> {
let addresses = state
.node
.endpoints()
.wallet()?
.get_addresses()
.await?
.into_iter()
.filter_map(|addr| match addr.address() {
Address::P2Pk(pk) => Some((*pk.h).clone()),
_ => None,
})
.collect::<Vec<_>>();
let contract_scan = ContractScan::new(state, scan_type, &addresses).await?;
let contract_scan = ContractScan::new(state, scan_type).await?;
let scan = state.store.scans().scan_by_type(scan_type)?;
if let Some(scan) = scan {
if node_scans.iter().any(|node_scan| {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- This file should undo anything in `up.sql`
DROP INDEX reserve_pubkey_idx;
DROP INDEX note_pubkey_idx;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CREATE INDEX reserve_pubkey_idx ON reserves(owner);
CREATE INDEX note_pubkey_idx ON notes(owner);
8 changes: 6 additions & 2 deletions crates/chaincash_store/src/notes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ use diesel::{
BelongingToDsl, Connection, ExpressionMethods, OptionalExtension, QueryDsl, RunQueryDsl,
Selectable, SelectableHelper,
};
use ergo_lib::ergotree_ir::chain::{self, ergo_box::BoxId, token::TokenId};
use ergo_lib::{
ergo_chain_types::EcPoint,
ergotree_ir::chain::{self, ergo_box::BoxId, token::TokenId},
};
use serde::Serialize;

use crate::{
Expand Down Expand Up @@ -170,9 +173,10 @@ impl NoteRepository {
.transpose()
}

pub fn notes(&self) -> Result<Vec<NoteWithHistory>, Error> {
pub fn notes_by_pubkeys(&self, pubkeys: &[EcPoint]) -> Result<Vec<NoteWithHistory>, Error> {
let mut conn = self.pool.get()?;
let notes = schema::notes::table
.filter(schema::notes::owner.eq_any(pubkeys.into_iter().cloned().map(String::from)))
.select(Note::as_select())
.load(conn.borrow_mut())?;
Ok(OwnershipEntry::belonging_to(&notes)
Expand Down
7 changes: 6 additions & 1 deletion crates/chaincash_store/src/reserves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::Error;
use chaincash_offchain::boxes::ReserveBoxSpec;
use diesel::dsl::delete;
use diesel::prelude::*;
use ergo_lib::ergo_chain_types::EcPoint;
use ergo_lib::ergotree_ir::chain;
use ergo_lib::ergotree_ir::chain::ergo_box::BoxId;
use ergo_lib::ergotree_ir::chain::token::TokenId;
Expand Down Expand Up @@ -82,10 +83,14 @@ impl ReserveRepository {
.expect("Failed to parse ReserveBoxSpec from database"))
}

pub fn reserve_boxes(&self) -> Result<Vec<ReserveBoxSpec>, Error> {
pub fn reserve_boxes_by_pubkeys(
&self,
pubkeys: &[EcPoint],
) -> Result<Vec<ReserveBoxSpec>, Error> {
let mut conn = self.pool.get()?;
let join = schema::reserves::table
.inner_join(schema::ergo_boxes::table)
.filter(schema::reserves::owner.eq_any(pubkeys.into_iter().cloned().map(String::from)))
.select((Reserve::as_select(), ErgoBox::as_select()))
.load::<(Reserve, ErgoBox)>(&mut conn)?;
// Panic here if parsing ReserveBox from database fails
Expand Down

0 comments on commit 49ddcf9

Please sign in to comment.