From 91282a7e67e54bb1fe5678ec6d6491d3a29f332e Mon Sep 17 00:00:00 2001 From: jouzo Date: Thu, 23 Nov 2023 13:27:46 +0100 Subject: [PATCH 001/185] Ocean endpoints scaffold --- lib/Cargo.lock | 22 ++++++ lib/Cargo.toml | 2 + lib/ain-evm/src/storage/cache.rs | 69 ++++++++--------- lib/ain-evm/src/storage/mod.rs | 12 +-- lib/ain-ocean/Cargo.toml | 10 +++ lib/ain-ocean/src/api/address.rs | 70 +++++++++++++++++ lib/ain-ocean/src/api/block.rs | 31 ++++++++ lib/ain-ocean/src/api/fee.rs | 22 ++++++ lib/ain-ocean/src/api/governance.rs | 20 +++++ lib/ain-ocean/src/api/loan.rs | 63 +++++++++++++++ lib/ain-ocean/src/api/masternode.rs | 15 ++++ lib/ain-ocean/src/api/mod.rs | 41 ++++++++++ lib/ain-ocean/src/api/oracle.rs | 20 +++++ lib/ain-ocean/src/api/poolpairs.rs | 106 ++++++++++++++++++++++++++ lib/ain-ocean/src/api/prices.rs | 49 ++++++++++++ lib/ain-ocean/src/api/rawtx.rs | 24 ++++++ lib/ain-ocean/src/api/stats.rs | 25 ++++++ lib/ain-ocean/src/api/tokens.rs | 21 +++++ lib/ain-ocean/src/api/transactions.rs | 26 +++++++ lib/ain-ocean/src/lib.rs | 4 + 20 files changed, 607 insertions(+), 45 deletions(-) create mode 100644 lib/ain-ocean/Cargo.toml create mode 100644 lib/ain-ocean/src/api/address.rs create mode 100644 lib/ain-ocean/src/api/block.rs create mode 100644 lib/ain-ocean/src/api/fee.rs create mode 100644 lib/ain-ocean/src/api/governance.rs create mode 100644 lib/ain-ocean/src/api/loan.rs create mode 100644 lib/ain-ocean/src/api/masternode.rs create mode 100644 lib/ain-ocean/src/api/mod.rs create mode 100644 lib/ain-ocean/src/api/oracle.rs create mode 100644 lib/ain-ocean/src/api/poolpairs.rs create mode 100644 lib/ain-ocean/src/api/prices.rs create mode 100644 lib/ain-ocean/src/api/rawtx.rs create mode 100644 lib/ain-ocean/src/api/stats.rs create mode 100644 lib/ain-ocean/src/api/tokens.rs create mode 100644 lib/ain-ocean/src/api/transactions.rs create mode 100644 lib/ain-ocean/src/lib.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 2eb080789e5..173c017a4e7 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -206,6 +206,14 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "ain-ocean" +version = "0.1.0" +dependencies = [ + "axum", + "serde", +] + [[package]] name = "ain-rs-exports" version = "0.1.0" @@ -399,7 +407,11 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", "sync_wrapper", + "tokio", "tower", "tower-layer", "tower-service", @@ -4254,6 +4266,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" +dependencies = [ + "itoa", + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 2a1a25843a0..e3d517444cf 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -76,6 +76,8 @@ jsonrpsee-core = "0.16" jsonrpsee-server = "0.16" jsonrpsee-types = "0.16" +axum = "0.6.20" + tempdir = "0.3" rocksdb = { version = "0.21", default-features = false } diff --git a/lib/ain-evm/src/storage/cache.rs b/lib/ain-evm/src/storage/cache.rs index 2c81ce46625..b645cdc5bdf 100644 --- a/lib/ain-evm/src/storage/cache.rs +++ b/lib/ain-evm/src/storage/cache.rs @@ -3,18 +3,16 @@ use std::{borrow::ToOwned, num::NonZeroUsize, sync::RwLock}; use ethereum::{BlockAny, TransactionV2}; use ethereum_types::{H256, U256}; use lru::LruCache; -use parking_lot::Mutex; use super::traits::{BlockStorage, Rollback, TransactionStorage}; use crate::Result; #[derive(Debug)] pub struct Cache { - transactions: Mutex>, - blocks: Mutex>, - block_hashes: Mutex>, + transactions: RwLock>, + blocks: RwLock>, + block_hashes: RwLock>, latest_block: RwLock>, - contract_code: Mutex>>, } impl Cache { @@ -22,16 +20,13 @@ impl Cache { pub fn new(cache_size: Option) -> Self { Cache { - transactions: Mutex::new(LruCache::new( + transactions: RwLock::new(LruCache::new( NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), )), - blocks: Mutex::new(LruCache::new( + blocks: RwLock::new(LruCache::new( NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), )), - block_hashes: Mutex::new(LruCache::new( - NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), - )), - contract_code: Mutex::new(LruCache::new( + block_hashes: RwLock::new(LruCache::new( NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), )), latest_block: RwLock::new(None), @@ -41,13 +36,19 @@ impl Cache { impl BlockStorage for Cache { fn get_block_by_number(&self, number: &U256) -> Result> { - let block = self.blocks.lock().get(number).map(ToOwned::to_owned); + let block = self + .blocks + .write() + .unwrap() + .get(number) + .map(ToOwned::to_owned); Ok(block) } fn get_block_by_hash(&self, block_hash: &H256) -> Result> { self.block_hashes - .lock() + .write() + .unwrap() .get(block_hash) .map_or(Ok(None), |block_number| { self.get_block_by_number(block_number) @@ -59,8 +60,11 @@ impl BlockStorage for Cache { let block_number = block.header.number; let hash = block.header.hash(); - self.blocks.lock().put(block_number, block.clone()); - self.block_hashes.lock().put(hash, block_number); + self.blocks + .write() + .unwrap() + .put(block_number, block.clone()); + self.block_hashes.write().unwrap().put(hash, block_number); Ok(()) } @@ -83,7 +87,7 @@ impl BlockStorage for Cache { impl TransactionStorage for Cache { fn extend_transactions_from_block(&self, block: &BlockAny) -> Result<()> { - let mut cache = self.transactions.lock(); + let mut cache = self.transactions.write().unwrap(); for transaction in &block.transactions { let hash = transaction.hash(); @@ -93,7 +97,12 @@ impl TransactionStorage for Cache { } fn get_transaction_by_hash(&self, hash: &H256) -> Result> { - let transaction = self.transactions.lock().get(hash).map(ToOwned::to_owned); + let transaction = self + .transactions + .write() + .unwrap() + .get(hash) + .map(ToOwned::to_owned); Ok(transaction) } @@ -103,7 +112,8 @@ impl TransactionStorage for Cache { index: usize, ) -> Result> { self.block_hashes - .lock() + .write() + .unwrap() .get(block_hash) .map_or(Ok(None), |block_number| { self.get_transaction_by_block_number_and_index(block_number, index) @@ -117,7 +127,8 @@ impl TransactionStorage for Cache { ) -> Result> { let transaction = self .blocks - .lock() + .write() + .unwrap() .get(block_number) .and_then(|block| block.transactions.get(index).map(ToOwned::to_owned)); Ok(transaction) @@ -125,7 +136,8 @@ impl TransactionStorage for Cache { fn put_transaction(&self, transaction: &TransactionV2) -> Result<()> { self.transactions - .lock() + .write() + .unwrap() .put(transaction.hash(), transaction.clone()); Ok(()) } @@ -134,13 +146,13 @@ impl TransactionStorage for Cache { impl Rollback for Cache { fn disconnect_latest_block(&self) -> Result<()> { if let Some(block) = self.get_latest_block()? { - let mut transaction_cache = self.transactions.lock(); + let mut transaction_cache = self.transactions.write().unwrap(); for tx in &block.transactions { transaction_cache.pop(&tx.hash()); } - self.block_hashes.lock().pop(&block.header.hash()); - self.blocks.lock().pop(&block.header.number); + self.block_hashes.write().unwrap().pop(&block.header.hash()); + self.blocks.write().unwrap().pop(&block.header.number); let previous_block = self.get_block_by_hash(&block.header.parent_hash)?; self.put_latest_block(previous_block.as_ref())?; @@ -148,14 +160,3 @@ impl Rollback for Cache { Ok(()) } } - -impl Cache { - pub fn get_code_by_hash(&self, hash: &H256) -> Result>> { - Ok(self.contract_code.lock().get(hash).map(ToOwned::to_owned)) - } - - pub fn put_code(&self, hash: H256, code: &[u8]) -> Result<()> { - self.contract_code.lock().put(hash, code.to_vec()); - Ok(()) - } -} diff --git a/lib/ain-evm/src/storage/mod.rs b/lib/ain-evm/src/storage/mod.rs index 00f5eda18dc..d3ee93c5b9a 100644 --- a/lib/ain-evm/src/storage/mod.rs +++ b/lib/ain-evm/src/storage/mod.rs @@ -193,17 +193,7 @@ impl FlushableStorage for Storage { impl Storage { pub fn get_code_by_hash(&self, address: H160, hash: H256) -> Result>> { - match self.cache.get_code_by_hash(&hash) { - Ok(Some(code)) => Ok(Some(code)), - Ok(None) => { - let code = self.blockstore.get_code_by_hash(address, &hash); - if let Ok(Some(ref code)) = code { - self.cache.put_code(hash, code)?; - } - code - } - Err(e) => Err(e), - } + self.blockstore.get_code_by_hash(address, &hash) } pub fn put_code( diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml new file mode 100644 index 00000000000..c2082ddf53a --- /dev/null +++ b/lib/ain-ocean/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "ain-ocean" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +axum.workspace = true +serde.workspace = true diff --git a/lib/ain-ocean/src/api/address.rs b/lib/ain-ocean/src/api/address.rs new file mode 100644 index 00000000000..8bface2c67c --- /dev/null +++ b/lib/ain-ocean/src/api/address.rs @@ -0,0 +1,70 @@ +use axum::{extract::Path, routing::get, Router}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct Address { + address: String, +} + +#[derive(Deserialize)] +struct History { + address: String, + height: i64, + txno: i64, +} + +async fn get_account_history( + Path(History { + address, + height, + txno, + }): Path, +) -> String { + format!( + "Account history for address {}, height {}, txno {}", + address, height, txno + ) +} + +async fn list_account_history(Path(Address { address }): Path
) -> String { + format!("List account history for address {}", address) +} + +async fn get_balance(Path(Address { address }): Path
) -> String { + format!("balance for address {address}") +} + +async fn get_aggregation(Path(Address { address }): Path
) -> String { + format!("Aggregation for address {}", address) +} + +async fn list_token(Path(Address { address }): Path
) -> String { + format!("List tokens for address {}", address) +} + +async fn list_vault(Path(Address { address }): Path
) -> String { + format!("List vaults for address {}", address) +} + +async fn list_transaction(Path(Address { address }): Path
) -> String { + format!("List transactions for address {}", address) +} + +async fn list_transaction_unspent(Path(Address { address }): Path
) -> String { + format!("List unspent transactions for address {}", address) +} + +pub fn router() -> Router { + Router::new().nest( + "/:address", + Router::new() + .route("/history/:height/:txno", get(get_account_history)) + .route("/history", get(list_account_history)) + .route("/balance", get(get_balance)) + .route("/aggregation", get(get_aggregation)) + .route("/tokens", get(list_token)) + .route("/vaults", get(list_vault)) + .route("/transactions", get(list_transaction)) + .route("/transactions/unspent", get(list_transaction_unspent)), + ) +} diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs new file mode 100644 index 00000000000..19834e1eda5 --- /dev/null +++ b/lib/ain-ocean/src/api/block.rs @@ -0,0 +1,31 @@ +use axum::{extract::Path, routing::get, Router}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct BlockId { + id: String, +} + +#[derive(Deserialize)] +struct BlockHash { + hash: String, +} + +async fn list_blocks() -> String { + "List of blocks".to_string() +} + +async fn get_block(Path(BlockId { id }): Path) -> String { + format!("Details of block with id {}", id) +} + +async fn get_transactions(Path(BlockHash { hash }): Path) -> String { + format!("Transactions for block with hash {}", hash) +} + +pub fn router() -> Router { + Router::new() + .route("/", get(list_blocks)) + .route("/:id", get(get_block)) + .route("/:hash/transactions", get(get_transactions)) +} diff --git a/lib/ain-ocean/src/api/fee.rs b/lib/ain-ocean/src/api/fee.rs new file mode 100644 index 00000000000..4a042b8a6bd --- /dev/null +++ b/lib/ain-ocean/src/api/fee.rs @@ -0,0 +1,22 @@ +use axum::{extract::Query, routing::get, Router}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct EstimateQuery { + confirmation_target: i32, +} + +async fn estimate_fee( + Query(EstimateQuery { + confirmation_target, + }): Query, +) -> String { + format!( + "Fee estimate for confirmation target {}", + confirmation_target + ) +} + +pub fn router() -> Router { + Router::new().route("/estimate", get(estimate_fee)) +} diff --git a/lib/ain-ocean/src/api/governance.rs b/lib/ain-ocean/src/api/governance.rs new file mode 100644 index 00000000000..dd0979a2eff --- /dev/null +++ b/lib/ain-ocean/src/api/governance.rs @@ -0,0 +1,20 @@ +use axum::{extract::Path, routing::get, Router}; + +async fn list_gov_proposals() -> String { + "List of governance proposals".to_string() +} + +async fn get_gov_proposal(Path(proposal_id): Path) -> String { + format!("Details of governance proposal with id {}", proposal_id) +} + +async fn list_gov_proposal_votes(Path(proposal_id): Path) -> String { + format!("Votes for governance proposal with id {}", proposal_id) +} + +pub fn router() -> Router { + Router::new() + .route("/proposals", get(list_gov_proposals)) + .route("/proposals/:id", get(get_gov_proposal)) + .route("/proposals/:id/votes", get(list_gov_proposal_votes)) +} diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs new file mode 100644 index 00000000000..5452df1f3d0 --- /dev/null +++ b/lib/ain-ocean/src/api/loan.rs @@ -0,0 +1,63 @@ +use axum::{extract::Path, routing::get, Router}; + +async fn list_scheme() -> String { + "List of loan schemes".to_string() +} + +async fn get_scheme(Path(scheme_id): Path) -> String { + format!("Details of loan scheme with id {}", scheme_id) +} + +async fn list_collateral_token() -> String { + "List of collateral tokens".to_string() +} + +async fn get_collateral_token(Path(token_id): Path) -> String { + format!("Details of collateral token with id {}", token_id) +} + +async fn list_loan_token() -> String { + "List of loan tokens".to_string() +} + +async fn get_loan_token(Path(token_id): Path) -> String { + format!("Details of loan token with id {}", token_id) +} + +async fn list_vault() -> String { + "List of vaults".to_string() +} + +async fn get_vault(Path(vault_id): Path) -> String { + format!("Details of vault with id {}", vault_id) +} + +async fn list_vault_auction_history( + Path((vault_id, height, batch_index)): Path<(String, i64, i64)>, +) -> String { + format!( + "Auction history for vault id {}, height {}, batch index {}", + vault_id, height, batch_index + ) +} + +async fn list_auction() -> String { + "List of auctions".to_string() +} + +pub fn router() -> Router { + Router::new() + .route("/schemes", get(list_scheme)) + .route("/schemes/:id", get(get_scheme)) + .route("/collaterals", get(list_collateral_token)) + .route("/collaterals/:id", get(get_collateral_token)) + .route("/tokens", get(list_loan_token)) + .route("/tokens/:id", get(get_loan_token)) + .route("/vaults", get(list_vault)) + .route("/vaults/:id", get(get_vault)) + .route( + "/vaults/:id/auctions/:height/batches/:batchIndex/history", + get(list_vault_auction_history), + ) + .route("/auctions", get(list_auction)) +} diff --git a/lib/ain-ocean/src/api/masternode.rs b/lib/ain-ocean/src/api/masternode.rs new file mode 100644 index 00000000000..a15e184fd23 --- /dev/null +++ b/lib/ain-ocean/src/api/masternode.rs @@ -0,0 +1,15 @@ +use axum::{extract::Path, routing::get, Router}; + +async fn list_masternodes() -> String { + "List of masternodes".to_string() +} + +async fn get_masternode(Path(masternode_id): Path) -> String { + format!("Details of masternode with id {}", masternode_id) +} + +pub fn router() -> Router { + Router::new() + .route("/", get(list_masternodes)) + .route("/:id", get(get_masternode)) +} diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs new file mode 100644 index 00000000000..c173f1ab1b6 --- /dev/null +++ b/lib/ain-ocean/src/api/mod.rs @@ -0,0 +1,41 @@ +use std::net::SocketAddr; + +use axum::{Router, Server}; + +mod address; +mod block; +mod fee; +mod governance; +mod loan; +mod masternode; +mod oracle; +mod poolpairs; +mod prices; +mod rawtx; +mod stats; +mod tokens; +mod transactions; + +pub async fn start_ocean() { + let app = Router::new() + .nest("/address", address::router()) + .nest("/governance", governance::router()) + .nest("/loans", loan::router()) + .nest("/fee", fee::router()) + .nest("/masternodes", masternode::router()) + .nest("/oracles", oracle::router()) + .nest("/poolpairs", poolpairs::router()) + .nest("/prices", prices::router()) + .nest("/rawtx", rawtx::router()) + .nest("/stats", stats::router()) + .nest("/tokens", tokens::router()) + .nest("/transactions", transactions::router()) + .nest("/blocks", block::router()); + + let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); + println!("Listening on {}", addr); + Server::bind(&addr) + .serve(app.into_make_service()) + .await + .unwrap(); +} diff --git a/lib/ain-ocean/src/api/oracle.rs b/lib/ain-ocean/src/api/oracle.rs new file mode 100644 index 00000000000..bee3856022e --- /dev/null +++ b/lib/ain-ocean/src/api/oracle.rs @@ -0,0 +1,20 @@ +use axum::{extract::Path, routing::get, Router}; + +async fn list_oracles() -> String { + "List of oracles".to_string() +} + +async fn get_price_feed(Path((oracle_id, key)): Path<(String, String)>) -> String { + format!("Price feed for oracle ID {} and key {}", oracle_id, key) +} + +async fn get_oracle_by_address(Path(address): Path) -> String { + format!("Oracle details for address {}", address) +} + +pub fn router() -> Router { + Router::new() + .route("/", get(list_oracles)) + .route("/:oracleId/:key/feed", get(get_price_feed)) + .route("/:address", get(get_oracle_by_address)) +} diff --git a/lib/ain-ocean/src/api/poolpairs.rs b/lib/ain-ocean/src/api/poolpairs.rs new file mode 100644 index 00000000000..59500949387 --- /dev/null +++ b/lib/ain-ocean/src/api/poolpairs.rs @@ -0,0 +1,106 @@ +use axum::{ + extract::{Path, Query}, + routing::get, + Router, +}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct PoolPair { + id: String, +} + +#[derive(Deserialize)] +struct SwapAggregate { + id: String, + interval: i64, +} + +#[derive(Deserialize)] +struct SwappableTokens { + token_id: String, +} + +#[derive(Deserialize)] +struct BestPath { + from_token_id: String, + to_token_id: String, +} + +#[derive(Debug, Deserialize)] +struct DexPrices { + denomination: Option, +} + +async fn list_poolpairs() -> String { + "List of poolpairs".to_string() +} + +async fn get_poolpair(Path(PoolPair { id }): Path) -> String { + format!("Details of poolpair with id {}", id) +} + +async fn list_pool_swaps(Path(PoolPair { id }): Path) -> String { + format!("List of swaps for poolpair {}", id) +} + +async fn list_pool_swaps_verbose(Path(PoolPair { id }): Path) -> String { + format!("Verbose list of swaps for poolpair {}", id) +} + +async fn list_pool_swap_aggregates( + Path(SwapAggregate { id, interval }): Path, +) -> String { + format!( + "Aggregate swaps for poolpair {} over interval {}", + id, interval + ) +} + +async fn get_swappable_tokens(Path(SwappableTokens { token_id }): Path) -> String { + format!("Swappable tokens for token id {}", token_id) +} + +async fn get_best_path( + Query(BestPath { + from_token_id, + to_token_id, + }): Query, +) -> String { + format!( + "Best path from token id {} to {}", + from_token_id, to_token_id + ) +} + +async fn get_all_paths( + Query(BestPath { + from_token_id, + to_token_id, + }): Query, +) -> String { + format!( + "All paths from token id {} to {}", + from_token_id, to_token_id + ) +} + +async fn list_dex_prices(Query(DexPrices { denomination }): Query) -> String { + format!("List of DEX prices with denomination {:?}", denomination) +} + +pub fn router() -> Router { + Router::new() + .route("/", get(list_poolpairs)) + .route("/:id", get(get_poolpair)) + .route("/:id/swaps", get(list_pool_swaps)) + .route("/:id/swaps/verbose", get(list_pool_swaps_verbose)) + .route( + "/:id/swaps/aggregate/:interval", + get(list_pool_swap_aggregates), + ) + .route("/paths/swappable/:tokenId", get(get_swappable_tokens)) + .route("/paths/best", get(get_best_path)) + .route("/paths", get(get_all_paths)) + .route("/dexprices", get(list_dex_prices)) +} diff --git a/lib/ain-ocean/src/api/prices.rs b/lib/ain-ocean/src/api/prices.rs new file mode 100644 index 00000000000..94d13200839 --- /dev/null +++ b/lib/ain-ocean/src/api/prices.rs @@ -0,0 +1,49 @@ +use axum::{extract::Path, routing::get, Router}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct PriceKey { + key: String, +} + +#[derive(Deserialize)] +struct FeedWithInterval { + key: String, + interval: i64, +} + +async fn list_prices() -> String { + "List of prices".to_string() +} + +async fn get_price(Path(PriceKey { key }): Path) -> String { + format!("Details of price with key {}", key) +} + +async fn get_feed_active(Path(PriceKey { key }): Path) -> String { + format!("Active feed for price with key {}", key) +} + +async fn get_feed(Path(PriceKey { key }): Path) -> String { + format!("Feed for price with key {}", key) +} + +async fn get_feed_with_interval( + Path(FeedWithInterval { key, interval }): Path, +) -> String { + format!("Feed for price with key {} over interval {}", key, interval) +} + +async fn get_oracles(Path(PriceKey { key }): Path) -> String { + format!("Oracles for price with key {}", key) +} + +pub fn router() -> Router { + Router::new() + .route("/", get(list_prices)) + .route("/:key", get(get_price)) + .route("/:key/feed/active", get(get_feed_active)) + .route("/:key/feed", get(get_feed)) + .route("/:key/feed/interval/:interval", get(get_feed_with_interval)) + .route("/:key/oracles", get(get_oracles)) +} diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs new file mode 100644 index 00000000000..98258abbc04 --- /dev/null +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -0,0 +1,24 @@ +use axum::{ + extract::Path, + routing::{get, post}, + Router, +}; + +async fn send_rawtx() -> String { + "Sending raw transaction".to_string() +} + +async fn test_rawtx() -> String { + "Testing raw transaction".to_string() +} + +async fn get_rawtx(Path(txid): Path) -> String { + format!("Details of raw transaction with txid {}", txid) +} + +pub fn router() -> Router { + Router::new() + .route("/send", post(send_rawtx)) + .route("/test", get(test_rawtx)) + .route("/:txid", get(get_rawtx)) +} diff --git a/lib/ain-ocean/src/api/stats.rs b/lib/ain-ocean/src/api/stats.rs new file mode 100644 index 00000000000..8077b4b009b --- /dev/null +++ b/lib/ain-ocean/src/api/stats.rs @@ -0,0 +1,25 @@ +use axum::{routing::get, Router}; + +async fn get_stats() -> String { + "General stats".to_string() +} + +async fn get_reward_distribution() -> String { + "Reward distribution stats".to_string() +} + +async fn get_supply() -> String { + "Supply stats".to_string() +} + +async fn get_burn() -> String { + "Burn stats".to_string() +} + +pub fn router() -> Router { + Router::new() + .route("/", get(get_stats)) + .route("/rewards/distribution", get(get_reward_distribution)) + .route("/supply", get(get_supply)) + .route("/burn", get(get_burn)) +} diff --git a/lib/ain-ocean/src/api/tokens.rs b/lib/ain-ocean/src/api/tokens.rs new file mode 100644 index 00000000000..3b3d0f455d8 --- /dev/null +++ b/lib/ain-ocean/src/api/tokens.rs @@ -0,0 +1,21 @@ +use axum::{extract::Path, routing::get, Router}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct TokenId { + id: u32, +} + +async fn list_tokens() -> String { + "List of tokens".to_string() +} + +async fn get_token(Path(TokenId { id }): Path) -> String { + format!("Details of token with id {}", id) +} + +pub fn router() -> Router { + Router::new() + .route("/", get(list_tokens)) + .route("/:id", get(get_token)) +} diff --git a/lib/ain-ocean/src/api/transactions.rs b/lib/ain-ocean/src/api/transactions.rs new file mode 100644 index 00000000000..f75592a8cde --- /dev/null +++ b/lib/ain-ocean/src/api/transactions.rs @@ -0,0 +1,26 @@ +use axum::{extract::Path, routing::get, Router}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct TransactionId { + id: String, +} + +async fn get_transaction(Path(TransactionId { id }): Path) -> String { + format!("Details of transaction with id {}", id) +} + +async fn get_vins(Path(TransactionId { id }): Path) -> String { + format!("Vins for transaction with id {}", id) +} + +async fn get_vouts(Path(TransactionId { id }): Path) -> String { + format!("Vouts for transaction with id {}", id) +} + +pub fn router() -> Router { + Router::new() + .route("/:id", get(get_transaction)) + .route("/:id/vins", get(get_vins)) + .route("/:id/vouts", get(get_vouts)) +} diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs new file mode 100644 index 00000000000..916ddabe2a4 --- /dev/null +++ b/lib/ain-ocean/src/lib.rs @@ -0,0 +1,4 @@ +mod api; +mod model; + +pub use api::start_ocean; From 8956bbba80ba8467020d865cc8ca168e5188d5c4 Mon Sep 17 00:00:00 2001 From: jouzo Date: Fri, 24 Nov 2023 13:35:00 +0100 Subject: [PATCH 002/185] Model scaffold --- lib/ain-ocean/src/model/block.rs | 27 +++++++++ lib/ain-ocean/src/model/masternode.rs | 40 +++++++++++++ lib/ain-ocean/src/model/masternode_stats.rs | 40 +++++++++++++ lib/ain-ocean/src/model/mod.rs | 21 +++++++ lib/ain-ocean/src/model/oracle.rs | 32 ++++++++++ lib/ain-ocean/src/model/oracle_history.rs | 34 +++++++++++ .../src/model/oracle_price_active.rs | 60 +++++++++++++++++++ .../src/model/oracle_price_aggregated.rs | 43 +++++++++++++ .../model/oracle_price_aggregated_interval.rs | 44 ++++++++++++++ lib/ain-ocean/src/model/oracle_price_feed.rs | 29 +++++++++ .../src/model/oracle_token_currency.rs | 26 ++++++++ lib/ain-ocean/src/model/poolswap.rs | 27 +++++++++ .../src/model/poolswap_aggregated.rs | 28 +++++++++ lib/ain-ocean/src/model/price_ticker.rs | 12 ++++ lib/ain-ocean/src/model/raw_block.rs | 11 ++++ lib/ain-ocean/src/model/script_activity.rs | 47 +++++++++++++++ lib/ain-ocean/src/model/script_aggregation.rs | 44 ++++++++++++++ lib/ain-ocean/src/model/script_unspent.rs | 37 ++++++++++++ lib/ain-ocean/src/model/transaction.rs | 28 +++++++++ lib/ain-ocean/src/model/transaction_vin.rs | 36 +++++++++++ lib/ain-ocean/src/model/transaction_vout.rs | 19 ++++++ .../src/model/vault_auction_batch_history.rs | 28 +++++++++ 22 files changed, 713 insertions(+) create mode 100644 lib/ain-ocean/src/model/block.rs create mode 100644 lib/ain-ocean/src/model/masternode.rs create mode 100644 lib/ain-ocean/src/model/masternode_stats.rs create mode 100644 lib/ain-ocean/src/model/mod.rs create mode 100644 lib/ain-ocean/src/model/oracle.rs create mode 100644 lib/ain-ocean/src/model/oracle_history.rs create mode 100644 lib/ain-ocean/src/model/oracle_price_active.rs create mode 100644 lib/ain-ocean/src/model/oracle_price_aggregated.rs create mode 100644 lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs create mode 100644 lib/ain-ocean/src/model/oracle_price_feed.rs create mode 100644 lib/ain-ocean/src/model/oracle_token_currency.rs create mode 100644 lib/ain-ocean/src/model/poolswap.rs create mode 100644 lib/ain-ocean/src/model/poolswap_aggregated.rs create mode 100644 lib/ain-ocean/src/model/price_ticker.rs create mode 100644 lib/ain-ocean/src/model/raw_block.rs create mode 100644 lib/ain-ocean/src/model/script_activity.rs create mode 100644 lib/ain-ocean/src/model/script_aggregation.rs create mode 100644 lib/ain-ocean/src/model/script_unspent.rs create mode 100644 lib/ain-ocean/src/model/transaction.rs create mode 100644 lib/ain-ocean/src/model/transaction_vin.rs create mode 100644 lib/ain-ocean/src/model/transaction_vout.rs create mode 100644 lib/ain-ocean/src/model/vault_auction_batch_history.rs diff --git a/lib/ain-ocean/src/model/block.rs b/lib/ain-ocean/src/model/block.rs new file mode 100644 index 00000000000..96a0671d9ce --- /dev/null +++ b/lib/ain-ocean/src/model/block.rs @@ -0,0 +1,27 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct Block { + pub id: String, + pub hash: String, + pub previous_hash: String, + pub height: i32, + pub version: i32, + pub time: i32, + pub median_time: i32, + pub transaction_count: i32, + pub difficulty: i32, + pub masternode: String, + pub minter: String, + pub minter_block_count: i32, + pub reward: String, + pub stake_modifier: String, + pub merkleroot: String, + pub size: i32, + pub size_stripped: i32, + pub weight: i32, +} + + + diff --git a/lib/ain-ocean/src/model/masternode.rs b/lib/ain-ocean/src/model/masternode.rs new file mode 100644 index 00000000000..a50978fb17a --- /dev/null +++ b/lib/ain-ocean/src/model/masternode.rs @@ -0,0 +1,40 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct Masternode { + pub id: String, + pub sort: String, + pub owner_address: String, + pub operator_address: String, + pub creation_height: i32, + pub resign_height: i32, + pub resign_tx: String, + pub minted_blocks: i32, + pub timelock: i32, + pub collateral: String, + pub block: MasternodeBlock, + pub history: Vec, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct MasternodeBlock { + pub hash: String, + pub height: i32, + pub time: i32, + pub median_time: i32, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct HistoryItem { + pub txid: String, + pub owner_address: String, + pub operator_address: String, +} + + + diff --git a/lib/ain-ocean/src/model/masternode_stats.rs b/lib/ain-ocean/src/model/masternode_stats.rs new file mode 100644 index 00000000000..6f8d7fad270 --- /dev/null +++ b/lib/ain-ocean/src/model/masternode_stats.rs @@ -0,0 +1,40 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct MasternodeStats { + pub id: String, + pub block: MasternodeStatsBlock, + pub stats: MasternodeStatsStats, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct TimelockStats { + pub weeks: i32, + pub tvl: String, + pub count: i32, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct MasternodeStatsBlock { + pub hash: String, + pub height: i32, + pub time: i32, + pub median_time: i32, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct MasternodeStatsStats { + pub count: i32, + pub tvl: String, + pub locked: Vec, +} + + + diff --git a/lib/ain-ocean/src/model/mod.rs b/lib/ain-ocean/src/model/mod.rs new file mode 100644 index 00000000000..5d77166b54f --- /dev/null +++ b/lib/ain-ocean/src/model/mod.rs @@ -0,0 +1,21 @@ +pub mod block; +pub mod masternode; +pub mod masternode_stats; +pub mod oracle; +pub mod oracle_history; +pub mod oracle_price_active; +pub mod oracle_price_aggregated; +pub mod oracle_price_aggregated_interval; +pub mod oracle_price_feed; +pub mod oracle_token_currency; +pub mod poolswap; +pub mod poolswap_aggregated; +pub mod price_ticker; +pub mod raw_block; +pub mod script_activity; +pub mod script_aggregation; +pub mod script_unspent; +pub mod transaction; +pub mod transaction_vin; +pub mod transaction_vout; +pub mod vault_auction_batch_history; diff --git a/lib/ain-ocean/src/model/oracle.rs b/lib/ain-ocean/src/model/oracle.rs new file mode 100644 index 00000000000..71619e42184 --- /dev/null +++ b/lib/ain-ocean/src/model/oracle.rs @@ -0,0 +1,32 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct Oracle { + pub id: String, + pub owner_address: String, + pub weightage: i32, + pub price_feeds: Vec, + pub block: OracleBlock, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct PriceFeedsItem { + pub token: String, + pub currency: String, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OracleBlock { + pub hash: String, + pub height: i32, + pub time: i32, + pub median_time: i32, +} + + + diff --git a/lib/ain-ocean/src/model/oracle_history.rs b/lib/ain-ocean/src/model/oracle_history.rs new file mode 100644 index 00000000000..ff579bbdb39 --- /dev/null +++ b/lib/ain-ocean/src/model/oracle_history.rs @@ -0,0 +1,34 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OracleHistory { + pub id: String, + pub oracle_id: String, + pub sort: String, + pub owner_address: String, + pub weightage: i32, + pub price_feeds: Vec, + pub block: OracleHistoryBlock, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct PriceFeedsItem { + pub token: String, + pub currency: String, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OracleHistoryBlock { + pub hash: String, + pub height: i32, + pub time: i32, + pub median_time: i32, +} + + + diff --git a/lib/ain-ocean/src/model/oracle_price_active.rs b/lib/ain-ocean/src/model/oracle_price_active.rs new file mode 100644 index 00000000000..de3e0fdf597 --- /dev/null +++ b/lib/ain-ocean/src/model/oracle_price_active.rs @@ -0,0 +1,60 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceActive { + pub id: String, + pub key: String, + pub sort: String, + pub active: OraclePriceActiveActive, + pub next: OraclePriceActiveNext, + pub is_live: bool, + pub block: OraclePriceActiveBlock, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceActiveActive { + pub amount: String, + pub weightage: i32, + pub oracles: OraclePriceActiveActiveOracles, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceActiveNext { + pub amount: String, + pub weightage: i32, + pub oracles: OraclePriceActiveNextOracles, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceActiveBlock { + pub hash: String, + pub height: i32, + pub time: i32, + pub median_time: i32, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceActiveActiveOracles { + pub active: i32, + pub total: i32, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceActiveNextOracles { + pub active: i32, + pub total: i32, +} + + + diff --git a/lib/ain-ocean/src/model/oracle_price_aggregated.rs b/lib/ain-ocean/src/model/oracle_price_aggregated.rs new file mode 100644 index 00000000000..893d1e5a7e3 --- /dev/null +++ b/lib/ain-ocean/src/model/oracle_price_aggregated.rs @@ -0,0 +1,43 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceAggregated { + pub id: String, + pub key: String, + pub sort: String, + pub token: String, + pub currency: String, + pub aggregated: OraclePriceAggregatedAggregated, + pub block: OraclePriceAggregatedBlock, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceAggregatedAggregated { + pub amount: String, + pub weightage: i32, + pub oracles: OraclePriceAggregatedAggregatedOracles, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceAggregatedBlock { + pub hash: String, + pub height: i32, + pub time: i32, + pub median_time: i32, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceAggregatedAggregatedOracles { + pub active: i32, + pub total: i32, +} + + + diff --git a/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs new file mode 100644 index 00000000000..3761a349744 --- /dev/null +++ b/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs @@ -0,0 +1,44 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceAggregatedInterval { + pub id: String, + pub key: String, + pub sort: String, + pub token: String, + pub currency: String, + pub aggregated: OraclePriceAggregatedIntervalAggregated, + pub block: OraclePriceAggregatedIntervalBlock, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceAggregatedIntervalAggregated { + pub amount: String, + pub weightage: i32, + pub count: i32, + pub oracles: OraclePriceAggregatedIntervalAggregatedOracles, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceAggregatedIntervalBlock { + pub hash: String, + pub height: i32, + pub time: i32, + pub median_time: i32, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceAggregatedIntervalAggregatedOracles { + pub active: i32, + pub total: i32, +} + + + diff --git a/lib/ain-ocean/src/model/oracle_price_feed.rs b/lib/ain-ocean/src/model/oracle_price_feed.rs new file mode 100644 index 00000000000..b3007fbc030 --- /dev/null +++ b/lib/ain-ocean/src/model/oracle_price_feed.rs @@ -0,0 +1,29 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceFeed { + pub id: String, + pub key: String, + pub sort: String, + pub token: String, + pub currency: String, + pub oracle_id: String, + pub txid: String, + pub time: i32, + pub amount: String, + pub block: OraclePriceFeedBlock, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceFeedBlock { + pub hash: String, + pub height: i32, + pub time: i32, + pub median_time: i32, +} + + + diff --git a/lib/ain-ocean/src/model/oracle_token_currency.rs b/lib/ain-ocean/src/model/oracle_token_currency.rs new file mode 100644 index 00000000000..5de605b304c --- /dev/null +++ b/lib/ain-ocean/src/model/oracle_token_currency.rs @@ -0,0 +1,26 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OracleTokenCurrency { + pub id: String, + pub key: String, + pub token: String, + pub currency: String, + pub oracle_id: String, + pub weightage: i32, + pub block: OracleTokenCurrencyBlock, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct OracleTokenCurrencyBlock { + pub hash: String, + pub height: i32, + pub time: i32, + pub median_time: i32, +} + + + diff --git a/lib/ain-ocean/src/model/poolswap.rs b/lib/ain-ocean/src/model/poolswap.rs new file mode 100644 index 00000000000..e14ed89e82d --- /dev/null +++ b/lib/ain-ocean/src/model/poolswap.rs @@ -0,0 +1,27 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct PoolSwap { + pub id: String, + pub txid: String, + pub txno: i32, + pub pool_pair_id: String, + pub sort: String, + pub from_amount: String, + pub from_token_id: i32, + pub block: PoolSwapBlock, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct PoolSwapBlock { + pub hash: String, + pub height: i32, + pub time: i32, + pub median_time: i32, +} + + + diff --git a/lib/ain-ocean/src/model/poolswap_aggregated.rs b/lib/ain-ocean/src/model/poolswap_aggregated.rs new file mode 100644 index 00000000000..484a0a30292 --- /dev/null +++ b/lib/ain-ocean/src/model/poolswap_aggregated.rs @@ -0,0 +1,28 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct PoolSwapAggregated { + pub id: String, + pub key: String, + pub bucket: i32, + pub aggregated: PoolSwapAggregatedAggregated, + pub block: PoolSwapAggregatedBlock, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct PoolSwapAggregatedAggregated { + pub amounts: Vec, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct PoolSwapAggregatedBlock { + pub median_time: i32, +} + + + diff --git a/lib/ain-ocean/src/model/price_ticker.rs b/lib/ain-ocean/src/model/price_ticker.rs new file mode 100644 index 00000000000..46f330cbbde --- /dev/null +++ b/lib/ain-ocean/src/model/price_ticker.rs @@ -0,0 +1,12 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct PriceTicker { + pub id: String, + pub sort: String, + pub price: OraclePriceAggregated, +} + + + diff --git a/lib/ain-ocean/src/model/raw_block.rs b/lib/ain-ocean/src/model/raw_block.rs new file mode 100644 index 00000000000..9f3c2f08efd --- /dev/null +++ b/lib/ain-ocean/src/model/raw_block.rs @@ -0,0 +1,11 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct RawBlock { + pub id: String, + pub json: String, +} + + + diff --git a/lib/ain-ocean/src/model/script_activity.rs b/lib/ain-ocean/src/model/script_activity.rs new file mode 100644 index 00000000000..71d27e50df6 --- /dev/null +++ b/lib/ain-ocean/src/model/script_activity.rs @@ -0,0 +1,47 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct ScriptActivity { + pub id: String, + pub hid: String, + pub r#type: ScriptActivityType, + pub type_hex: ScriptActivityTypeHex, + pub txid: String, + pub block: ScriptActivityBlock, + pub script: ScriptActivityScript, + pub vin: ScriptActivityVin, + pub vout: ScriptActivityVout, + pub value: String, + pub token_id: i32, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct ScriptActivityBlock { + pub hash: String, + pub height: i32, + pub time: i32, + pub median_time: i32, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct ScriptActivityScript { + pub r#type: String, + pub hex: String, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct ScriptActivityVin { + pub txid: String, + pub n: i32, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct ScriptActivityVout { + pub txid: String, + pub n: i32, +} diff --git a/lib/ain-ocean/src/model/script_aggregation.rs b/lib/ain-ocean/src/model/script_aggregation.rs new file mode 100644 index 00000000000..b5752950cd0 --- /dev/null +++ b/lib/ain-ocean/src/model/script_aggregation.rs @@ -0,0 +1,44 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct ScriptAggregation { + pub id: String, + pub hid: String, + pub block: ScriptAggregationBlock, + pub script: ScriptAggregationScript, + pub statistic: ScriptAggregationStatistic, + pub amount: ScriptAggregationAmount, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct ScriptAggregationBlock { + pub hash: String, + pub height: i32, + pub time: i32, + pub median_time: i32, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct ScriptAggregationScript { + pub r#type: String, + pub hex: String, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct ScriptAggregationStatistic { + pub tx_count: i32, + pub tx_in_count: i32, + pub tx_out_count: i32, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct ScriptAggregationAmount { + pub tx_in: String, + pub tx_out: String, + pub unspent: String, +} diff --git a/lib/ain-ocean/src/model/script_unspent.rs b/lib/ain-ocean/src/model/script_unspent.rs new file mode 100644 index 00000000000..f018d9b90ad --- /dev/null +++ b/lib/ain-ocean/src/model/script_unspent.rs @@ -0,0 +1,37 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct ScriptUnspent { + pub id: String, + pub hid: String, + pub sort: String, + pub block: ScriptUnspentBlock, + pub script: ScriptUnspentScript, + pub vout: ScriptUnspentVout, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct ScriptUnspentBlock { + pub hash: String, + pub height: i32, + pub time: i32, + pub median_time: i32, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct ScriptUnspentScript { + pub r#type: String, + pub hex: String, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct ScriptUnspentVout { + pub txid: String, + pub n: i32, + pub value: String, + pub token_id: i32, +} diff --git a/lib/ain-ocean/src/model/transaction.rs b/lib/ain-ocean/src/model/transaction.rs new file mode 100644 index 00000000000..341d902874f --- /dev/null +++ b/lib/ain-ocean/src/model/transaction.rs @@ -0,0 +1,28 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct Transaction { + pub id: String, + pub order: i32, + pub block: TransactionBlock, + pub txid: String, + pub hash: String, + pub version: i32, + pub size: i32, + pub v_size: i32, + pub weight: i32, + pub total_vout_value: String, + pub lock_time: i32, + pub vin_count: i32, + pub vout_count: i32, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct TransactionBlock { + pub hash: String, + pub height: i32, + pub time: i32, + pub median_time: i32, +} diff --git a/lib/ain-ocean/src/model/transaction_vin.rs b/lib/ain-ocean/src/model/transaction_vin.rs new file mode 100644 index 00000000000..704a10998ec --- /dev/null +++ b/lib/ain-ocean/src/model/transaction_vin.rs @@ -0,0 +1,36 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct TransactionVin { + pub id: String, + pub txid: String, + pub coinbase: String, + pub vout: TransactionVinVout, + pub script: TransactionVinScript, + pub tx_in_witness: Vec, + pub sequence: String, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct TransactionVinVout { + pub id: String, + pub txid: String, + pub n: i32, + pub value: String, + pub token_id: i32, + pub script: TransactionVinVoutScript, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct TransactionVinScript { + pub hex: String, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct TransactionVinVoutScript { + pub hex: String, +} diff --git a/lib/ain-ocean/src/model/transaction_vout.rs b/lib/ain-ocean/src/model/transaction_vout.rs new file mode 100644 index 00000000000..7f09cebd21e --- /dev/null +++ b/lib/ain-ocean/src/model/transaction_vout.rs @@ -0,0 +1,19 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct TransactionVout { + pub id: String, + pub txid: String, + pub n: i32, + pub value: String, + pub token_id: i32, + pub script: TransactionVoutScript, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct TransactionVoutScript { + pub hex: String, + pub r#type: String, +} diff --git a/lib/ain-ocean/src/model/vault_auction_batch_history.rs b/lib/ain-ocean/src/model/vault_auction_batch_history.rs new file mode 100644 index 00000000000..bf39d3362b6 --- /dev/null +++ b/lib/ain-ocean/src/model/vault_auction_batch_history.rs @@ -0,0 +1,28 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct VaultAuctionBatchHistory { + pub id: String, + pub key: String, + pub sort: String, + pub vault_id: String, + pub index: i32, + pub from: String, + pub amount: String, + pub token_id: i32, + pub block: VaultAuctionBatchHistoryBlock, +} + + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct VaultAuctionBatchHistoryBlock { + pub hash: String, + pub height: i32, + pub time: i32, + pub median_time: i32, +} + + + From fc0f48c992702ed515889a19a0212a0317f22628 Mon Sep 17 00:00:00 2001 From: jouzo Date: Mon, 27 Nov 2023 20:17:16 +0100 Subject: [PATCH 003/185] Start ocean server --- lib/Cargo.lock | 213 +++++++++++++++++---- lib/Cargo.toml | 2 +- lib/ain-evm/Cargo.toml | 1 + lib/ain-evm/src/services.rs | 10 + lib/ain-grpc/Cargo.toml | 2 + lib/ain-grpc/src/lib.rs | 19 ++ lib/ain-ocean/Cargo.toml | 1 + lib/ain-ocean/src/api/mod.rs | 17 +- lib/ain-ocean/src/lib.rs | 2 +- lib/ain-ocean/src/model/price_ticker.rs | 7 +- lib/ain-ocean/src/model/script_activity.rs | 32 ++++ lib/ain-rs-exports/src/core.rs | 6 + lib/ain-rs-exports/src/lib.rs | 1 + src/init.cpp | 12 +- 14 files changed, 271 insertions(+), 54 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 173c017a4e7..3d798bdbec6 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -112,6 +112,7 @@ dependencies = [ "ain-contracts", "ain-cpp-imports", "anyhow", + "axum 0.7.1", "bincode", "ethabi", "ethbloom", @@ -159,8 +160,10 @@ version = "0.1.0" dependencies = [ "ain-cpp-imports", "ain-evm", + "ain-ocean", "anyhow", "async-trait", + "axum 0.7.1", "cxx", "env_logger", "ethereum", @@ -168,7 +171,7 @@ dependencies = [ "evm", "heck 0.4.1", "hex", - "hyper", + "hyper 0.14.27", "jsonrpsee 0.16.3", "jsonrpsee-server", "lazy_static", @@ -210,7 +213,8 @@ dependencies = [ name = "ain-ocean" version = "0.1.0" dependencies = [ - "axum", + "axum 0.7.1", + "hyper 0.14.27", "serde", ] @@ -392,13 +396,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", - "axum-core", + "axum-core 0.3.4", "bitflags 1.3.2", "bytes", "futures-util", - "http", - "http-body", - "hyper", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.27", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "810a80b128d70e6ed2bdf3fe8ed72c0ae56f5f5948d01c2753282dd92a84fce8" +dependencies = [ + "async-trait", + "axum-core 0.4.0", + "bytes", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.0.1", + "hyper-util", "itoa", "matchit", "memchr", @@ -426,10 +459,30 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http", - "http-body", + "http 0.2.9", + "http-body 0.4.5", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0ddc355eab88f4955090a823715df47acf0b7660aab7a69ad5ce6301ee3b73" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", "mime", + "pin-project-lite", "rustversion", + "sync_wrapper", "tower-layer", "tower-service", ] @@ -1874,7 +1927,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.9", "indexmap 1.9.3", "slab", "tokio", @@ -1882,6 +1935,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "h2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d308f63daf4181410c242d34c11f928dcb3aa105852019e043c9d1f4e4368a" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 1.0.0", + "indexmap 2.0.2", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hash-db" version = "0.15.2" @@ -2033,6 +2105,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.5" @@ -2040,7 +2123,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", - "http", + "http 0.2.9", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.0.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" +dependencies = [ + "bytes", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", "pin-project-lite", ] @@ -2078,9 +2184,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.3.21", + "http 0.2.9", + "http-body 0.4.5", "httparse", "httpdate", "itoa", @@ -2092,6 +2198,25 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403f9214f3e703236b221f1a9cd88ec8b4adfa5296de01ab96216361f4692f56" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.0", + "http 1.0.0", + "http-body 1.0.0", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "tokio", +] + [[package]] name = "hyper-rustls" version = "0.24.2" @@ -2099,8 +2224,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http", - "hyper", + "http 0.2.9", + "hyper 0.14.27", "log", "rustls", "rustls-native-certs", @@ -2115,12 +2240,32 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper", + "hyper 0.14.27", "pin-project-lite", "tokio", "tokio-io-timeout", ] +[[package]] +name = "hyper-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca339002caeb0d159cc6e023dff48e199f081e42fa039895c7c6f38b37f2e9d" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "hyper 1.0.1", + "pin-project-lite", + "socket2 0.5.5", + "tokio", + "tower", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" version = "0.1.58" @@ -2347,7 +2492,7 @@ dependencies = [ "futures-channel", "futures-util", "globset", - "hyper", + "hyper 0.14.27", "jsonrpsee-types 0.16.3", "parking_lot", "rand 0.8.5", @@ -2370,7 +2515,7 @@ dependencies = [ "async-trait", "beef", "futures-util", - "hyper", + "hyper 0.14.27", "jsonrpsee-types 0.18.2", "serde", "serde_json", @@ -2386,7 +2531,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e5f9fabdd5d79344728521bb65e3106b49ec405a78b66fbff073b72b389fa43" dependencies = [ "async-trait", - "hyper", + "hyper 0.14.27", "hyper-rustls", "jsonrpsee-core 0.16.3", "jsonrpsee-types 0.16.3", @@ -2405,7 +2550,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1705c65069729e3dccff6fd91ee431d5d31cabcf00ce68a62a2c6435ac713af9" dependencies = [ "async-trait", - "hyper", + "hyper 0.14.27", "hyper-rustls", "jsonrpsee-core 0.18.2", "jsonrpsee-types 0.18.2", @@ -2438,8 +2583,8 @@ checksum = "cf4d945a6008c9b03db3354fb3c83ee02d2faa9f2e755ec1dfb69c3551b8f4ba" dependencies = [ "futures-channel", "futures-util", - "http", - "hyper", + "http 0.2.9", + "hyper 0.14.27", "jsonrpsee-core 0.16.3", "jsonrpsee-types 0.16.3", "serde", @@ -3820,10 +3965,10 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "hyper", + "h2 0.3.21", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.27", "hyper-rustls", "ipnet", "js-sys", @@ -4481,7 +4626,7 @@ dependencies = [ "base64 0.13.1", "bytes", "futures", - "http", + "http 0.2.9", "httparse", "log", "rand 0.8.5", @@ -5281,15 +5426,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" dependencies = [ "async-trait", - "axum", + "axum 0.6.20", "base64 0.21.5", "bytes", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "hyper", + "h2 0.3.21", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.27", "hyper-timeout", "percent-encoding", "pin-project", @@ -5347,8 +5492,8 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http", - "http-body", + "http 0.2.9", + "http-body 0.4.5", "http-range-header", "httpdate", "iri-string", diff --git a/lib/Cargo.toml b/lib/Cargo.toml index e3d517444cf..8a2f5d26874 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -76,7 +76,7 @@ jsonrpsee-core = "0.16" jsonrpsee-server = "0.16" jsonrpsee-types = "0.16" -axum = "0.6.20" +axum = "0.7.1" tempdir = "0.3" diff --git a/lib/ain-evm/Cargo.toml b/lib/ain-evm/Cargo.toml index 6e09e82ed90..f5feaea9658 100644 --- a/lib/ain-evm/Cargo.toml +++ b/lib/ain-evm/Cargo.toml @@ -42,6 +42,7 @@ lazy_static.workspace = true jsonrpsee-core.workspace = true jsonrpsee-server.workspace = true jsonrpsee-types.workspace = true +axum.workspace = true tokio = { workspace = true, features = ["rt-multi-thread"] } # Cache dependencies diff --git a/lib/ain-evm/src/services.rs b/lib/ain-evm/src/services.rs index 3481190322f..7b9a9893c70 100644 --- a/lib/ain-evm/src/services.rs +++ b/lib/ain-evm/src/services.rs @@ -41,6 +41,7 @@ pub struct Services { pub tokio_worker: Mutex>>, pub json_rpc_handles: Mutex>, pub websocket_handles: Mutex>, + pub ocean_handle: Mutex>>, pub evm: Arc, } @@ -66,6 +67,7 @@ impl Services { }))), json_rpc_handles: Mutex::new(vec![]), websocket_handles: Mutex::new(vec![]), + ocean_handle: Mutex::new(None), evm: Arc::new(EVMServices::new().expect("Error initializating handlers")), } } @@ -84,6 +86,14 @@ impl Services { server.stop()?; } } + + { + if let Some(handle) = self.ocean_handle.lock().take() { + handle.abort(); + } + } + + // TODO: Propogate error Ok(()) } diff --git a/lib/ain-grpc/Cargo.toml b/lib/ain-grpc/Cargo.toml index 5a038572361..0615ed5d30c 100644 --- a/lib/ain-grpc/Cargo.toml +++ b/lib/ain-grpc/Cargo.toml @@ -7,6 +7,7 @@ build = "build.rs" [dependencies] ain-evm = { path = "../ain-evm" } ain-cpp-imports = { path = "../ain-cpp-imports" } +ain-ocean = { path = "../ain-ocean" } cxx.workspace = true env_logger.workspace = true evm = { workspace = true, default-features = false, features = ["with-serde"] } @@ -35,6 +36,7 @@ tower-http.workspace = true tower.workspace = true hyper.workspace = true rand.workspace = true +axum.workspace = true [build-dependencies] heck.workspace = true diff --git a/lib/ain-grpc/src/lib.rs b/lib/ain-grpc/src/lib.rs index 125eeb6206d..de5c7ca7a09 100644 --- a/lib/ain-grpc/src/lib.rs +++ b/lib/ain-grpc/src/lib.rs @@ -122,6 +122,25 @@ pub fn init_network_grpc_service(_addr: String) -> Result<()> { Ok(()) } +pub fn init_network_rest_ocean(addr: String) -> Result<()> { + info!("Starting REST Ocean server at {}", addr); + let addr = addr.as_str().parse::()?; + let runtime = &SERVICES; + + let handle = runtime.tokio_runtime.clone(); + let listener = runtime + .tokio_runtime + .block_on(tokio::net::TcpListener::bind(addr))?; + let server_handle = runtime.tokio_runtime.spawn(async move { + axum::serve(listener, ain_ocean::ocean_router()) + .await + .unwrap(); + }); + *runtime.ocean_handle.lock() = Some(server_handle); + + Ok(()) +} + pub fn init_network_subscriptions_service(addr: String) -> Result<()> { info!("Starting WebSockets server at {}", addr); let addr = addr.as_str().parse::()?; diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index c2082ddf53a..4ebf0ea35d7 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -8,3 +8,4 @@ edition = "2021" [dependencies] axum.workspace = true serde.workspace = true +hyper.workspace = true diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index c173f1ab1b6..4fc8d80da8d 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -1,6 +1,4 @@ -use std::net::SocketAddr; - -use axum::{Router, Server}; +use axum::Router; mod address; mod block; @@ -16,8 +14,8 @@ mod stats; mod tokens; mod transactions; -pub async fn start_ocean() { - let app = Router::new() +pub fn ocean_router() -> Router { + Router::new() .nest("/address", address::router()) .nest("/governance", governance::router()) .nest("/loans", loan::router()) @@ -30,12 +28,5 @@ pub async fn start_ocean() { .nest("/stats", stats::router()) .nest("/tokens", tokens::router()) .nest("/transactions", transactions::router()) - .nest("/blocks", block::router()); - - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - println!("Listening on {}", addr); - Server::bind(&addr) - .serve(app.into_make_service()) - .await - .unwrap(); + .nest("/blocks", block::router()) } diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 916ddabe2a4..2dae6056be6 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -1,4 +1,4 @@ mod api; mod model; -pub use api::start_ocean; +pub use api::ocean_router; diff --git a/lib/ain-ocean/src/model/price_ticker.rs b/lib/ain-ocean/src/model/price_ticker.rs index 46f330cbbde..3f9668b78f9 100644 --- a/lib/ain-ocean/src/model/price_ticker.rs +++ b/lib/ain-ocean/src/model/price_ticker.rs @@ -1,4 +1,6 @@ -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; + +use super::oracle_price_aggregated::OraclePriceAggregated; #[derive(Serialize, Deserialize, Debug, Default)] #[serde(rename_all = "camelCase")] @@ -7,6 +9,3 @@ pub struct PriceTicker { pub sort: String, pub price: OraclePriceAggregated, } - - - diff --git a/lib/ain-ocean/src/model/script_activity.rs b/lib/ain-ocean/src/model/script_activity.rs index 71d27e50df6..c156766a10e 100644 --- a/lib/ain-ocean/src/model/script_activity.rs +++ b/lib/ain-ocean/src/model/script_activity.rs @@ -1,5 +1,37 @@ use serde::{Deserialize, Serialize}; +#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum ScriptActivityType { + #[default] + Vin, + Vout, +} + +impl ScriptActivityType { + pub fn as_str(&self) -> &'static str { + match self { + ScriptActivityType::Vin => "vin", + ScriptActivityType::Vout => "vout", + } + } +} + +#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum ScriptActivityTypeHex { + #[default] + Vin, + Vout, +} + +impl ScriptActivityTypeHex { + pub fn as_str(&self) -> &'static str { + match self { + ScriptActivityTypeHex::Vin => "00", + ScriptActivityTypeHex::Vout => "01", + } + } +} + #[derive(Serialize, Deserialize, Debug, Default)] #[serde(rename_all = "camelCase")] pub struct ScriptActivity { diff --git a/lib/ain-rs-exports/src/core.rs b/lib/ain-rs-exports/src/core.rs index 02d1d34c22c..91209548ec5 100644 --- a/lib/ain-rs-exports/src/core.rs +++ b/lib/ain-rs-exports/src/core.rs @@ -44,6 +44,12 @@ pub fn ain_rs_init_network_subscriptions_service(addr: String) -> Result<()> { Ok(()) } +#[ffi_fallible] +pub fn ain_rs_init_network_rest_ocean(addr: String) -> Result<()> { + ain_grpc::init_network_rest_ocean(addr)?; + Ok(()) +} + #[ffi_fallible] pub fn ain_rs_stop_network_services() -> Result<()> { ain_grpc::stop_network_services()?; diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index e97f7e9a538..dae97502e2d 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -46,6 +46,7 @@ pub mod ffi { // Networking fn ain_rs_init_network_json_rpc_service(result: &mut CrossBoundaryResult, addr: String); fn ain_rs_init_network_grpc_service(result: &mut CrossBoundaryResult, addr: String); + fn ain_rs_init_network_rest_ocean(result: &mut CrossBoundaryResult, addr: String); fn ain_rs_init_network_subscriptions_service( result: &mut CrossBoundaryResult, addr: String, diff --git a/src/init.cpp b/src/init.cpp index d8e1c242c1d..bd6f3f11a9b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1592,7 +1592,7 @@ void SetupCacheSizes(CacheSizes& cacheSizes) { void SetupRPCPorts(std::vector& ethEndpoints, std::vector& gEndpoints, std::vector& wsEndpoints) { std::string default_address = "127.0.0.1"; - + // Determine which addresses to bind to ETH RPC server int eth_rpc_port = gArgs.GetArg("-ethrpcport", BaseParams().ETHRPCPort()); if (eth_rpc_port == -1) { @@ -2402,6 +2402,16 @@ bool AppInitMain(InitInterfaces& interfaces) } } } + + // bind ocean REST addresses + // for (auto it = ocean_endpoints.begin(); it != ocean_endpoints.end(); ++it) { + // LogPrint(BCLog::HTTP, "Binding ocean server on endpoint %s\n", *it); + auto res = XResultStatusLogged(ain_rs_init_network_rest_ocean(result, "127.0.0.1:3002")) + if (!res) { + // LogPrintf("Binding websocket server on endpoint %s failed.\n", *it); + return false; + } + // } } uiInterface.InitMessage(_("Done loading").translated); From 42b01a1867865b92618b8a19908944e0505cbea7 Mon Sep 17 00:00:00 2001 From: jouzo Date: Mon, 27 Nov 2023 20:35:28 +0100 Subject: [PATCH 004/185] Remove storage changes --- lib/ain-evm/src/storage/cache.rs | 69 ++++++++++++++++---------------- lib/ain-evm/src/storage/mod.rs | 12 +++++- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/lib/ain-evm/src/storage/cache.rs b/lib/ain-evm/src/storage/cache.rs index b645cdc5bdf..2c81ce46625 100644 --- a/lib/ain-evm/src/storage/cache.rs +++ b/lib/ain-evm/src/storage/cache.rs @@ -3,16 +3,18 @@ use std::{borrow::ToOwned, num::NonZeroUsize, sync::RwLock}; use ethereum::{BlockAny, TransactionV2}; use ethereum_types::{H256, U256}; use lru::LruCache; +use parking_lot::Mutex; use super::traits::{BlockStorage, Rollback, TransactionStorage}; use crate::Result; #[derive(Debug)] pub struct Cache { - transactions: RwLock>, - blocks: RwLock>, - block_hashes: RwLock>, + transactions: Mutex>, + blocks: Mutex>, + block_hashes: Mutex>, latest_block: RwLock>, + contract_code: Mutex>>, } impl Cache { @@ -20,13 +22,16 @@ impl Cache { pub fn new(cache_size: Option) -> Self { Cache { - transactions: RwLock::new(LruCache::new( + transactions: Mutex::new(LruCache::new( NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), )), - blocks: RwLock::new(LruCache::new( + blocks: Mutex::new(LruCache::new( NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), )), - block_hashes: RwLock::new(LruCache::new( + block_hashes: Mutex::new(LruCache::new( + NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), + )), + contract_code: Mutex::new(LruCache::new( NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), )), latest_block: RwLock::new(None), @@ -36,19 +41,13 @@ impl Cache { impl BlockStorage for Cache { fn get_block_by_number(&self, number: &U256) -> Result> { - let block = self - .blocks - .write() - .unwrap() - .get(number) - .map(ToOwned::to_owned); + let block = self.blocks.lock().get(number).map(ToOwned::to_owned); Ok(block) } fn get_block_by_hash(&self, block_hash: &H256) -> Result> { self.block_hashes - .write() - .unwrap() + .lock() .get(block_hash) .map_or(Ok(None), |block_number| { self.get_block_by_number(block_number) @@ -60,11 +59,8 @@ impl BlockStorage for Cache { let block_number = block.header.number; let hash = block.header.hash(); - self.blocks - .write() - .unwrap() - .put(block_number, block.clone()); - self.block_hashes.write().unwrap().put(hash, block_number); + self.blocks.lock().put(block_number, block.clone()); + self.block_hashes.lock().put(hash, block_number); Ok(()) } @@ -87,7 +83,7 @@ impl BlockStorage for Cache { impl TransactionStorage for Cache { fn extend_transactions_from_block(&self, block: &BlockAny) -> Result<()> { - let mut cache = self.transactions.write().unwrap(); + let mut cache = self.transactions.lock(); for transaction in &block.transactions { let hash = transaction.hash(); @@ -97,12 +93,7 @@ impl TransactionStorage for Cache { } fn get_transaction_by_hash(&self, hash: &H256) -> Result> { - let transaction = self - .transactions - .write() - .unwrap() - .get(hash) - .map(ToOwned::to_owned); + let transaction = self.transactions.lock().get(hash).map(ToOwned::to_owned); Ok(transaction) } @@ -112,8 +103,7 @@ impl TransactionStorage for Cache { index: usize, ) -> Result> { self.block_hashes - .write() - .unwrap() + .lock() .get(block_hash) .map_or(Ok(None), |block_number| { self.get_transaction_by_block_number_and_index(block_number, index) @@ -127,8 +117,7 @@ impl TransactionStorage for Cache { ) -> Result> { let transaction = self .blocks - .write() - .unwrap() + .lock() .get(block_number) .and_then(|block| block.transactions.get(index).map(ToOwned::to_owned)); Ok(transaction) @@ -136,8 +125,7 @@ impl TransactionStorage for Cache { fn put_transaction(&self, transaction: &TransactionV2) -> Result<()> { self.transactions - .write() - .unwrap() + .lock() .put(transaction.hash(), transaction.clone()); Ok(()) } @@ -146,13 +134,13 @@ impl TransactionStorage for Cache { impl Rollback for Cache { fn disconnect_latest_block(&self) -> Result<()> { if let Some(block) = self.get_latest_block()? { - let mut transaction_cache = self.transactions.write().unwrap(); + let mut transaction_cache = self.transactions.lock(); for tx in &block.transactions { transaction_cache.pop(&tx.hash()); } - self.block_hashes.write().unwrap().pop(&block.header.hash()); - self.blocks.write().unwrap().pop(&block.header.number); + self.block_hashes.lock().pop(&block.header.hash()); + self.blocks.lock().pop(&block.header.number); let previous_block = self.get_block_by_hash(&block.header.parent_hash)?; self.put_latest_block(previous_block.as_ref())?; @@ -160,3 +148,14 @@ impl Rollback for Cache { Ok(()) } } + +impl Cache { + pub fn get_code_by_hash(&self, hash: &H256) -> Result>> { + Ok(self.contract_code.lock().get(hash).map(ToOwned::to_owned)) + } + + pub fn put_code(&self, hash: H256, code: &[u8]) -> Result<()> { + self.contract_code.lock().put(hash, code.to_vec()); + Ok(()) + } +} diff --git a/lib/ain-evm/src/storage/mod.rs b/lib/ain-evm/src/storage/mod.rs index d3ee93c5b9a..00f5eda18dc 100644 --- a/lib/ain-evm/src/storage/mod.rs +++ b/lib/ain-evm/src/storage/mod.rs @@ -193,7 +193,17 @@ impl FlushableStorage for Storage { impl Storage { pub fn get_code_by_hash(&self, address: H160, hash: H256) -> Result>> { - self.blockstore.get_code_by_hash(address, &hash) + match self.cache.get_code_by_hash(&hash) { + Ok(Some(code)) => Ok(Some(code)), + Ok(None) => { + let code = self.blockstore.get_code_by_hash(address, &hash); + if let Ok(Some(ref code)) = code { + self.cache.put_code(hash, code)?; + } + code + } + Err(e) => Err(e), + } } pub fn put_code( From cd00f583dd3b037b483d7cd6a64927e7e6d52955 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Thu, 7 Dec 2023 04:05:08 +0800 Subject: [PATCH 005/185] Ocean list pagination + json req/res (#2737) * add ApiPageResponse + impl json on list_blocks * refine * body -> query --- lib/Cargo.lock | 16 +++ lib/Cargo.toml | 2 +- lib/ain-ocean/Cargo.toml | 5 +- lib/ain-ocean/src/api/block.rs | 61 +++++++++- lib/ain-ocean/src/api_paged_response.rs | 150 ++++++++++++++++++++++++ lib/ain-ocean/src/error.rs | 19 +++ lib/ain-ocean/src/lib.rs | 2 + 7 files changed, 249 insertions(+), 6 deletions(-) create mode 100644 lib/ain-ocean/src/api_paged_response.rs create mode 100644 lib/ain-ocean/src/error.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 3d798bdbec6..7e1da30d4aa 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -215,7 +215,10 @@ version = "0.1.0" dependencies = [ "axum 0.7.1", "hyper 0.14.27", + "keccak-hash", + "log", "serde", + "thiserror", ] [[package]] @@ -425,6 +428,7 @@ checksum = "810a80b128d70e6ed2bdf3fe8ed72c0ae56f5f5948d01c2753282dd92a84fce8" dependencies = [ "async-trait", "axum-core 0.4.0", + "axum-macros", "bytes", "futures-util", "http 1.0.0", @@ -487,6 +491,18 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-macros" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a2edad600410b905404c594e2523549f1bcd4bded1e252c8f74524ccce0b867" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "backtrace" version = "0.3.69" diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 8a2f5d26874..aaf1ed6cd82 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -76,7 +76,7 @@ jsonrpsee-core = "0.16" jsonrpsee-server = "0.16" jsonrpsee-types = "0.16" -axum = "0.7.1" +axum = { version = "0.7.1", features = ["macros"] } tempdir = "0.3" diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index 4ebf0ea35d7..bc5204d243e 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -7,5 +7,8 @@ edition = "2021" [dependencies] axum.workspace = true -serde.workspace = true hyper.workspace = true +keccak-hash.workspace = true +log.workspace = true +serde.workspace = true +thiserror.workspace = true diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 19834e1eda5..142d379dcec 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -1,5 +1,7 @@ -use axum::{extract::Path, routing::get, Router}; -use serde::Deserialize; +use axum::{debug_handler, extract::{Path, Query}, Json, routing::get, Router}; +use serde::{Deserialize, Serialize}; + +use crate::api_paged_response::ApiPagedResponse; #[derive(Deserialize)] struct BlockId { @@ -11,8 +13,29 @@ struct BlockHash { hash: String, } -async fn list_blocks() -> String { - "List of blocks".to_string() +#[derive(Deserialize)] +pub struct ListBlocksQuery { + pub size: usize, + pub next: Option +} + +#[debug_handler] +async fn list_blocks(Query(query): Query) -> Json> { + // TODO(): query from db + // db::block::list(req).await... + let blocks = vec![ + Block { id: "0".into() }, + Block { id: "1".into() }, + Block { id: "2".into() }, + ]; + + Json(ApiPagedResponse + ::of( + blocks, + query.size, + |block| block.clone().id + ) + ) } async fn get_block(Path(BlockId { id }): Path) -> String { @@ -29,3 +52,33 @@ pub fn router() -> Router { .route("/:id", get(get_block)) .route("/:hash/transactions", get(get_transactions)) } + +#[derive(Clone, Debug, Serialize)] +#[serde(default)] +pub struct Block { + id: String, + // TODO(): type mapping + // hash: H256, + // previous_hash: H256, + + // height: u64, + // version: u64, + // time: u64, // ---------------| block time in seconds since epoch + // median_time: u64, // --------| meidan time of the past 11 block timestamps + + // transaction_count: u64, + + // difficulty: u64, + + // masternode: H256, + // minter: H256, + // minter_block_count: u64, + // reward: f64 + + // state_modifier: H256, + // merkle_root: H256, + + // size: u64, + // size_stripped: u64, + // weight: u64, +} diff --git a/lib/ain-ocean/src/api_paged_response.rs b/lib/ain-ocean/src/api_paged_response.rs new file mode 100644 index 00000000000..83ac978df99 --- /dev/null +++ b/lib/ain-ocean/src/api_paged_response.rs @@ -0,0 +1,150 @@ +use serde::Serialize; + +/// ApiPagedResponse indicates that this response of data array slice is part of a sorted list of items. +/// Items are part of a larger sorted list and the slice indicates a window within the large sorted list. +/// Each ApiPagedResponse holds the data array and the "token" for next part of the slice. +/// The next token should be passed via query 'next' and only used when getting the next slice. +/// Hence the first request, the next token is always empty and not provided. +/// +/// With ascending sorted list and a limit of 3 items per slice will have the behaviour as such. +/// +/// SORTED : | [1] [2] [3] | [4] [5] [6] | [7] [8] [9] | [10] +/// Query 1 : Data: [1] [2] [3], Next: 3, Operator: GT (>) +/// Query 2 : Data: [4] [5] [6], Next: 6, Operator: GT (>) +/// Query 3 : Data: [7] [8] [9], Next: 3, Operator: GT (>) +/// Query 4 : Data: [10], Next: undefined +/// +/// This design is resilient also mutating sorted list, where pagination is not. +/// +/// SORTED : [2] [4] [6] [8] [10] [12] [14] +/// Query 1 : Data: [2] [4] [6], Next: 6, Operator: GT (>) +/// +/// Being in a slice window, the larger sorted list can be mutated. +/// You only need the next token to get the next slice. +/// MUTATED : [2] [4] [7] [8] [9] [10] [12] [14] +/// Query 2 : Data: [7] [8] [9], Next: 6, Operator: GT (>) +/// +/// Limitations of this requires your dat astructure to always be sorted in one direction and your sort +/// indexes always fixed. Hence the moving down of the slice window, your operator will be greater than (GT). +/// While moving up your operator will be less than (GT). +/// +/// ASC : | [1] [2] [3] | [4] [5] [6] | [7] [8] [9] | +/// >3 >6 >9 +/// DESC : | [9] [8] [7] | [6] [5] [4] | [3] [2] [1] | +/// <7 <4 <1 +/// For developer quality life it's unwise to allow inclusive operator, it just creates more overhead +/// to understanding our services. No GTE or LTE, always GT and LE. Services must beclean and clear, +/// when the usage narrative is clear and so will the use of ease. LIST query must be dead simple. +/// Image travelling down the path, and getting a "next token" to get the next set of itmes to +/// continue walking. +/// +/// Because the limit is not part of the slice window your query mechanism should support varying size windows. +/// +/// DATA: | [1] [2] [3] | [4] [5] [6] [7] | [8] [9] | ... +/// | limit 3, >3 | limit 4, >7 | limit 2, >9 +/// For simplicity your API should not attempt to allow access to different sort indexes, be cognizant of +/// how our APIs are consumed. If we create a GET /blocks operation to list blocks what would the correct indexes +/// be 99% of the time? +/// +/// Answer: Blocks sorted by height in descending order, that's your sorted list and your slice window. +/// : <- Latest | [100] [99] [98] [97] [...] | Oldest -> +/// +#[derive(Debug, Serialize, PartialEq)] +pub struct ApiPagedResponse { + data: Vec, + page: ApiPage, +} + +#[derive(Debug, Serialize, PartialEq)] +struct ApiPage { + next: Option, +} + +impl ApiPagedResponse { + pub fn new(data: Vec, next: Option<&str>) -> Self { + Self { data, page: ApiPage{ next: next.map(Into::into) } } // Option<&str> -> Option + } + + pub fn next(data: Vec, next: Option<&str>) -> Self { + Self::new(data, next) + } + + pub fn of(data: Vec, limit: usize, next_provider: impl Fn(&T) -> String) -> Self { + if data.len() == limit && data.len() > 0 && limit > 0 { + let next = next_provider(&data[limit - 1]); + Self::next(data, Some(next.as_str())) + } else { + Self::next(data, None) + } + } + + pub fn empty() -> Self { + Self::new(Vec::new(), None) + } +} + +#[cfg(test)] +mod tests { + use super::{ApiPagedResponse, ApiPage}; + + #[derive(Clone, Debug)] + struct Item { + id: String, + sort: String, + } + + impl Item { + fn new(id: &str, sort: &str) -> Self { + Self { + id: id.into(), + sort: sort.into(), + } + } + } + + #[test] + fn should_next_with_none() { + let items: Vec = vec![ + Item::new("0", "a"), + Item::new("1", "b"), + ]; + + let next = ApiPagedResponse::next(items, None).page.next; + assert_eq!(next, None); + } + + #[test] + fn should_next_with_value() { + let items: Vec = vec![ + Item::new("0", "a"), + Item::new("1", "b"), + ]; + + let next = ApiPagedResponse::next(items, Some("b")).page.next; + assert_eq!(next, Some("b".into())); + } + + #[test] + fn should_of_with_limit_3() { + let items: Vec = vec![ + Item::new("0", "a"), + Item::new("1", "b"), + Item::new("2", "c"), + ]; + + let next = ApiPagedResponse::of(items, 3, |item| item.clone().sort).page.next; + assert_eq!(next, Some("c".into())) + } + + #[test] + fn should_not_create_with_limit_3_while_size_2() { + let items: Vec = vec![ + Item::new("0", "a"), + Item::new("1", "b"), + ]; + + let page = ApiPagedResponse::of(items, 3, |item| item.clone().sort).page; + assert_eq!(page, ApiPage{next: None}) + } + +} diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs new file mode 100644 index 00000000000..7064679280d --- /dev/null +++ b/lib/ain-ocean/src/error.rs @@ -0,0 +1,19 @@ +use axum::{http::StatusCode, response::{IntoResponse, Response}}; +use thiserror::Error; + +pub type OceanResult = Result; + +#[derive(Error, Debug)] +pub enum OceanError { +} + +impl IntoResponse for OceanError { + fn into_response(self) -> Response { + let code: StatusCode = match self { + // OceanError::SomeError => StatusCode::SomeCode, + _ => StatusCode::INTERNAL_SERVER_ERROR, + }; + let reason = self.to_string(); + (code, reason).into_response() + } +} diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 2dae6056be6..7ee6252f32c 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -1,4 +1,6 @@ mod api; +pub mod api_paged_response; +pub mod error; mod model; pub use api::ocean_router; From d0cd25d3b7e829bf304d710b358f0ddb6e11fcc7 Mon Sep 17 00:00:00 2001 From: jouzo Date: Thu, 7 Dec 2023 22:08:20 +0100 Subject: [PATCH 006/185] Ocean indexing scaffold --- lib/Cargo.lock | 627 +++++++++++------- lib/Cargo.toml | 6 + lib/ain-ocean/Cargo.toml | 3 + lib/ain-ocean/src/indexer/auction.rs | 14 + lib/ain-ocean/src/indexer/masternode.rs | 83 +++ lib/ain-ocean/src/indexer/mod.rs | 70 ++ lib/ain-ocean/src/indexer/oracle.rs | 44 ++ lib/ain-ocean/src/indexer/pool.rs | 24 + lib/ain-ocean/src/lib.rs | 2 + lib/ain-ocean/src/model/block.rs | 8 +- lib/ain-ocean/src/model/masternode.rs | 32 +- lib/ain-ocean/src/model/masternode_stats.rs | 20 +- lib/ain-ocean/src/model/oracle.rs | 16 +- lib/ain-ocean/src/model/oracle_history.rs | 16 +- .../src/model/oracle_price_active.rs | 28 +- .../src/model/oracle_price_aggregated.rs | 20 +- .../model/oracle_price_aggregated_interval.rs | 20 +- lib/ain-ocean/src/model/oracle_price_feed.rs | 12 +- .../src/model/oracle_token_currency.rs | 12 +- lib/ain-ocean/src/model/poolswap.rs | 12 +- .../src/model/poolswap_aggregated.rs | 16 +- lib/ain-ocean/src/model/price_ticker.rs | 5 +- lib/ain-ocean/src/model/raw_block.rs | 8 +- lib/ain-ocean/src/model/script_activity.rs | 21 +- lib/ain-ocean/src/model/script_aggregation.rs | 17 +- lib/ain-ocean/src/model/script_unspent.rs | 14 +- lib/ain-ocean/src/model/transaction.rs | 8 +- lib/ain-ocean/src/model/transaction_vin.rs | 14 +- lib/ain-ocean/src/model/transaction_vout.rs | 8 +- .../src/model/vault_auction_batch_history.rs | 12 +- lib/ain-rs-exports/Cargo.toml | 1 + lib/ain-rs-exports/src/core.rs | 4 + lib/ain-rs-exports/src/lib.rs | 2 + src/dfi/validation.cpp | 12 + 34 files changed, 736 insertions(+), 475 deletions(-) create mode 100644 lib/ain-ocean/src/indexer/auction.rs create mode 100644 lib/ain-ocean/src/indexer/masternode.rs create mode 100644 lib/ain-ocean/src/indexer/mod.rs create mode 100644 lib/ain-ocean/src/indexer/oracle.rs create mode 100644 lib/ain-ocean/src/indexer/pool.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 7e1da30d4aa..f262033d95c 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -27,7 +27,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ - "gimli 0.28.0", + "gimli 0.28.1", ] [[package]] @@ -53,7 +53,7 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.11", "once_cell", "version_check", ] @@ -65,7 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if", - "getrandom 0.2.10", + "getrandom 0.2.11", "once_cell", "version_check", "zerocopy", @@ -112,7 +112,7 @@ dependencies = [ "ain-contracts", "ain-cpp-imports", "anyhow", - "axum 0.7.1", + "axum 0.7.2", "bincode", "ethabi", "ethbloom", @@ -163,7 +163,7 @@ dependencies = [ "ain-ocean", "anyhow", "async-trait", - "axum 0.7.1", + "axum 0.7.2", "cxx", "env_logger", "ethereum", @@ -192,7 +192,7 @@ dependencies = [ "serde_json", "serde_with", "sha3", - "syn 2.0.38", + "syn 2.0.39", "tokio", "tonic", "tonic-build", @@ -206,14 +206,17 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "ain-ocean" version = "0.1.0" dependencies = [ - "axum 0.7.1", + "axum 0.7.2", + "bitcoin", + "dftx-rs", + "hex", "hyper 0.14.27", "keccak-hash", "log", @@ -230,6 +233,7 @@ dependencies = [ "ain-evm", "ain-grpc", "ain-macros", + "ain-ocean", "anyhow", "cxx", "cxx-gen", @@ -305,9 +309,9 @@ dependencies = [ [[package]] name = "array-bytes" -version = "6.1.0" +version = "6.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b1c5a481ec30a5abd8dfbd94ab5cf1bb4e9a66be7f1b3b322f2f1170c200fd" +checksum = "6f840fb7195bcfc5e17ea40c26e5ce6d5b9ce5d584466e17703209657e459ae0" [[package]] name = "arrayref" @@ -338,9 +342,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f658e2baef915ba0f26f1f7c42bfb8e12f532a01f449a090ded75ae7a07e9ba2" +checksum = "bc2d0cfb2a7388d34f590e76686704c494ed7aaceed62ee1ba35cbf363abc2a5" dependencies = [ "brotli", "flate2", @@ -360,7 +364,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -403,7 +407,7 @@ dependencies = [ "bitflags 1.3.2", "bytes", "futures-util", - "http 0.2.9", + "http 0.2.11", "http-body 0.4.5", "hyper 0.14.27", "itoa", @@ -422,12 +426,12 @@ dependencies = [ [[package]] name = "axum" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "810a80b128d70e6ed2bdf3fe8ed72c0ae56f5f5948d01c2753282dd92a84fce8" +checksum = "202651474fe73c62d9e0a56c6133f7a0ff1dc1c8cf7a5b03381af2a26553ac9d" dependencies = [ "async-trait", - "axum-core 0.4.0", + "axum-core 0.4.1", "axum-macros", "bytes", "futures-util", @@ -463,7 +467,7 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 0.2.9", + "http 0.2.11", "http-body 0.4.5", "mime", "rustversion", @@ -473,9 +477,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0ddc355eab88f4955090a823715df47acf0b7660aab7a69ad5ce6301ee3b73" +checksum = "77cb22c689c44d4c07b0ab44ebc25d69d8ae601a2f28fb8d672d344178fa17aa" dependencies = [ "async-trait", "bytes", @@ -500,7 +504,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -552,6 +556,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "bech32" +version = "0.10.0-beta" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98f7eed2b2781a6f0b5c903471d48e15f56fb4e1165df8a9a2337fd1a59d45ea" + [[package]] name = "beef" version = "0.5.2" @@ -588,7 +598,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -606,6 +616,41 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +[[package]] +name = "bitcoin" +version = "0.31.0" +source = "git+https://github.com/Jouzo/rust-bitcoin.git#d540306b57be5ff16b120c0e70b87512d289c262" +dependencies = [ + "bech32", + "bitcoin-internals", + "bitcoin-io", + "bitcoin_hashes", + "hex-conservative", + "hex_lit", + "secp256k1 0.28.0", +] + +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" + +[[package]] +name = "bitcoin-io" +version = "0.1.0" +source = "git+https://github.com/Jouzo/rust-bitcoin.git#d540306b57be5ff16b120c0e70b87512d289c262" + +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -730,9 +775,9 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bstr" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019" +checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c" dependencies = [ "memchr", "serde", @@ -915,9 +960,9 @@ checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -925,9 +970,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpp_demangle" @@ -1006,9 +1051,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array 0.14.7", "rand_core 0.6.4", @@ -1096,7 +1141,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1108,7 +1153,7 @@ dependencies = [ "codespan-reporting", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1125,7 +1170,7 @@ checksum = "587663dd5fb3d10932c8aecfe7c844db1bcf0aee93eeab08fac13dc1212c2e7f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1149,7 +1194,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1160,7 +1205,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1175,9 +1220,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" dependencies = [ "powerfmt", "serde", @@ -1200,6 +1245,28 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a1abaf4d861455be59f64fd2b55606cb151fce304ede7165f410243ce96bde6" +[[package]] +name = "dftx-macro" +version = "0.1.0" +source = "git+https://github.com/Jouzo/dftx-rs.git#7973f1ad240d5f7724e51c6b090bcd3daafc495c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "dftx-rs" +version = "0.1.0" +source = "git+https://github.com/Jouzo/dftx-rs.git#7973f1ad240d5f7724e51c6b090bcd3daafc495c" +dependencies = [ + "anyhow", + "bitcoin", + "bitflags 2.4.1", + "dftx-macro", + "hex", +] + [[package]] name = "diff" version = "0.1.13" @@ -1307,21 +1374,21 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d2f3407d9a573d666de4b5bdf10569d73ca9478087346697dcbae6244bfbcd" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" [[package]] name = "ecdsa" -version = "0.16.8" +version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", "digest 0.10.7", "elliptic-curve", "rfc6979", - "signature 2.1.0", + "signature 2.2.0", "spki", ] @@ -1368,9 +1435,9 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "elliptic-curve" -version = "0.13.6" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97ca172ae9dc9f9b779a6e3a65d308f2af74e5b8c921299075bdb4a0370e914" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", @@ -1405,9 +1472,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ "humantime", "is-terminal", @@ -1439,12 +1506,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.5" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1516,9 +1583,9 @@ dependencies = [ [[package]] name = "ethers-core" -version = "2.0.10" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0a17f0708692024db9956b31d7a20163607d2745953f5ae8125ab368ba280ad" +checksum = "2f03e0bdc216eeb9e355b90cf610ef6c5bb8aca631f97b5ae9980ce34ea7878d" dependencies = [ "arrayvec 0.7.4", "bytes", @@ -1543,9 +1610,9 @@ dependencies = [ [[package]] name = "ethers-solc" -version = "2.0.10" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de34e484e7ae3cab99fbfd013d6c5dc7f9013676a4e0e414d8b12e1213e8b3ba" +checksum = "a64f710586d147864cff66540a6d64518b9ff37d73ef827fee430538265b595f" dependencies = [ "cfg-if", "const-hex", @@ -1705,9 +1772,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -1801,7 +1868,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1876,9 +1943,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", @@ -1898,9 +1965,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "glob" @@ -1910,15 +1977,15 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" dependencies = [ "aho-corasick", "bstr", - "fnv", "log", - "regex", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", ] [[package]] @@ -1934,17 +2001,17 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", - "http 0.2.9", - "indexmap 1.9.3", + "http 0.2.11", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -1963,7 +2030,7 @@ dependencies = [ "futures-sink", "futures-util", "http 1.0.0", - "indexmap 2.0.2", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -2011,9 +2078,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ "ahash 0.8.6", "allocator-api2", @@ -2055,12 +2122,24 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-conservative" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" + [[package]] name = "hex-literal" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "hex_lit" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" + [[package]] name = "hmac" version = "0.8.1" @@ -2112,9 +2191,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -2139,7 +2218,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", - "http 0.2.9", + "http 0.2.11", "pin-project-lite", ] @@ -2200,8 +2279,8 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.3.21", - "http 0.2.9", + "h2 0.3.22", + "http 0.2.11", "http-body 0.4.5", "httparse", "httpdate", @@ -2240,7 +2319,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http 0.2.9", + "http 0.2.11", "hyper 0.14.27", "log", "rustls", @@ -2313,9 +2392,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -2372,12 +2451,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.2", + "hashbrown 0.14.3", "serde", ] @@ -2424,7 +2503,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi 0.3.3", - "rustix 0.38.21", + "rustix 0.38.26", "windows-sys 0.48.0", ] @@ -2463,9 +2542,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] @@ -2599,7 +2678,7 @@ checksum = "cf4d945a6008c9b03db3354fb3c83ee02d2faa9f2e755ec1dfb69c3551b8f4ba" dependencies = [ "futures-channel", "futures-util", - "http 0.2.9", + "http 0.2.11", "hyper 0.14.27", "jsonrpsee-core 0.16.3", "jsonrpsee-types 0.16.3", @@ -2643,9 +2722,9 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +checksum = "3f01b677d82ef7a676aa37e099defd83a28e15687112cafdd112d60236b6115b" dependencies = [ "cfg-if", "ecdsa", @@ -2750,9 +2829,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libloading" @@ -2770,6 +2849,17 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall", +] + [[package]] name = "librocksdb-sys" version = "0.11.0+8.1.1" @@ -2861,9 +2951,9 @@ checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" [[package]] name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "lock_api" @@ -2883,11 +2973,11 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "lru" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efa59af2ddfad1854ae27d75009d538d0998b4b2fd47083e743ac1a10e46c60" +checksum = "2994eeba8ed550fd9b47a0b38f0242bc3344e496483c6180b69139cc2fa5d1d7" dependencies = [ - "hashbrown 0.14.2", + "hashbrown 0.14.3", ] [[package]] @@ -2946,7 +3036,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix 0.38.21", + "rustix 0.38.26", ] [[package]] @@ -3036,9 +3126,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -3214,10 +3304,10 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" dependencies = [ - "proc-macro-crate 2.0.0", + "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3298,9 +3388,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "parity-scale-codec" -version = "3.6.5" +version = "3.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" dependencies = [ "arrayvec 0.7.4", "bitvec", @@ -3313,11 +3403,11 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.5" +version = "3.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 2.0.1", "proc-macro2", "quote", "syn 1.0.109", @@ -3341,7 +3431,7 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "smallvec", "windows-targets 0.48.5", ] @@ -3398,9 +3488,9 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "petgraph" @@ -3409,7 +3499,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.0.2", + "indexmap 2.1.0", ] [[package]] @@ -3442,7 +3532,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3480,7 +3570,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3546,7 +3636,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3575,11 +3665,12 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" dependencies = [ - "toml_edit 0.20.7", + "toml_datetime", + "toml_edit 0.20.2", ] [[package]] @@ -3608,18 +3699,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c003ac8c77cb07bb74f5f198bce836a689bcd5a42574612bf14d17bfd08c20e" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" dependencies = [ "bitflags 2.4.1", "lazy_static", @@ -3627,7 +3718,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "rand_xorshift", - "regex-syntax 0.7.5", + "regex-syntax 0.8.2", "unarray", ] @@ -3796,7 +3887,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.11", ] [[package]] @@ -3862,15 +3953,6 @@ dependencies = [ "rand_core 0.3.1", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -3882,12 +3964,12 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ - "getrandom 0.2.10", - "redox_syscall 0.2.16", + "getrandom 0.2.11", + "libredox", "thiserror", ] @@ -3908,7 +3990,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -3981,8 +4063,8 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.3.21", - "http 0.2.9", + "h2 0.3.22", + "http 0.2.11", "http-body 0.4.5", "hyper 0.14.27", "hyper-rustls", @@ -4022,12 +4104,12 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.5" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", - "getrandom 0.2.10", + "getrandom 0.2.11", "libc", "spin 0.9.8", "untrusted", @@ -4138,22 +4220,22 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.21" +version = "0.38.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" dependencies = [ "bitflags 2.4.1", "errno", "libc", - "linux-raw-sys 0.4.10", - "windows-sys 0.48.0", + "linux-raw-sys 0.4.12", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.21.8" +version = "0.21.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" +checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" dependencies = [ "log", "ring", @@ -4175,9 +4257,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ "base64 0.21.5", ] @@ -4328,7 +4410,17 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" dependencies = [ - "secp256k1-sys", + "secp256k1-sys 0.6.1", +] + +[[package]] +name = "secp256k1" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acea373acb8c21ecb5a23741452acd2593ed44ee3d343e72baaa143bc89d0d5" +dependencies = [ + "bitcoin_hashes", + "secp256k1-sys 0.9.0", ] [[package]] @@ -4340,6 +4432,15 @@ dependencies = [ "cc", ] +[[package]] +name = "secp256k1-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e67c467c38fd24bd5499dc9a18183b31575c12ee549197e3e20d57aa4fe3b7" +dependencies = [ + "cc", +] + [[package]] name = "secrecy" version = "0.8.0" @@ -4398,22 +4499,22 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.190" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.190" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -4459,7 +4560,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.0.2", + "indexmap 2.1.0", "serde", "serde_json", "serde_with_macros", @@ -4475,7 +4576,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -4571,9 +4672,9 @@ checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" [[package]] name = "signature" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", "rand_core 0.6.4", @@ -4609,9 +4710,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "socket2" @@ -4642,7 +4743,7 @@ dependencies = [ "base64 0.13.1", "bytes", "futures", - "http 0.2.9", + "http 0.2.11", "httparse", "log", "rand 0.8.5", @@ -4651,9 +4752,9 @@ dependencies = [ [[package]] name = "solang-parser" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cb9fa2fa2fa6837be8a2495486ff92e3ffe68a99b6eeba288e139efdd842457" +checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" dependencies = [ "itertools 0.11.0", "lalrpop", @@ -4692,7 +4793,7 @@ dependencies = [ "regex", "scale-info", "schnorrkel", - "secp256k1", + "secp256k1 0.24.3", "secrecy", "serde", "sp-core-hashing", @@ -4731,7 +4832,7 @@ checksum = "f12dae7cf6c1e825d13ffd4ce16bd9309db7c539929d0302b4443ed451a9f4e5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -4759,7 +4860,7 @@ dependencies = [ "log", "parity-scale-codec", "rustversion", - "secp256k1", + "secp256k1 0.24.3", "sp-core", "sp-externalities", "sp-keystore", @@ -4825,7 +4926,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -4938,9 +5039,9 @@ dependencies = [ [[package]] name = "spki" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", @@ -4948,9 +5049,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.43.0" +version = "1.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6915280e2d0db8911e5032a5c275571af6bdded2916abd691a659be25d3439" +checksum = "35935738370302d5e33963665b77541e4b990a3e919ec904c837a56cfc891de1" dependencies = [ "Inflector", "num-format", @@ -5054,7 +5155,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5091,9 +5192,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "svm-rs" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0cc95be7cc2c384a2f57cac56548d2178650905ebe5725bc8970ccc25529060" +checksum = "20689c7d03b6461b502d0b95d6c24874c7d24dea2688af80486a130a06af3b07" dependencies = [ "dirs", "fs2", @@ -5122,9 +5223,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -5188,8 +5289,8 @@ checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.4.1", - "rustix 0.38.21", + "redox_syscall", + "rustix 0.38.26", "windows-sys 0.48.0", ] @@ -5206,9 +5307,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] @@ -5239,7 +5340,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5335,9 +5436,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.33.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ "backtrace", "bytes", @@ -5362,13 +5463,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5409,9 +5510,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" @@ -5419,18 +5520,18 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "toml_datetime", "winnow", ] [[package]] name = "toml_edit" -version = "0.20.7" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "toml_datetime", "winnow", ] @@ -5447,8 +5548,8 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "h2 0.3.21", - "http 0.2.9", + "h2 0.3.22", + "http 0.2.11", "http-body 0.4.5", "hyper 0.14.27", "hyper-timeout", @@ -5508,7 +5609,7 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http 0.2.9", + "http 0.2.11", "http-body 0.4.5", "http-range-header", "httpdate", @@ -5558,7 +5659,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5744,9 +5845,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -5755,11 +5856,11 @@ dependencies = [ [[package]] name = "uuid" -version = "1.5.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.11", ] [[package]] @@ -5890,9 +5991,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -5900,24 +6001,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ "cfg-if", "js-sys", @@ -5927,9 +6028,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5937,22 +6038,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "wasmparser" @@ -6098,9 +6199,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", @@ -6108,9 +6209,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.2" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" +checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" [[package]] name = "which" @@ -6121,7 +6222,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.21", + "rustix 0.38.26", ] [[package]] @@ -6192,6 +6293,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -6222,6 +6332,21 @@ dependencies = [ "windows_x86_64_msvc 0.48.5", ] +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -6234,6 +6359,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -6246,6 +6377,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -6258,6 +6395,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -6270,6 +6413,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -6282,6 +6431,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -6294,6 +6449,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -6306,11 +6467,17 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winnow" -version = "0.5.18" +version = "0.5.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176b6138793677221d420fd2f0aeeced263f197688b36484660da767bca2fa32" +checksum = "b7e87b8dfbe3baffbe687eef2e164e32286eff31a5ee16463ce03d991643ec94" dependencies = [ "memchr", ] @@ -6342,29 +6509,29 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "zerocopy" -version = "0.7.20" +version = "0.7.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd66a62464e3ffd4e37bd09950c2b9dd6c4f8767380fabba0d523f9a775bc85a" +checksum = "5d075cf85bbb114e933343e087b92f2146bac0d55b534cbb8188becf0039948e" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.20" +version = "0.7.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "255c4596d41e6916ced49cfafea18727b24d67878fa180ddfd69b9df34fd1726" +checksum = "86cd5ca076997b97ef09d3ad65efe811fa68c9e874cb636ccb211223a813b0c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] @@ -6377,7 +6544,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] diff --git a/lib/Cargo.toml b/lib/Cargo.toml index aaf1ed6cd82..0167a8398d9 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -18,6 +18,8 @@ lto = true vsdb = { git = "https://github.com/defich/vsdb.git" } vsdbsled = { git = "https://github.com/defich/vsdbsled.git" } ethereum = { git = "https://github.com/defich/ethereum.git" } +bitcoin = { git = "https://github.com/Jouzo/rust-bitcoin.git" } +bitcoin-io = { git = "https://github.com/Jouzo/rust-bitcoin.git" } [workspace.dependencies] @@ -115,3 +117,7 @@ lru = "0.12" #### Precompile dependencies sp-io = "24.0" substrate-bn = "0.6" + +#### Ocean dependencies +dftx-rs = { git = "https://github.com/Jouzo/dftx-rs.git" } +bitcoin = "0.31" diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index bc5204d243e..ea3c5b49e12 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -12,3 +12,6 @@ keccak-hash.workspace = true log.workspace = true serde.workspace = true thiserror.workspace = true +hex.workspace = true +dftx-rs.workspace = true +bitcoin.workspace = true diff --git a/lib/ain-ocean/src/indexer/auction.rs b/lib/ain-ocean/src/indexer/auction.rs new file mode 100644 index 00000000000..190373e576a --- /dev/null +++ b/lib/ain-ocean/src/indexer/auction.rs @@ -0,0 +1,14 @@ +use dftx_rs::{vault::PlaceAuctionBid, Transaction}; + +use super::BlockContext; +use crate::indexer::{Index, Result}; + +impl Index for PlaceAuctionBid { + fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + todo!() + } + + fn invalidate(&self) { + todo!() + } +} diff --git a/lib/ain-ocean/src/indexer/masternode.rs b/lib/ain-ocean/src/indexer/masternode.rs new file mode 100644 index 00000000000..fe90f1cb48c --- /dev/null +++ b/lib/ain-ocean/src/indexer/masternode.rs @@ -0,0 +1,83 @@ +use std::io::Write; + +use dftx_rs::{masternode::*, Transaction}; +use log::debug; + +use super::BlockContext; +use crate::{ + indexer::{Index, Result}, + model::masternode::{Masternode, MasternodeBlock}, +}; + +impl Index for CreateMasternode { + fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + debug!("[CreateMasternode] Indexing..."); + + let masternode = Masternode { + id: tx.txid().to_string(), + owner_address: tx.output[1].script_pubkey.to_hex_string(), + operator_address: tx.output[1].script_pubkey.to_hex_string(), + creation_height: context.height, + resign_height: -1, + resign_tx: None, + minted_blocks: 0, + timelock: self.timelock.0.unwrap_or_default(), + block: MasternodeBlock { + hash: context.hash.to_string(), + height: context.height, + time: context.time, + median_time: context.median_time, + }, + collateral: tx.output[1].value.to_string(), + sort: None, + history: None, + }; + + let mut file = std::fs::OpenOptions::new() + .write(true) + .create(true) + .append(true) + .open("/tmp/masternode") + .expect("Unable to open file"); + + writeln!(file, "{:?}", masternode).expect("Unable to write to file"); + + Ok(()) + } + + fn invalidate(&self) { + todo!() + } +} + +impl Index for UpdateMasternode { + fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + debug!("[UpdateMasternode] Indexing..."); + // TODO + // Get mn + // Update fields + Ok(()) + } + + fn invalidate(&self) { + // TODO + // Get mn + // Restore from history + } +} + +impl Index for ResignMasternode { + fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + debug!("[ResignMasternode] Indexing..."); + // TODO + // Get mn + // Set resign tx and resign height + Ok(()) + } + + fn invalidate(&self) { + // TODO + // Get mn + // Set resign height to -1 + } +} diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs new file mode 100644 index 00000000000..2bc71390a40 --- /dev/null +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -0,0 +1,70 @@ +mod auction; +mod masternode; +mod oracle; +mod pool; + +use dftx_rs::Transaction; + +pub(crate) type Result = std::result::Result>; + +pub(crate) trait Index { + fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()>; + fn invalidate(&self); +} + +use bitcoin::BlockHash; +use dftx_rs::{deserialize, Block, DfTx}; + +pub(crate) struct BlockContext { + height: u32, + hash: BlockHash, + time: u64, + median_time: u64, +} + +pub fn index_block(block: String, block_height: u32) -> Result<()> { + let hex = hex::decode(block)?; + let block = deserialize::(&hex)?; + + let context = BlockContext { + height: block_height, + hash: block.block_hash(), + time: 0, // TODO + median_time: 0, // TODO + }; + + for tx in block.txdata { + let bytes = tx.output[0].script_pubkey.as_bytes(); + if bytes.len() > 2 && bytes[0] == 0x6a && bytes[1] <= 0x4e { + let offset = 1 + match bytes[1] { + 0x4c => 2, + 0x4d => 3, + 0x4e => 4, + _ => 1, + }; + + let raw_tx = &bytes[offset..]; + + let dftx = deserialize::(raw_tx)?; + + match dftx { + DfTx::CreateMasternode(data) => data.index(&context, tx)?, + DfTx::UpdateMasternode(data) => data.index(&context, tx)?, + DfTx::ResignMasternode(data) => data.index(&context, tx)?, + DfTx::AppointOracle(data) => data.index(&context, tx)?, + DfTx::RemoveOracle(data) => data.index(&context, tx)?, + DfTx::UpdateOracle(data) => data.index(&context, tx)?, + DfTx::SetOracleData(data) => data.index(&context, tx)?, + DfTx::PoolSwap(data) => data.index(&context, tx)?, + DfTx::CompositeSwap(data) => data.index(&context, tx)?, + DfTx::PlaceAuctionBid(data) => data.index(&context, tx)?, + _ => (), + } + } + } + Ok(()) +} + +pub fn invalidate_block() { + todo!() +} diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs new file mode 100644 index 00000000000..950bda90352 --- /dev/null +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -0,0 +1,44 @@ +use dftx_rs::{oracles::*, Transaction}; + +use super::BlockContext; +use crate::indexer::{Index, Result}; + +impl Index for AppointOracle { + fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + todo!() + } + + fn invalidate(&self) { + todo!() + } +} + +impl Index for RemoveOracle { + fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + todo!() + } + + fn invalidate(&self) { + todo!() + } +} + +impl Index for UpdateOracle { + fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + todo!() + } + + fn invalidate(&self) { + todo!() + } +} + +impl Index for SetOracleData { + fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + todo!() + } + + fn invalidate(&self) { + todo!() + } +} diff --git a/lib/ain-ocean/src/indexer/pool.rs b/lib/ain-ocean/src/indexer/pool.rs new file mode 100644 index 00000000000..86916590516 --- /dev/null +++ b/lib/ain-ocean/src/indexer/pool.rs @@ -0,0 +1,24 @@ +use dftx_rs::{pool::*, Transaction}; + +use super::BlockContext; +use crate::indexer::{Index, Result}; + +impl Index for PoolSwap { + fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + todo!() + } + + fn invalidate(&self) { + todo!() + } +} + +impl Index for CompositeSwap { + fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + todo!() + } + + fn invalidate(&self) { + todo!() + } +} diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 7ee6252f32c..5d7ebdbaf24 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -1,6 +1,8 @@ mod api; pub mod api_paged_response; pub mod error; +mod indexer; mod model; pub use api::ocean_router; +pub use indexer::{index_block, invalidate_block}; diff --git a/lib/ain-ocean/src/model/block.rs b/lib/ain-ocean/src/model/block.rs index 96a0671d9ce..fc6ea91318d 100644 --- a/lib/ain-ocean/src/model/block.rs +++ b/lib/ain-ocean/src/model/block.rs @@ -1,7 +1,4 @@ -use serde::{Serialize, Deserialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct Block { pub id: String, pub hash: String, @@ -22,6 +19,3 @@ pub struct Block { pub size_stripped: i32, pub weight: i32, } - - - diff --git a/lib/ain-ocean/src/model/masternode.rs b/lib/ain-ocean/src/model/masternode.rs index a50978fb17a..8db67494927 100644 --- a/lib/ain-ocean/src/model/masternode.rs +++ b/lib/ain-ocean/src/model/masternode.rs @@ -1,40 +1,32 @@ -use serde::{Serialize, Deserialize}; +use bitcoin::{BlockHash, Txid}; -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug)] pub struct Masternode { pub id: String, - pub sort: String, + pub sort: Option, pub owner_address: String, pub operator_address: String, - pub creation_height: i32, + pub creation_height: u32, pub resign_height: i32, - pub resign_tx: String, + pub resign_tx: Option, pub minted_blocks: i32, - pub timelock: i32, + pub timelock: u16, pub collateral: String, pub block: MasternodeBlock, - pub history: Vec, + pub history: Option>, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug)] pub struct MasternodeBlock { pub hash: String, - pub height: i32, - pub time: i32, - pub median_time: i32, + pub height: u32, + pub time: u64, + pub median_time: u64, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug)] pub struct HistoryItem { pub txid: String, pub owner_address: String, pub operator_address: String, } - - - diff --git a/lib/ain-ocean/src/model/masternode_stats.rs b/lib/ain-ocean/src/model/masternode_stats.rs index 6f8d7fad270..b3060c4f2ac 100644 --- a/lib/ain-ocean/src/model/masternode_stats.rs +++ b/lib/ain-ocean/src/model/masternode_stats.rs @@ -1,25 +1,18 @@ -use serde::{Serialize, Deserialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct MasternodeStats { pub id: String, pub block: MasternodeStatsBlock, pub stats: MasternodeStatsStats, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct TimelockStats { pub weeks: i32, pub tvl: String, pub count: i32, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct MasternodeStatsBlock { pub hash: String, pub height: i32, @@ -27,14 +20,9 @@ pub struct MasternodeStatsBlock { pub median_time: i32, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct MasternodeStatsStats { pub count: i32, pub tvl: String, pub locked: Vec, } - - - diff --git a/lib/ain-ocean/src/model/oracle.rs b/lib/ain-ocean/src/model/oracle.rs index 71619e42184..fe3b35df4c2 100644 --- a/lib/ain-ocean/src/model/oracle.rs +++ b/lib/ain-ocean/src/model/oracle.rs @@ -1,7 +1,4 @@ -use serde::{Serialize, Deserialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct Oracle { pub id: String, pub owner_address: String, @@ -10,23 +7,16 @@ pub struct Oracle { pub block: OracleBlock, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct PriceFeedsItem { pub token: String, pub currency: String, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OracleBlock { pub hash: String, pub height: i32, pub time: i32, pub median_time: i32, } - - - diff --git a/lib/ain-ocean/src/model/oracle_history.rs b/lib/ain-ocean/src/model/oracle_history.rs index ff579bbdb39..c1155124f4e 100644 --- a/lib/ain-ocean/src/model/oracle_history.rs +++ b/lib/ain-ocean/src/model/oracle_history.rs @@ -1,7 +1,4 @@ -use serde::{Serialize, Deserialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OracleHistory { pub id: String, pub oracle_id: String, @@ -12,23 +9,16 @@ pub struct OracleHistory { pub block: OracleHistoryBlock, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct PriceFeedsItem { pub token: String, pub currency: String, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OracleHistoryBlock { pub hash: String, pub height: i32, pub time: i32, pub median_time: i32, } - - - diff --git a/lib/ain-ocean/src/model/oracle_price_active.rs b/lib/ain-ocean/src/model/oracle_price_active.rs index de3e0fdf597..4289fe01571 100644 --- a/lib/ain-ocean/src/model/oracle_price_active.rs +++ b/lib/ain-ocean/src/model/oracle_price_active.rs @@ -1,7 +1,4 @@ -use serde::{Serialize, Deserialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OraclePriceActive { pub id: String, pub key: String, @@ -12,27 +9,21 @@ pub struct OraclePriceActive { pub block: OraclePriceActiveBlock, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OraclePriceActiveActive { pub amount: String, pub weightage: i32, pub oracles: OraclePriceActiveActiveOracles, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OraclePriceActiveNext { pub amount: String, pub weightage: i32, pub oracles: OraclePriceActiveNextOracles, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OraclePriceActiveBlock { pub hash: String, pub height: i32, @@ -40,21 +31,14 @@ pub struct OraclePriceActiveBlock { pub median_time: i32, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OraclePriceActiveActiveOracles { pub active: i32, pub total: i32, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OraclePriceActiveNextOracles { pub active: i32, pub total: i32, } - - - diff --git a/lib/ain-ocean/src/model/oracle_price_aggregated.rs b/lib/ain-ocean/src/model/oracle_price_aggregated.rs index 893d1e5a7e3..c948a9c7b45 100644 --- a/lib/ain-ocean/src/model/oracle_price_aggregated.rs +++ b/lib/ain-ocean/src/model/oracle_price_aggregated.rs @@ -1,7 +1,4 @@ -use serde::{Serialize, Deserialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OraclePriceAggregated { pub id: String, pub key: String, @@ -12,18 +9,14 @@ pub struct OraclePriceAggregated { pub block: OraclePriceAggregatedBlock, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OraclePriceAggregatedAggregated { pub amount: String, pub weightage: i32, pub oracles: OraclePriceAggregatedAggregatedOracles, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OraclePriceAggregatedBlock { pub hash: String, pub height: i32, @@ -31,13 +24,8 @@ pub struct OraclePriceAggregatedBlock { pub median_time: i32, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OraclePriceAggregatedAggregatedOracles { pub active: i32, pub total: i32, } - - - diff --git a/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs index 3761a349744..6f9729fb418 100644 --- a/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs +++ b/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs @@ -1,7 +1,4 @@ -use serde::{Serialize, Deserialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OraclePriceAggregatedInterval { pub id: String, pub key: String, @@ -12,9 +9,7 @@ pub struct OraclePriceAggregatedInterval { pub block: OraclePriceAggregatedIntervalBlock, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OraclePriceAggregatedIntervalAggregated { pub amount: String, pub weightage: i32, @@ -22,9 +17,7 @@ pub struct OraclePriceAggregatedIntervalAggregated { pub oracles: OraclePriceAggregatedIntervalAggregatedOracles, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OraclePriceAggregatedIntervalBlock { pub hash: String, pub height: i32, @@ -32,13 +25,8 @@ pub struct OraclePriceAggregatedIntervalBlock { pub median_time: i32, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OraclePriceAggregatedIntervalAggregatedOracles { pub active: i32, pub total: i32, } - - - diff --git a/lib/ain-ocean/src/model/oracle_price_feed.rs b/lib/ain-ocean/src/model/oracle_price_feed.rs index b3007fbc030..122b99bf975 100644 --- a/lib/ain-ocean/src/model/oracle_price_feed.rs +++ b/lib/ain-ocean/src/model/oracle_price_feed.rs @@ -1,7 +1,4 @@ -use serde::{Serialize, Deserialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OraclePriceFeed { pub id: String, pub key: String, @@ -15,15 +12,10 @@ pub struct OraclePriceFeed { pub block: OraclePriceFeedBlock, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OraclePriceFeedBlock { pub hash: String, pub height: i32, pub time: i32, pub median_time: i32, } - - - diff --git a/lib/ain-ocean/src/model/oracle_token_currency.rs b/lib/ain-ocean/src/model/oracle_token_currency.rs index 5de605b304c..e4b431301d5 100644 --- a/lib/ain-ocean/src/model/oracle_token_currency.rs +++ b/lib/ain-ocean/src/model/oracle_token_currency.rs @@ -1,7 +1,4 @@ -use serde::{Serialize, Deserialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OracleTokenCurrency { pub id: String, pub key: String, @@ -12,15 +9,10 @@ pub struct OracleTokenCurrency { pub block: OracleTokenCurrencyBlock, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct OracleTokenCurrencyBlock { pub hash: String, pub height: i32, pub time: i32, pub median_time: i32, } - - - diff --git a/lib/ain-ocean/src/model/poolswap.rs b/lib/ain-ocean/src/model/poolswap.rs index e14ed89e82d..f6dd97ebd28 100644 --- a/lib/ain-ocean/src/model/poolswap.rs +++ b/lib/ain-ocean/src/model/poolswap.rs @@ -1,7 +1,4 @@ -use serde::{Serialize, Deserialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct PoolSwap { pub id: String, pub txid: String, @@ -13,15 +10,10 @@ pub struct PoolSwap { pub block: PoolSwapBlock, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct PoolSwapBlock { pub hash: String, pub height: i32, pub time: i32, pub median_time: i32, } - - - diff --git a/lib/ain-ocean/src/model/poolswap_aggregated.rs b/lib/ain-ocean/src/model/poolswap_aggregated.rs index 484a0a30292..90afba7ae21 100644 --- a/lib/ain-ocean/src/model/poolswap_aggregated.rs +++ b/lib/ain-ocean/src/model/poolswap_aggregated.rs @@ -1,7 +1,4 @@ -use serde::{Serialize, Deserialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct PoolSwapAggregated { pub id: String, pub key: String, @@ -10,19 +7,12 @@ pub struct PoolSwapAggregated { pub block: PoolSwapAggregatedBlock, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct PoolSwapAggregatedAggregated { pub amounts: Vec, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct PoolSwapAggregatedBlock { pub median_time: i32, } - - - diff --git a/lib/ain-ocean/src/model/price_ticker.rs b/lib/ain-ocean/src/model/price_ticker.rs index 3f9668b78f9..a9a334c4f2d 100644 --- a/lib/ain-ocean/src/model/price_ticker.rs +++ b/lib/ain-ocean/src/model/price_ticker.rs @@ -1,9 +1,6 @@ -use serde::{Deserialize, Serialize}; - use super::oracle_price_aggregated::OraclePriceAggregated; -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct PriceTicker { pub id: String, pub sort: String, diff --git a/lib/ain-ocean/src/model/raw_block.rs b/lib/ain-ocean/src/model/raw_block.rs index 9f3c2f08efd..3569073e51d 100644 --- a/lib/ain-ocean/src/model/raw_block.rs +++ b/lib/ain-ocean/src/model/raw_block.rs @@ -1,11 +1,5 @@ -use serde::{Serialize, Deserialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct RawBlock { pub id: String, pub json: String, } - - - diff --git a/lib/ain-ocean/src/model/script_activity.rs b/lib/ain-ocean/src/model/script_activity.rs index c156766a10e..6440f457c33 100644 --- a/lib/ain-ocean/src/model/script_activity.rs +++ b/lib/ain-ocean/src/model/script_activity.rs @@ -1,6 +1,4 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Default, PartialEq, Eq)] pub enum ScriptActivityType { #[default] Vin, @@ -16,7 +14,7 @@ impl ScriptActivityType { } } -#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Default, PartialEq, Eq)] pub enum ScriptActivityTypeHex { #[default] Vin, @@ -32,8 +30,7 @@ impl ScriptActivityTypeHex { } } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct ScriptActivity { pub id: String, pub hid: String, @@ -48,8 +45,7 @@ pub struct ScriptActivity { pub token_id: i32, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct ScriptActivityBlock { pub hash: String, pub height: i32, @@ -57,22 +53,19 @@ pub struct ScriptActivityBlock { pub median_time: i32, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct ScriptActivityScript { pub r#type: String, pub hex: String, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct ScriptActivityVin { pub txid: String, pub n: i32, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct ScriptActivityVout { pub txid: String, pub n: i32, diff --git a/lib/ain-ocean/src/model/script_aggregation.rs b/lib/ain-ocean/src/model/script_aggregation.rs index b5752950cd0..e0a6b838b1e 100644 --- a/lib/ain-ocean/src/model/script_aggregation.rs +++ b/lib/ain-ocean/src/model/script_aggregation.rs @@ -1,7 +1,4 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct ScriptAggregation { pub id: String, pub hid: String, @@ -11,8 +8,7 @@ pub struct ScriptAggregation { pub amount: ScriptAggregationAmount, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct ScriptAggregationBlock { pub hash: String, pub height: i32, @@ -20,23 +16,20 @@ pub struct ScriptAggregationBlock { pub median_time: i32, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct ScriptAggregationScript { pub r#type: String, pub hex: String, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct ScriptAggregationStatistic { pub tx_count: i32, pub tx_in_count: i32, pub tx_out_count: i32, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct ScriptAggregationAmount { pub tx_in: String, pub tx_out: String, diff --git a/lib/ain-ocean/src/model/script_unspent.rs b/lib/ain-ocean/src/model/script_unspent.rs index f018d9b90ad..eecbfbdecf4 100644 --- a/lib/ain-ocean/src/model/script_unspent.rs +++ b/lib/ain-ocean/src/model/script_unspent.rs @@ -1,7 +1,4 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct ScriptUnspent { pub id: String, pub hid: String, @@ -11,8 +8,7 @@ pub struct ScriptUnspent { pub vout: ScriptUnspentVout, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct ScriptUnspentBlock { pub hash: String, pub height: i32, @@ -20,15 +16,13 @@ pub struct ScriptUnspentBlock { pub median_time: i32, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct ScriptUnspentScript { pub r#type: String, pub hex: String, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct ScriptUnspentVout { pub txid: String, pub n: i32, diff --git a/lib/ain-ocean/src/model/transaction.rs b/lib/ain-ocean/src/model/transaction.rs index 341d902874f..3edcb78a8aa 100644 --- a/lib/ain-ocean/src/model/transaction.rs +++ b/lib/ain-ocean/src/model/transaction.rs @@ -1,7 +1,4 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct Transaction { pub id: String, pub order: i32, @@ -18,8 +15,7 @@ pub struct Transaction { pub vout_count: i32, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct TransactionBlock { pub hash: String, pub height: i32, diff --git a/lib/ain-ocean/src/model/transaction_vin.rs b/lib/ain-ocean/src/model/transaction_vin.rs index 704a10998ec..14081d06ff7 100644 --- a/lib/ain-ocean/src/model/transaction_vin.rs +++ b/lib/ain-ocean/src/model/transaction_vin.rs @@ -1,7 +1,4 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct TransactionVin { pub id: String, pub txid: String, @@ -12,8 +9,7 @@ pub struct TransactionVin { pub sequence: String, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct TransactionVinVout { pub id: String, pub txid: String, @@ -23,14 +19,12 @@ pub struct TransactionVinVout { pub script: TransactionVinVoutScript, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct TransactionVinScript { pub hex: String, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct TransactionVinVoutScript { pub hex: String, } diff --git a/lib/ain-ocean/src/model/transaction_vout.rs b/lib/ain-ocean/src/model/transaction_vout.rs index 7f09cebd21e..1ba65ebf989 100644 --- a/lib/ain-ocean/src/model/transaction_vout.rs +++ b/lib/ain-ocean/src/model/transaction_vout.rs @@ -1,7 +1,4 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct TransactionVout { pub id: String, pub txid: String, @@ -11,8 +8,7 @@ pub struct TransactionVout { pub script: TransactionVoutScript, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct TransactionVoutScript { pub hex: String, pub r#type: String, diff --git a/lib/ain-ocean/src/model/vault_auction_batch_history.rs b/lib/ain-ocean/src/model/vault_auction_batch_history.rs index bf39d3362b6..b2f9cae2bc1 100644 --- a/lib/ain-ocean/src/model/vault_auction_batch_history.rs +++ b/lib/ain-ocean/src/model/vault_auction_batch_history.rs @@ -1,7 +1,4 @@ -use serde::{Serialize, Deserialize}; - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct VaultAuctionBatchHistory { pub id: String, pub key: String, @@ -14,15 +11,10 @@ pub struct VaultAuctionBatchHistory { pub block: VaultAuctionBatchHistoryBlock, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Default)] pub struct VaultAuctionBatchHistoryBlock { pub hash: String, pub height: i32, pub time: i32, pub median_time: i32, } - - - diff --git a/lib/ain-rs-exports/Cargo.toml b/lib/ain-rs-exports/Cargo.toml index 80184d53c25..30a88ff7c35 100644 --- a/lib/ain-rs-exports/Cargo.toml +++ b/lib/ain-rs-exports/Cargo.toml @@ -12,6 +12,7 @@ crate-type = ["staticlib"] [dependencies] ain-evm = { path = "../ain-evm" } ain-grpc = { path = "../ain-grpc" } +ain-ocean = { path = "../ain-ocean" } ain-contracts = { path = "../ain-contracts" } ain-macros = { path = "../ain-macros" } ain-cpp-imports = { path = "../ain-cpp-imports" } diff --git a/lib/ain-rs-exports/src/core.rs b/lib/ain-rs-exports/src/core.rs index 91209548ec5..29d1cc4a232 100644 --- a/lib/ain-rs-exports/src/core.rs +++ b/lib/ain-rs-exports/src/core.rs @@ -61,3 +61,7 @@ pub fn ain_rs_wipe_evm_folder() -> Result<()> { ain_grpc::wipe_evm_folder()?; Ok(()) } + +pub fn ocean_index_block(block: String, block_height: u32) { + ain_ocean::index_block(block, block_height); +} diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index dae97502e2d..0e0c3b6dc3f 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -344,6 +344,8 @@ pub mod ffi { ); fn evm_try_flush_db(result: &mut CrossBoundaryResult); + + fn ocean_index_block(block: String, block_height: u32); } // ========= Debug ========== diff --git a/src/dfi/validation.cpp b/src/dfi/validation.cpp index a6a5da5bee0..417644f736a 100644 --- a/src/dfi/validation.cpp +++ b/src/dfi/validation.cpp @@ -2854,4 +2854,16 @@ void ProcessDeFiEvent(const CBlock &block, // construct undo FlushCacheCreateUndo(pindex, mnview, cache, uint256()); + + + // Ocean archive + const auto oceanArchive{true}; + if (oceanArchive) { + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << block; + + // Convert the serialized data to a string + std::string serializedData = HexStr(ss.begin(), ss.end()); + ocean_index_block(serializedData, pindex->nHeight); + } } From 641ed941767271801ae5ceddf8473922e1e4e37c Mon Sep 17 00:00:00 2001 From: Nagaraj <144004792+nagarajm22@users.noreply.github.com> Date: Fri, 8 Dec 2023 17:51:03 +0800 Subject: [PATCH 007/185] Ocean API: rocks db implementation for ocean API (#2728) * Added `rockdb` to ocean api. * Implementation of ocean-api database method all module. * Added data_access layer * Added test case for module. --- lib/Cargo.lock | 331 +++++++++++++++++- lib/Cargo.toml | 1 - lib/Makefile.am | 4 - lib/ain-evm/src/storage/cache.rs | 69 ++-- lib/ain-evm/src/storage/mod.rs | 12 +- lib/ain-ocean/Cargo.toml | 14 + lib/ain-ocean/README.md | 0 lib/ain-ocean/src/api/block.rs | 31 +- lib/ain-ocean/src/api_paged_response.rs | 65 ++-- lib/ain-ocean/src/data_acces/block.rs | 41 +++ lib/ain-ocean/src/data_acces/masternode.rs | 44 +++ .../src/data_acces/masternode_states.rs | 64 ++++ lib/ain-ocean/src/data_acces/mod.rs | 20 ++ lib/ain-ocean/src/data_acces/oracle.rs | 42 +++ .../src/data_acces/oracle_price_aggregated.rs | 43 +++ .../oracle_price_aggregated_interval.rs | 43 +++ .../src/data_acces/oracle_token_currency.rs | 32 ++ lib/ain-ocean/src/data_acces/order_history.rs | 33 ++ lib/ain-ocean/src/data_acces/pool_swap.rs | 31 ++ .../src/data_acces/pool_swap_aggregated.rs | 48 +++ lib/ain-ocean/src/data_acces/price_ticker.rs | 43 +++ lib/ain-ocean/src/data_acces/raw_block.rs | 40 +++ .../src/data_acces/script_activity.rs | 33 ++ .../src/data_acces/script_aggregation.rs | 44 +++ .../src/data_acces/script_unspent.rs | 33 ++ lib/ain-ocean/src/data_acces/test/mod.rs | 2 + .../src/data_acces/test/oracle_test.rs | 71 ++++ .../src/data_acces/test/transaction_test.rs | 99 ++++++ lib/ain-ocean/src/data_acces/transaction.rs | 48 +++ .../src/data_acces/transaction_vin.rs | 32 ++ .../src/data_acces/transaction_vout.rs | 44 +++ .../data_acces/vault_auction_batch_history.rs | 41 +++ lib/ain-ocean/src/database/config.rs | 36 ++ lib/ain-ocean/src/database/db_manger.rs | 282 +++++++++++++++ lib/ain-ocean/src/database/db_test.rs | 180 ++++++++++ lib/ain-ocean/src/database/mod.rs | 3 + lib/ain-ocean/src/error.rs | 8 +- lib/ain-ocean/src/lib.rs | 6 +- lib/ain-ocean/src/model/block.rs | 5 +- lib/ain-ocean/src/model/masternode.rs | 10 +- lib/ain-ocean/src/model/masternode_stats.rs | 14 +- lib/ain-ocean/src/model/oracle.rs | 11 +- lib/ain-ocean/src/model/oracle_history.rs | 11 +- .../src/model/oracle_price_active.rs | 20 +- .../src/model/oracle_price_aggregated.rs | 14 +- .../model/oracle_price_aggregated_interval.rs | 14 +- lib/ain-ocean/src/model/oracle_price_feed.rs | 8 +- .../src/model/oracle_token_currency.rs | 8 +- lib/ain-ocean/src/model/poolswap.rs | 8 +- .../src/model/poolswap_aggregated.rs | 11 +- lib/ain-ocean/src/model/price_ticker.rs | 4 +- lib/ain-ocean/src/model/raw_block.rs | 5 +- lib/ain-ocean/src/model/script_activity.rs | 16 +- lib/ain-ocean/src/model/script_aggregation.rs | 11 +- lib/ain-ocean/src/model/script_unspent.rs | 9 +- lib/ain-ocean/src/model/transaction.rs | 8 +- lib/ain-ocean/src/model/transaction_vin.rs | 9 +- lib/ain-ocean/src/model/transaction_vout.rs | 5 +- .../src/model/vault_auction_batch_history.rs | 8 +- make.sh | 22 +- src/dfi/validation.cpp | 1 - 61 files changed, 2056 insertions(+), 189 deletions(-) create mode 100644 lib/ain-ocean/README.md create mode 100644 lib/ain-ocean/src/data_acces/block.rs create mode 100644 lib/ain-ocean/src/data_acces/masternode.rs create mode 100644 lib/ain-ocean/src/data_acces/masternode_states.rs create mode 100644 lib/ain-ocean/src/data_acces/mod.rs create mode 100644 lib/ain-ocean/src/data_acces/oracle.rs create mode 100644 lib/ain-ocean/src/data_acces/oracle_price_aggregated.rs create mode 100644 lib/ain-ocean/src/data_acces/oracle_price_aggregated_interval.rs create mode 100644 lib/ain-ocean/src/data_acces/oracle_token_currency.rs create mode 100644 lib/ain-ocean/src/data_acces/order_history.rs create mode 100644 lib/ain-ocean/src/data_acces/pool_swap.rs create mode 100644 lib/ain-ocean/src/data_acces/pool_swap_aggregated.rs create mode 100644 lib/ain-ocean/src/data_acces/price_ticker.rs create mode 100644 lib/ain-ocean/src/data_acces/raw_block.rs create mode 100644 lib/ain-ocean/src/data_acces/script_activity.rs create mode 100644 lib/ain-ocean/src/data_acces/script_aggregation.rs create mode 100644 lib/ain-ocean/src/data_acces/script_unspent.rs create mode 100644 lib/ain-ocean/src/data_acces/test/mod.rs create mode 100644 lib/ain-ocean/src/data_acces/test/oracle_test.rs create mode 100644 lib/ain-ocean/src/data_acces/test/transaction_test.rs create mode 100644 lib/ain-ocean/src/data_acces/transaction.rs create mode 100644 lib/ain-ocean/src/data_acces/transaction_vin.rs create mode 100644 lib/ain-ocean/src/data_acces/transaction_vout.rs create mode 100644 lib/ain-ocean/src/data_acces/vault_auction_batch_history.rs create mode 100644 lib/ain-ocean/src/database/config.rs create mode 100644 lib/ain-ocean/src/database/db_manger.rs create mode 100644 lib/ain-ocean/src/database/db_test.rs create mode 100644 lib/ain-ocean/src/database/mod.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index f262033d95c..81b7e9a882a 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -124,7 +124,7 @@ dependencies = [ "hex", "hex-literal", "jsonrpsee-core 0.16.3", - "jsonrpsee-server", + "jsonrpsee-server 0.16.3", "jsonrpsee-types 0.16.3", "keccak-hash", "lazy_static", @@ -173,7 +173,7 @@ dependencies = [ "hex", "hyper 0.14.27", "jsonrpsee 0.16.3", - "jsonrpsee-server", + "jsonrpsee-server 0.16.3", "lazy_static", "libsecp256k1", "log", @@ -213,15 +213,29 @@ dependencies = [ name = "ain-ocean" version = "0.1.0" dependencies = [ + "anyhow", "axum 0.7.2", "bitcoin", + "bitcoin_hashes 0.12.0", + "ctrlc", "dftx-rs", + "futures", "hex", "hyper 0.14.27", + "json", + "jsonrpsee 0.20.3", "keccak-hash", "log", + "rocksdb", "serde", + "serde_json", + "structopt", + "tarpc", + "tempdir", + "tempfile", "thiserror", + "tokio", + "tokio-serde", ] [[package]] @@ -624,7 +638,7 @@ dependencies = [ "bech32", "bitcoin-internals", "bitcoin-io", - "bitcoin_hashes", + "bitcoin_hashes 0.13.0", "hex-conservative", "hex_lit", "secp256k1 0.28.0", @@ -641,6 +655,21 @@ name = "bitcoin-io" version = "0.1.0" source = "git+https://github.com/Jouzo/rust-bitcoin.git#d540306b57be5ff16b120c0e70b87512d289c262" +[[package]] +name = "bitcoin-private" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" + +[[package]] +name = "bitcoin_hashes" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" +dependencies = [ + "bitcoin-private", +] + [[package]] name = "bitcoin_hashes" version = "0.13.0" @@ -1010,6 +1039,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.3" @@ -1091,6 +1130,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "ctrlc" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" +dependencies = [ + "nix", + "windows-sys 0.48.0", +] + [[package]] name = "curve25519-dalek" version = "2.1.3" @@ -2549,6 +2598,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" + [[package]] name = "jsonrpsee" version = "0.16.3" @@ -2557,8 +2612,8 @@ checksum = "367a292944c07385839818bb71c8d76611138e2dedb0677d035b8da21d29c78b" dependencies = [ "jsonrpsee-core 0.16.3", "jsonrpsee-http-client 0.16.3", - "jsonrpsee-proc-macros", - "jsonrpsee-server", + "jsonrpsee-proc-macros 0.16.3", + "jsonrpsee-server 0.16.3", "jsonrpsee-types 0.16.3", "tracing", ] @@ -2574,6 +2629,21 @@ dependencies = [ "jsonrpsee-types 0.18.2", ] +[[package]] +name = "jsonrpsee" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "affdc52f7596ccb2d7645231fc6163bb314630c989b64998f3699a28b4d5d4dc" +dependencies = [ + "jsonrpsee-core 0.20.3", + "jsonrpsee-http-client 0.20.3", + "jsonrpsee-proc-macros 0.20.3", + "jsonrpsee-server 0.20.3", + "jsonrpsee-types 0.20.3", + "tokio", + "tracing", +] + [[package]] name = "jsonrpsee-core" version = "0.16.3" @@ -2619,6 +2689,29 @@ dependencies = [ "tracing", ] +[[package]] +name = "jsonrpsee-core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2327ba8df2fdbd5e897e2b5ed25ce7f299d345b9736b6828814c3dbd1fd47b" +dependencies = [ + "anyhow", + "async-trait", + "beef", + "futures-util", + "hyper 0.14.27", + "jsonrpsee-types 0.20.3", + "parking_lot", + "rand 0.8.5", + "rustc-hash", + "serde", + "serde_json", + "soketto", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "jsonrpsee-http-client" version = "0.16.3" @@ -2657,6 +2750,26 @@ dependencies = [ "tracing", ] +[[package]] +name = "jsonrpsee-http-client" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f80c17f62c7653ce767e3d7288b793dfec920f97067ceb189ebdd3570f2bc20" +dependencies = [ + "async-trait", + "hyper 0.14.27", + "hyper-rustls", + "jsonrpsee-core 0.20.3", + "jsonrpsee-types 0.20.3", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", + "url", +] + [[package]] name = "jsonrpsee-proc-macros" version = "0.16.3" @@ -2670,6 +2783,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "jsonrpsee-proc-macros" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29110019693a4fa2dbda04876499d098fa16d70eba06b1e6e2b3f1b251419515" +dependencies = [ + "heck 0.4.1", + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "jsonrpsee-server" version = "0.16.3" @@ -2692,6 +2818,29 @@ dependencies = [ "tracing", ] +[[package]] +name = "jsonrpsee-server" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c39a00449c9ef3f50b84fc00fc4acba20ef8f559f07902244abf4c15c5ab9c" +dependencies = [ + "futures-util", + "http 0.2.11", + "hyper 0.14.27", + "jsonrpsee-core 0.20.3", + "jsonrpsee-types 0.20.3", + "route-recognizer", + "serde", + "serde_json", + "soketto", + "thiserror", + "tokio", + "tokio-stream", + "tokio-util", + "tower", + "tracing", +] + [[package]] name = "jsonrpsee-types" version = "0.16.3" @@ -2720,6 +2869,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "jsonrpsee-types" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be0be325642e850ed0bdff426674d2e66b2b7117c9be23a7caef68a2902b7d9" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", + "tracing", +] + [[package]] name = "k256" version = "0.13.2" @@ -2872,6 +3035,7 @@ dependencies = [ "glob", "libc", "libz-sys", + "lz4-sys", "zstd-sys", ] @@ -2980,6 +3144,16 @@ dependencies = [ "hashbrown 0.14.3", ] +[[package]] +name = "lz4-sys" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "mach" version = "0.3.2" @@ -3176,6 +3350,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "libc", +] + [[package]] name = "nohash-hasher" version = "0.2.0" @@ -3380,6 +3565,49 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "opentelemetry" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d6c3d7288a106c0a363e4b0e8d308058d56902adefb16f4936f417ffef086e" +dependencies = [ + "opentelemetry_api", + "opentelemetry_sdk", +] + +[[package]] +name = "opentelemetry_api" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c24f96e21e7acc813c7a8394ee94978929db2bcc46cf6b5014fc612bf7760c22" +dependencies = [ + "futures-channel", + "futures-util", + "indexmap 1.9.3", + "js-sys", + "once_cell", + "pin-project-lite", + "thiserror", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca41c4933371b61c2a2f214bf16931499af4ec90543604ec828f7a625c09113" +dependencies = [ + "async-trait", + "crossbeam-channel", + "futures-channel", + "futures-executor", + "futures-util", + "once_cell", + "opentelemetry_api", + "percent-encoding", + "rand 0.8.5", + "thiserror", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -4157,6 +4385,12 @@ dependencies = [ "librocksdb-sys", ] +[[package]] +name = "route-recognizer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" + [[package]] name = "ruc" version = "4.2.1" @@ -4419,7 +4653,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2acea373acb8c21ecb5a23741452acd2593ed44ee3d343e72baaa143bc89d0d5" dependencies = [ - "bitcoin_hashes", + "bitcoin_hashes 0.13.0", "secp256k1-sys 0.9.0", ] @@ -4664,6 +4898,15 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + [[package]] name = "signature" version = "1.6.4" @@ -4981,7 +5224,7 @@ dependencies = [ "sp-std", "tracing", "tracing-core", - "tracing-subscriber", + "tracing-subscriber 0.2.25", ] [[package]] @@ -5271,6 +5514,41 @@ version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" +[[package]] +name = "tarpc" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f41bce44d290df0598ae4b9cd6ea7f58f651fd3aa4af1b26060c4fa32b08af7" +dependencies = [ + "anyhow", + "fnv", + "futures", + "humantime", + "opentelemetry", + "pin-project", + "rand 0.8.5", + "serde", + "static_assertions", + "tarpc-plugins", + "thiserror", + "tokio", + "tokio-serde", + "tokio-util", + "tracing", + "tracing-opentelemetry", +] + +[[package]] +name = "tarpc-plugins" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee42b4e559f17bce0385ebf511a7beb67d5cc33c12c96b7f4e9789919d9c10f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "tempdir" version = "0.3.7" @@ -5445,7 +5723,9 @@ dependencies = [ "libc", "mio", "num_cpus", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2 0.5.5", "tokio-macros", "windows-sys 0.48.0", @@ -5482,6 +5762,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-serde" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "911a61637386b789af998ee23f50aa30d5fd7edcec8d6d3dedae5e5815205466" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project", +] + [[package]] name = "tokio-stream" version = "0.1.14" @@ -5504,6 +5796,7 @@ dependencies = [ "futures-io", "futures-sink", "pin-project-lite", + "slab", "tokio", "tracing", ] @@ -5683,6 +5976,19 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-opentelemetry" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21ebb87a95ea13271332df069020513ab70bdb5637ca42d6e492dc3bbbad48de" +dependencies = [ + "once_cell", + "opentelemetry", + "tracing", + "tracing-core", + "tracing-subscriber 0.3.18", +] + [[package]] name = "tracing-serde" version = "0.1.3" @@ -5715,6 +6021,17 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + [[package]] name = "trie-db" version = "0.27.1" diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 0167a8398d9..d25737a1d76 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -79,7 +79,6 @@ jsonrpsee-server = "0.16" jsonrpsee-types = "0.16" axum = { version = "0.7.1", features = ["macros"] } - tempdir = "0.3" rocksdb = { version = "0.21", default-features = false } diff --git a/lib/Makefile.am b/lib/Makefile.am index 917309aa17a..39e5255d6eb 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -71,10 +71,6 @@ check: test: $(CARGO) test $(CARGO_MANIFEST_ARG) $(CARGO_EXTRA_ARGS) -.PHONY: clippy -clippy: - $(CARGO) clippy $(CARGO_MANIFEST_ARG) $(CARGO_EXTRA_ARGS) -- -Dwarnings - .PHONY: doc doc: $(CARGO) doc $(CARGO_MANIFEST_ARG) diff --git a/lib/ain-evm/src/storage/cache.rs b/lib/ain-evm/src/storage/cache.rs index 2c81ce46625..b645cdc5bdf 100644 --- a/lib/ain-evm/src/storage/cache.rs +++ b/lib/ain-evm/src/storage/cache.rs @@ -3,18 +3,16 @@ use std::{borrow::ToOwned, num::NonZeroUsize, sync::RwLock}; use ethereum::{BlockAny, TransactionV2}; use ethereum_types::{H256, U256}; use lru::LruCache; -use parking_lot::Mutex; use super::traits::{BlockStorage, Rollback, TransactionStorage}; use crate::Result; #[derive(Debug)] pub struct Cache { - transactions: Mutex>, - blocks: Mutex>, - block_hashes: Mutex>, + transactions: RwLock>, + blocks: RwLock>, + block_hashes: RwLock>, latest_block: RwLock>, - contract_code: Mutex>>, } impl Cache { @@ -22,16 +20,13 @@ impl Cache { pub fn new(cache_size: Option) -> Self { Cache { - transactions: Mutex::new(LruCache::new( + transactions: RwLock::new(LruCache::new( NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), )), - blocks: Mutex::new(LruCache::new( + blocks: RwLock::new(LruCache::new( NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), )), - block_hashes: Mutex::new(LruCache::new( - NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), - )), - contract_code: Mutex::new(LruCache::new( + block_hashes: RwLock::new(LruCache::new( NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), )), latest_block: RwLock::new(None), @@ -41,13 +36,19 @@ impl Cache { impl BlockStorage for Cache { fn get_block_by_number(&self, number: &U256) -> Result> { - let block = self.blocks.lock().get(number).map(ToOwned::to_owned); + let block = self + .blocks + .write() + .unwrap() + .get(number) + .map(ToOwned::to_owned); Ok(block) } fn get_block_by_hash(&self, block_hash: &H256) -> Result> { self.block_hashes - .lock() + .write() + .unwrap() .get(block_hash) .map_or(Ok(None), |block_number| { self.get_block_by_number(block_number) @@ -59,8 +60,11 @@ impl BlockStorage for Cache { let block_number = block.header.number; let hash = block.header.hash(); - self.blocks.lock().put(block_number, block.clone()); - self.block_hashes.lock().put(hash, block_number); + self.blocks + .write() + .unwrap() + .put(block_number, block.clone()); + self.block_hashes.write().unwrap().put(hash, block_number); Ok(()) } @@ -83,7 +87,7 @@ impl BlockStorage for Cache { impl TransactionStorage for Cache { fn extend_transactions_from_block(&self, block: &BlockAny) -> Result<()> { - let mut cache = self.transactions.lock(); + let mut cache = self.transactions.write().unwrap(); for transaction in &block.transactions { let hash = transaction.hash(); @@ -93,7 +97,12 @@ impl TransactionStorage for Cache { } fn get_transaction_by_hash(&self, hash: &H256) -> Result> { - let transaction = self.transactions.lock().get(hash).map(ToOwned::to_owned); + let transaction = self + .transactions + .write() + .unwrap() + .get(hash) + .map(ToOwned::to_owned); Ok(transaction) } @@ -103,7 +112,8 @@ impl TransactionStorage for Cache { index: usize, ) -> Result> { self.block_hashes - .lock() + .write() + .unwrap() .get(block_hash) .map_or(Ok(None), |block_number| { self.get_transaction_by_block_number_and_index(block_number, index) @@ -117,7 +127,8 @@ impl TransactionStorage for Cache { ) -> Result> { let transaction = self .blocks - .lock() + .write() + .unwrap() .get(block_number) .and_then(|block| block.transactions.get(index).map(ToOwned::to_owned)); Ok(transaction) @@ -125,7 +136,8 @@ impl TransactionStorage for Cache { fn put_transaction(&self, transaction: &TransactionV2) -> Result<()> { self.transactions - .lock() + .write() + .unwrap() .put(transaction.hash(), transaction.clone()); Ok(()) } @@ -134,13 +146,13 @@ impl TransactionStorage for Cache { impl Rollback for Cache { fn disconnect_latest_block(&self) -> Result<()> { if let Some(block) = self.get_latest_block()? { - let mut transaction_cache = self.transactions.lock(); + let mut transaction_cache = self.transactions.write().unwrap(); for tx in &block.transactions { transaction_cache.pop(&tx.hash()); } - self.block_hashes.lock().pop(&block.header.hash()); - self.blocks.lock().pop(&block.header.number); + self.block_hashes.write().unwrap().pop(&block.header.hash()); + self.blocks.write().unwrap().pop(&block.header.number); let previous_block = self.get_block_by_hash(&block.header.parent_hash)?; self.put_latest_block(previous_block.as_ref())?; @@ -148,14 +160,3 @@ impl Rollback for Cache { Ok(()) } } - -impl Cache { - pub fn get_code_by_hash(&self, hash: &H256) -> Result>> { - Ok(self.contract_code.lock().get(hash).map(ToOwned::to_owned)) - } - - pub fn put_code(&self, hash: H256, code: &[u8]) -> Result<()> { - self.contract_code.lock().put(hash, code.to_vec()); - Ok(()) - } -} diff --git a/lib/ain-evm/src/storage/mod.rs b/lib/ain-evm/src/storage/mod.rs index 00f5eda18dc..d3ee93c5b9a 100644 --- a/lib/ain-evm/src/storage/mod.rs +++ b/lib/ain-evm/src/storage/mod.rs @@ -193,17 +193,7 @@ impl FlushableStorage for Storage { impl Storage { pub fn get_code_by_hash(&self, address: H160, hash: H256) -> Result>> { - match self.cache.get_code_by_hash(&hash) { - Ok(Some(code)) => Ok(Some(code)), - Ok(None) => { - let code = self.blockstore.get_code_by_hash(address, &hash); - if let Ok(Some(ref code)) = code { - self.cache.put_code(hash, code)?; - } - code - } - Err(e) => Err(e), - } + self.blockstore.get_code_by_hash(address, &hash) } pub fn put_code( diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index ea3c5b49e12..a695e522ca2 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -15,3 +15,17 @@ thiserror.workspace = true hex.workspace = true dftx-rs.workspace = true bitcoin.workspace = true +tarpc = { version = "0.33", features = ["tokio1", "serde1", "serde-transport","tcp"] } +tokio = { version = "1", features = ["full"] } +serde_json = "1.0" +json = "0.12.4" +tokio-serde = {version="0.8.0"} +futures = "0.3.29" +jsonrpsee = { version = "0.20.3", features = ["server", "macros", "http-client", "jsonrpsee-server"] } +rocksdb = "0.21.0" +ctrlc = "3.1.9" +tempdir = "0.3.7" +bitcoin_hashes = "0.12.0" +structopt = { version = "0.3", default-features = false } +tempfile = "3.8.1" +anyhow.workspace = true diff --git a/lib/ain-ocean/README.md b/lib/ain-ocean/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 142d379dcec..80c8191b903 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -1,4 +1,9 @@ -use axum::{debug_handler, extract::{Path, Query}, Json, routing::get, Router}; +use axum::{ + debug_handler, + extract::{Path, Query}, + routing::get, + Json, Router, +}; use serde::{Deserialize, Serialize}; use crate::api_paged_response::ApiPagedResponse; @@ -16,7 +21,7 @@ struct BlockHash { #[derive(Deserialize)] pub struct ListBlocksQuery { pub size: usize, - pub next: Option + pub next: Option, } #[debug_handler] @@ -28,14 +33,10 @@ async fn list_blocks(Query(query): Query) -> Json) -> String { @@ -60,24 +61,24 @@ pub struct Block { // TODO(): type mapping // hash: H256, // previous_hash: H256, - + // height: u64, // version: u64, // time: u64, // ---------------| block time in seconds since epoch // median_time: u64, // --------| meidan time of the past 11 block timestamps - + // transaction_count: u64, // difficulty: u64, - + // masternode: H256, // minter: H256, // minter_block_count: u64, // reward: f64 - + // state_modifier: H256, // merkle_root: H256, - + // size: u64, // size_stripped: u64, // weight: u64, diff --git a/lib/ain-ocean/src/api_paged_response.rs b/lib/ain-ocean/src/api_paged_response.rs index 83ac978df99..24a877707f6 100644 --- a/lib/ain-ocean/src/api_paged_response.rs +++ b/lib/ain-ocean/src/api_paged_response.rs @@ -5,17 +5,17 @@ use serde::Serialize; /// Each ApiPagedResponse holds the data array and the "token" for next part of the slice. /// The next token should be passed via query 'next' and only used when getting the next slice. /// Hence the first request, the next token is always empty and not provided. -/// +/// /// With ascending sorted list and a limit of 3 items per slice will have the behaviour as such. -/// +/// /// SORTED : | [1] [2] [3] | [4] [5] [6] | [7] [8] [9] | [10] /// Query 1 : Data: [1] [2] [3], Next: 3, Operator: GT (>) /// Query 2 : Data: [4] [5] [6], Next: 6, Operator: GT (>) /// Query 3 : Data: [7] [8] [9], Next: 3, Operator: GT (>) /// Query 4 : Data: [10], Next: undefined -/// +/// /// This design is resilient also mutating sorted list, where pagination is not. -/// +/// /// SORTED : [2] [4] [6] [8] [10] [12] [14] /// Query 1 : Data: [2] [4] [6], Next: 6, Operator: GT (>) /// @@ -27,7 +27,7 @@ use serde::Serialize; /// Limitations of this requires your dat astructure to always be sorted in one direction and your sort /// indexes always fixed. Hence the moving down of the slice window, your operator will be greater than (GT). /// While moving up your operator will be less than (GT). -/// +/// /// ASC : | [1] [2] [3] | [4] [5] [6] | [7] [8] [9] | /// >3 >6 >9 /// DESC : | [9] [8] [7] | [6] [5] [4] | [3] [2] [1] | @@ -37,15 +37,15 @@ use serde::Serialize; /// when the usage narrative is clear and so will the use of ease. LIST query must be dead simple. /// Image travelling down the path, and getting a "next token" to get the next set of itmes to /// continue walking. -/// +/// /// Because the limit is not part of the slice window your query mechanism should support varying size windows. -/// +/// /// DATA: | [1] [2] [3] | [4] [5] [6] [7] | [8] [9] | ... /// | limit 3, >3 | limit 4, >7 | limit 2, >9 /// For simplicity your API should not attempt to allow access to different sort indexes, be cognizant of /// how our APIs are consumed. If we create a GET /blocks operation to list blocks what would the correct indexes /// be 99% of the time? -/// +/// /// Answer: Blocks sorted by height in descending order, that's your sorted list and your slice window. /// : <- Latest | [100] [99] [98] [97] [...] | Oldest -> /// @@ -62,7 +62,12 @@ struct ApiPage { impl ApiPagedResponse { pub fn new(data: Vec, next: Option<&str>) -> Self { - Self { data, page: ApiPage{ next: next.map(Into::into) } } // Option<&str> -> Option + Self { + data, + page: ApiPage { + next: next.map(Into::into), + }, + } // Option<&str> -> Option } pub fn next(data: Vec, next: Option<&str>) -> Self { @@ -77,7 +82,7 @@ impl ApiPagedResponse { Self::next(data, None) } } - + pub fn empty() -> Self { Self::new(Vec::new(), None) } @@ -85,14 +90,14 @@ impl ApiPagedResponse { #[cfg(test)] mod tests { - use super::{ApiPagedResponse, ApiPage}; - + use super::{ApiPage, ApiPagedResponse}; + #[derive(Clone, Debug)] struct Item { id: String, sort: String, } - + impl Item { fn new(id: &str, sort: &str) -> Self { Self { @@ -101,25 +106,19 @@ mod tests { } } } - + #[test] fn should_next_with_none() { - let items: Vec = vec![ - Item::new("0", "a"), - Item::new("1", "b"), - ]; - + let items: Vec = vec![Item::new("0", "a"), Item::new("1", "b")]; + let next = ApiPagedResponse::next(items, None).page.next; assert_eq!(next, None); } #[test] fn should_next_with_value() { - let items: Vec = vec![ - Item::new("0", "a"), - Item::new("1", "b"), - ]; - + let items: Vec = vec![Item::new("0", "a"), Item::new("1", "b")]; + let next = ApiPagedResponse::next(items, Some("b")).page.next; assert_eq!(next, Some("b".into())); } @@ -131,20 +130,18 @@ mod tests { Item::new("1", "b"), Item::new("2", "c"), ]; - - let next = ApiPagedResponse::of(items, 3, |item| item.clone().sort).page.next; + + let next = ApiPagedResponse::of(items, 3, |item| item.clone().sort) + .page + .next; assert_eq!(next, Some("c".into())) } - + #[test] fn should_not_create_with_limit_3_while_size_2() { - let items: Vec = vec![ - Item::new("0", "a"), - Item::new("1", "b"), - ]; - + let items: Vec = vec![Item::new("0", "a"), Item::new("1", "b")]; + let page = ApiPagedResponse::of(items, 3, |item| item.clone().sort).page; - assert_eq!(page, ApiPage{next: None}) + assert_eq!(page, ApiPage { next: None }) } - } diff --git a/lib/ain-ocean/src/data_acces/block.rs b/lib/ain-ocean/src/data_acces/block.rs new file mode 100644 index 00000000000..200fd033f77 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/block.rs @@ -0,0 +1,41 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::block::Block; +use anyhow::{anyhow, Result}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug)] +pub struct BlockDb { + pub db: RocksDB, +} + +impl BlockDb { + pub async fn get_by_hash(&self) -> Result { + todo!() + } + pub async fn get_by_height(&self) -> Result { + todo!() + } + pub async fn get_heighest(&self) -> Result { + todo!() + } + pub async fn query_by_height(&self, limit: i32, lt: i32) -> Result> { + todo!() + } + pub async fn store_block(&self, block: Block) -> Result<()> { + match serde_json::to_string(&block) { + Ok(value) => { + let key = block.id.clone(); + self.db.put("raw_block", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete_block(&self, hash: String) -> Result<()> { + match self.db.delete("raw_block", hash.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/masternode.rs b/lib/ain-ocean/src/data_acces/masternode.rs new file mode 100644 index 00000000000..918a51ff0c6 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/masternode.rs @@ -0,0 +1,44 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::masternode::Masternode; +use anyhow::{anyhow, Result}; +use serde::{Deserialize, Serialize}; +use serde_json; + +pub struct MasterNodeDB { + pub db: RocksDB, +} + +impl MasterNodeDB { + pub async fn query(&self, limit: i32, lt: i32) -> Result> { + todo!() + } + pub async fn get(&self, id: String) -> Result> { + match self.db.get("masternode", id.as_bytes()) { + Ok(Some(value)) => { + let master_node: Masternode = + serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; + Ok(Some(master_node)) + } + Ok(None) => Ok(None), + Err(e) => Err(anyhow!(e)), + } + } + pub async fn store(&self, stats: Masternode) -> Result<()> { + match serde_json::to_string(&stats) { + Ok(value) => { + let key = stats.id.clone(); + self.db + .put("masternode", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self.db.delete("masternode", id.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/masternode_states.rs b/lib/ain-ocean/src/data_acces/masternode_states.rs new file mode 100644 index 00000000000..1ab26b45872 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/masternode_states.rs @@ -0,0 +1,64 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::masternode_stats::MasternodeStats; +use anyhow::{anyhow, Result}; +use bitcoin::absolute::Height; +use rocksdb::{ColumnFamilyDescriptor, IteratorMode, DB}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug)] +pub struct MasterStatsDb { + pub db: RocksDB, +} +impl MasterStatsDb { + pub async fn get_latest(&self) -> Result { + // let mut latest_stats: Option = None; + // let mut highest_height = -1; + + // let iter = self.db.iterator("masternode_stats", IteratorMode::End); // Start from the end of the DB + + // for (key, value) in iter { + // let stats: MasternodeStats = serde_json::from_slice(&value)?; + // if stats.block.height > highest_height { + // highest_height = stats.block.height; + // latest_stats = Some(stats); + // } + // } + + // Ok(latest_stats); + todo!() + } + pub async fn query(&self, limit: i32, lt: i32) -> Result> { + todo!() + } + pub async fn get(&self, height: i32) -> Result> { + let bytes: &[u8] = &height.to_be_bytes(); + match self.db.get("masternode_stats", bytes) { + Ok(Some(value)) => { + let master_states: MasternodeStats = + serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; + Ok(Some(master_states)) + } + Ok(None) => Ok(None), + Err(e) => Err(anyhow!(e)), + } + } + pub async fn store(&self, stats: MasternodeStats) -> Result<()> { + match serde_json::to_string(&stats) { + Ok(value) => { + let key = stats.block.height.clone(); + let bytes: &[u8] = &key.to_be_bytes(); + self.db.put("masternode_stats", bytes, value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, height: i32) -> Result<()> { + let bytes: &[u8] = &height.to_be_bytes(); + match self.db.delete("masternode_stats", bytes) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/mod.rs b/lib/ain-ocean/src/data_acces/mod.rs new file mode 100644 index 00000000000..4072333a14e --- /dev/null +++ b/lib/ain-ocean/src/data_acces/mod.rs @@ -0,0 +1,20 @@ +pub mod block; +pub mod masternode; +pub mod masternode_states; +pub mod oracle; +pub mod oracle_price_aggregated; +pub mod oracle_price_aggregated_interval; +pub mod oracle_token_currency; +pub mod order_history; +pub mod pool_swap; +pub mod pool_swap_aggregated; +pub mod price_ticker; +pub mod raw_block; +pub mod script_activity; +pub mod script_aggregation; +pub mod script_unspent; +pub mod test; +pub mod transaction; +pub mod transaction_vin; +pub mod transaction_vout; +pub mod vault_auction_batch_history; diff --git a/lib/ain-ocean/src/data_acces/oracle.rs b/lib/ain-ocean/src/data_acces/oracle.rs new file mode 100644 index 00000000000..8bee24254b9 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/oracle.rs @@ -0,0 +1,42 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::oracle::Oracle; +use anyhow::{anyhow, Error, Result}; +use serde::{Deserialize, Serialize}; +use serde_json; + +pub struct OracleDb { + pub db: RocksDB, +} + +impl OracleDb { + pub async fn query(&self, limit: i32, lt: String) -> Result> { + todo!() + } + pub async fn store(&self, oracle: Oracle) -> Result<()> { + match serde_json::to_string(&oracle) { + Ok(value) => { + let key = oracle.id.clone(); + self.db.put("oracle", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn get(&self, id: String) -> Result> { + match self.db.get("oracle", id.as_bytes()) { + Ok(Some(value)) => { + let oracle: Oracle = serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; + Ok(Some(oracle)) + } + Ok(None) => Ok(None), + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self.db.delete("oracle", id.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/oracle_price_aggregated.rs b/lib/ain-ocean/src/data_acces/oracle_price_aggregated.rs new file mode 100644 index 00000000000..a16719eebe1 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/oracle_price_aggregated.rs @@ -0,0 +1,43 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::oracle_price_aggregated::OraclePriceAggregated; +use anyhow::{anyhow, Result}; +use serde::{Deserialize, Serialize}; + +pub struct OraclePriceAggrigatedDb { + pub db: RocksDB, +} + +impl OraclePriceAggrigatedDb { + pub async fn query( + &self, + key: String, + limit: i32, + lt: String, + ) -> Result> { + todo!() + } + pub async fn put(&self, oracle: OraclePriceAggregated) -> Result<()> { + match serde_json::to_string(&oracle) { + Ok(value) => { + let key = oracle.id.clone(); + self.db + .put("oracle_price_aggregated", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn get(&self, id: String) -> Option { + match self.db.get("oracle_price_aggregated", id.as_bytes()) { + Ok(Some(value)) => serde_json::from_slice(&value).ok(), + _ => None, + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self.db.delete("oracle_price_aggregated", id.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/data_acces/oracle_price_aggregated_interval.rs new file mode 100644 index 00000000000..109b44ed5fd --- /dev/null +++ b/lib/ain-ocean/src/data_acces/oracle_price_aggregated_interval.rs @@ -0,0 +1,43 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::oracle_price_aggregated_interval::OraclePriceAggregatedInterval; +use anyhow::{anyhow, Result}; +use serde::{Deserialize, Serialize}; + +pub struct OraclePriceAggregatedIntervalDb { + pub db: RocksDB, +} + +impl OraclePriceAggregatedIntervalDb { + pub async fn query( + &self, + key: String, + limit: i32, + lt: String, + ) -> Result> { + todo!() + } + pub async fn put(&self, oracle: OraclePriceAggregatedInterval) -> Result<()> { + match serde_json::to_string(&oracle) { + Ok(value) => { + let key = oracle.id.clone(); + self.db.put( + "oracle_price_aggregated_interval", + key.as_bytes(), + value.as_bytes(), + )?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self + .db + .delete("oracle_price_aggregated_interval", id.as_bytes()) + { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/oracle_token_currency.rs b/lib/ain-ocean/src/data_acces/oracle_token_currency.rs new file mode 100644 index 00000000000..f920f9b7d88 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/oracle_token_currency.rs @@ -0,0 +1,32 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::oracle_token_currency::OracleTokenCurrency; +use anyhow::{anyhow, Result}; +use serde::{Deserialize, Serialize}; + +pub struct OracleTokenCurrencyDb { + pub db: RocksDB, +} + +impl OracleTokenCurrencyDb { + pub async fn query(&self, limit: i32, lt: String) -> Result> { + todo!() + } + pub async fn put(&self, oracle_token: OracleTokenCurrency) -> Result<()> { + match serde_json::to_string(&oracle_token) { + Ok(value) => { + let key = oracle_token.id.clone(); + self.db + .put("oracle_token_currency", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self.db.delete("oracle_token_currency", id.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/order_history.rs b/lib/ain-ocean/src/data_acces/order_history.rs new file mode 100644 index 00000000000..abe2f673fa1 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/order_history.rs @@ -0,0 +1,33 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::oracle_history::OracleHistory; +use anyhow::{anyhow, Result}; +use serde::{Deserialize, Serialize}; + +pub struct OracleHistoryDB { + pub db: RocksDB, +} + +impl OracleHistoryDB { + pub async fn query(&self, oracleId: String, limit: i32, lt: String) -> Result { + todo!() + } + + pub async fn store(&self, oracle_history: OracleHistory) -> Result<()> { + match serde_json::to_string(&oracle_history) { + Ok(value) => { + let key = oracle_history.id.clone(); + self.db + .put("oracle_history", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self.db.delete("oracle_history", id.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/pool_swap.rs b/lib/ain-ocean/src/data_acces/pool_swap.rs new file mode 100644 index 00000000000..f61078f5272 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/pool_swap.rs @@ -0,0 +1,31 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::poolswap::PoolSwap; +use anyhow::{anyhow, Result}; +use serde::{Deserialize, Serialize}; + +pub struct PoolSwapDb { + pub db: RocksDB, +} + +impl PoolSwapDb { + pub async fn query(&self, key: String, limit: i32, lt: String) -> Result> { + todo!() + } + pub async fn put(&self, swap: PoolSwap) -> Result<()> { + match serde_json::to_string(&swap) { + Ok(value) => { + let key = swap.id.clone(); + self.db.put("pool_swap", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self.db.delete("pool_swap", id.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/pool_swap_aggregated.rs b/lib/ain-ocean/src/data_acces/pool_swap_aggregated.rs new file mode 100644 index 00000000000..45f756f410d --- /dev/null +++ b/lib/ain-ocean/src/data_acces/pool_swap_aggregated.rs @@ -0,0 +1,48 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::poolswap_aggregated::PoolSwapAggregated; +use anyhow::{anyhow, Result}; +use serde::{Deserialize, Serialize}; + +pub struct PoolSwapAggregatedDb { + pub db: RocksDB, +} + +impl PoolSwapAggregatedDb { + pub async fn query( + &self, + key: String, + limit: i32, + lt: String, + ) -> Result<(Vec)> { + todo!() + } + pub async fn put(&self, aggregated: PoolSwapAggregated) -> Result<()> { + match serde_json::to_string(&aggregated) { + Ok(value) => { + let key = aggregated.id.clone(); + self.db + .put("pool_swap_aggregated", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn get(&self, id: String) -> Result { + match self.db.get("pool_swap_aggregated", id.as_bytes()) { + Ok(Some(value)) => { + let pool_swap: PoolSwapAggregated = + serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; + Ok(pool_swap) + } + Ok(None) => Err(anyhow!("No data found for the given ID")), + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self.db.delete("pool_swap_aggregated", id.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/price_ticker.rs b/lib/ain-ocean/src/data_acces/price_ticker.rs new file mode 100644 index 00000000000..e1987dde9bd --- /dev/null +++ b/lib/ain-ocean/src/data_acces/price_ticker.rs @@ -0,0 +1,43 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::price_ticker::PriceTicker; +use anyhow::{anyhow, Result}; +use serde::{Deserialize, Serialize}; + +pub struct price_ticker { + pub db: RocksDB, +} + +impl price_ticker { + pub async fn query(&self, limit: i32, lt: String) -> Result> { + todo!() + } + pub async fn get(&self, id: String) -> Result { + match self.db.get("price_ticker", id.as_bytes()) { + Ok(Some(value)) => { + let pool_swap: PriceTicker = + serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; + Ok(pool_swap) + } + Ok(None) => Err(anyhow!("No data found for the given ID")), + Err(e) => Err(anyhow!(e)), + } + } + pub async fn put(&self, price: PriceTicker) -> Result<()> { + match serde_json::to_string(&price) { + Ok(value) => { + let key = price.id.clone(); + self.db + .put("price_ticker", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self.db.delete("price_ticker", id.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/raw_block.rs b/lib/ain-ocean/src/data_acces/raw_block.rs new file mode 100644 index 00000000000..f859fc80f57 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/raw_block.rs @@ -0,0 +1,40 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::raw_block::RawBlock; +use anyhow::{anyhow, Result}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug)] +pub struct RawBlockDb { + pub db: RocksDB, +} + +impl RawBlockDb { + pub async fn get(&self, hash: String) -> Result> { + match self.db.get("raw_block", hash.as_bytes()) { + Ok(Some(value)) => { + let trx: RawBlock = serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; + Ok(Some(trx)) + } + Ok(None) => Ok(None), + Err(e) => Err(anyhow!(e)), + } + } + + pub async fn store(&self, block: RawBlock) -> Result<()> { + match serde_json::to_string(&block) { + Ok(value) => { + let key = block.id.clone(); + self.db.put("raw_block", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, hash: String) -> Result<()> { + match self.db.delete("raw_block", hash.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/script_activity.rs b/lib/ain-ocean/src/data_acces/script_activity.rs new file mode 100644 index 00000000000..fcdc9985fdc --- /dev/null +++ b/lib/ain-ocean/src/data_acces/script_activity.rs @@ -0,0 +1,33 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::script_activity::ScriptActivity; +use anyhow::{anyhow, Error, Result}; +use serde::{Deserialize, Serialize}; +use serde_json; + +pub struct ScriptUnspentDB { + pub db: RocksDB, +} + +impl ScriptUnspentDB { + pub async fn query(&self, limit: i32, lt: String) -> Result> { + todo!() + } + pub async fn store(&self, unspent: ScriptActivity) -> Result<()> { + match serde_json::to_string(&unspent) { + Ok(value) => { + let key = unspent.id.clone(); + self.db + .put("script_activity", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self.db.delete("script_activity", id.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/script_aggregation.rs b/lib/ain-ocean/src/data_acces/script_aggregation.rs new file mode 100644 index 00000000000..0b630ff0169 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/script_aggregation.rs @@ -0,0 +1,44 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::script_aggregation::ScriptAggregation; +use anyhow::{anyhow, Error, Result}; +use serde::{Deserialize, Serialize}; +use serde_json; + +pub struct ScriptAggretionDB { + pub db: RocksDB, +} + +impl ScriptAggretionDB { + pub async fn query(&self, limit: i32, lt: String) -> Result> { + todo!() + } + pub async fn store(&self, aggregation: ScriptAggregation) -> Result<()> { + match serde_json::to_string(&aggregation) { + Ok(value) => { + let key = aggregation.id.clone(); + self.db + .put("script_aggregation", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn get(&self, id: String) -> Result> { + match self.db.get("script_aggregation", id.as_bytes()) { + Ok(Some(value)) => { + let oracle: ScriptAggregation = + serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; + Ok(Some(oracle)) + } + Ok(None) => Ok(None), + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self.db.delete("script_aggregation", id.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/script_unspent.rs b/lib/ain-ocean/src/data_acces/script_unspent.rs new file mode 100644 index 00000000000..e414384ac45 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/script_unspent.rs @@ -0,0 +1,33 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::script_unspent::ScriptUnspent; +use anyhow::{anyhow, Error, Result}; +use serde::{Deserialize, Serialize}; +use serde_json; + +pub struct ScriptUnspentDB { + pub db: RocksDB, +} + +impl ScriptUnspentDB { + pub async fn query(&self, limit: i32, lt: String) -> Result> { + todo!() + } + pub async fn store(&self, unspent: ScriptUnspent) -> Result<()> { + match serde_json::to_string(&unspent) { + Ok(value) => { + let key = unspent.id.clone(); + self.db + .put("script_unspent", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self.db.delete("script_unspent", id.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/test/mod.rs b/lib/ain-ocean/src/data_acces/test/mod.rs new file mode 100644 index 00000000000..bd9b68cbdc5 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/test/mod.rs @@ -0,0 +1,2 @@ +mod oracle_test; +mod transaction_test; diff --git a/lib/ain-ocean/src/data_acces/test/oracle_test.rs b/lib/ain-ocean/src/data_acces/test/oracle_test.rs new file mode 100644 index 00000000000..234388a7824 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/test/oracle_test.rs @@ -0,0 +1,71 @@ +#[cfg(test)] +mod tests { + use crate::data_acces::oracle::OracleDb; + use crate::database::db_manger::{ColumnFamilyOperations, RocksDB}; + use crate::model::oracle::{Oracle, OracleBlock, PriceFeedsItem}; + use tempfile::tempdir; + use tokio::task; + + // Function to set up a test database environment + fn setup_test_db() -> OracleDb { + let temp_dir = tempdir().unwrap(); + let db = RocksDB::new(temp_dir.path().to_str().unwrap()).unwrap(); // Adjust this according to your RocksDB struct + OracleDb { db } + } + + // Function to create a dummy Oracle instance for testing + fn create_dummy_oracle(id: &str) -> Oracle { + Oracle { + id: id.to_string(), + owner_address: "owner_address_example".to_string(), + weightage: 10, + price_feeds: vec![PriceFeedsItem { + token: "token_example".to_string(), + currency: "currency_example".to_string(), + }], + block: OracleBlock { + hash: "hash_example".to_string(), + height: 1, + time: 100000, + median_time: 100000, + }, + } + } + + #[tokio::test] + async fn test_store() { + let oracle_db = setup_test_db(); + let oracle = create_dummy_oracle("test_id_1"); + + let result = oracle_db.store(oracle).await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_get() { + let oracle_db = setup_test_db(); + let oracle = create_dummy_oracle("test_id_2"); + oracle_db.store(oracle.clone()).await.unwrap(); + + let result = oracle_db.get(oracle.id.clone()).await.unwrap(); + assert!(result.is_some()); + println!("the oracle result {:?}", result); + assert_eq!(result.unwrap(), oracle); + } + + #[tokio::test] + async fn test_delete() { + let oracle_db = setup_test_db(); + let oracle = create_dummy_oracle("test_id_3"); + oracle_db.store(oracle.clone()).await.unwrap(); + + let delete_result = oracle_db.delete(oracle.id.clone()).await; + assert!(delete_result.is_ok()); + + let get_result = oracle_db.get(oracle.id).await; + assert!(get_result.is_ok()); + assert!(get_result.unwrap().is_none()); + } + + // Additional tests for `query` and other edge cases can be added similarly +} diff --git a/lib/ain-ocean/src/data_acces/test/transaction_test.rs b/lib/ain-ocean/src/data_acces/test/transaction_test.rs new file mode 100644 index 00000000000..f835b40e3e9 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/test/transaction_test.rs @@ -0,0 +1,99 @@ +#[cfg(test)] +mod tests { + use crate::data_acces::transaction::TransactionVinDb; + use crate::data_acces::transaction_vout::TransactionVoutDb; + use crate::database::db_manger::{ColumnFamilyOperations, RocksDB}; + use crate::model::transaction::{Transaction, TransactionBlock}; + use crate::model::transaction_vout::{TransactionVout, TransactionVoutScript}; + use tempfile::tempdir; + use tokio::task; + + fn setup_test_db() -> TransactionVinDb { + let temp_dir = tempdir().unwrap(); + let db = RocksDB::new(temp_dir.path().to_str().unwrap()).unwrap(); + TransactionVinDb { db } + } + + // Sample transaction for testing + fn sample_transaction(id: &str) -> Transaction { + Transaction { + id: id.to_string(), + order: 1, + block: TransactionBlock { + hash: "sample_hash".to_string(), + height: 123, + time: 1000, + median_time: 1000, + }, + txid: id.to_string(), + hash: "sample_transaction_hash".to_string(), + version: 1, + size: 200, + v_size: 200, + weight: 300, + total_vout_value: "1000".to_string(), + lock_time: 0, + vin_count: 2, + vout_count: 2, + } + } + + fn sample_transaction_Vout() { + // Instantiate a sample TransactionVoutScript + let sample_script = TransactionVoutScript { + hex: "76a91488ac".to_string(), // Sample hex string + r#type: "pubkeyhash".to_string(), // Sample type + }; + + // Instantiate a sample TransactionVout + let sample_vout = TransactionVout { + id: "vout1".to_string(), // Sample ID + txid: "tx12345".to_string(), // Sample transaction ID + n: 0, // Sample index + value: "0.0001".to_string(), // Sample value in BTC or similar currency + token_id: 123, // Sample token ID + script: sample_script, // Use the sample script created above + }; + } + + #[tokio::test] + async fn test_store_transaction() { + let txn_vin_db = setup_test_db(); + + let test_transaction = sample_transaction("tx1"); + + let result = txn_vin_db.store(test_transaction).await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_store_get_transaction() { + let txn_vin_db = setup_test_db(); + + let test_transaction = sample_transaction("tx1"); + let trx_id = test_transaction.id.clone(); + + let result = txn_vin_db.store(test_transaction.clone()).await; + assert!(result.is_ok()); + + let result = txn_vin_db.get(trx_id).await.unwrap().unwrap(); + assert_eq!(test_transaction, result); + } + + #[tokio::test] + async fn test_store_get_delete_transaction() { + let txn_vin_db = setup_test_db(); + + let test_transaction = sample_transaction("tx1"); + let trx_id = test_transaction.id.clone(); + + let result = txn_vin_db.store(test_transaction.clone()).await; + assert!(result.is_ok()); + + let result = txn_vin_db.get(trx_id.clone()).await.unwrap().unwrap(); + assert_eq!(test_transaction, result); + + let result = txn_vin_db.delete(trx_id).await; + assert!(result.is_ok()); + } +} diff --git a/lib/ain-ocean/src/data_acces/transaction.rs b/lib/ain-ocean/src/data_acces/transaction.rs new file mode 100644 index 00000000000..e16701aa77b --- /dev/null +++ b/lib/ain-ocean/src/data_acces/transaction.rs @@ -0,0 +1,48 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::transaction::Transaction; +use anyhow::{anyhow, Result}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug)] +pub struct TransactionVinDb { + pub db: RocksDB, +} + +impl TransactionVinDb { + pub async fn get(&self, txid: String) -> Result> { + match self.db.get("transaction", txid.as_bytes()) { + Ok(Some(value)) => { + let trx: Transaction = serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; + Ok(Some(trx)) + } + Ok(None) => Ok(None), + Err(e) => Err(anyhow!(e)), + } + } + pub async fn store(&self, txn: Transaction) -> Result<()> { + match serde_json::to_string(&txn) { + Ok(value) => { + let key = txn.id.clone(); + self.db + .put("transaction", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, txid: String) -> Result<()> { + match self.db.delete("transaction", txid.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } + pub async fn query_by_blockhash( + &self, + hash: String, + limit: i32, + lt: i32, + ) -> Result> { + todo!() + } +} diff --git a/lib/ain-ocean/src/data_acces/transaction_vin.rs b/lib/ain-ocean/src/data_acces/transaction_vin.rs new file mode 100644 index 00000000000..1aae77ab1f5 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/transaction_vin.rs @@ -0,0 +1,32 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::transaction_vin::TransactionVin; +use anyhow::{anyhow, Result}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug)] +pub struct TransactionVinDb { + pub db: RocksDB, +} + +impl TransactionVinDb { + pub async fn store(&self, trx_vin: TransactionVin) -> Result<()> { + match serde_json::to_string(&trx_vin) { + Ok(value) => { + let key = trx_vin.id.clone(); + self.db.put("oracle", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self.db.delete("transaction_vin", id.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } + pub async fn query(&self, txid: String, limit: i32, lt: i32) -> Result> { + todo!() + } +} diff --git a/lib/ain-ocean/src/data_acces/transaction_vout.rs b/lib/ain-ocean/src/data_acces/transaction_vout.rs new file mode 100644 index 00000000000..145e68b282e --- /dev/null +++ b/lib/ain-ocean/src/data_acces/transaction_vout.rs @@ -0,0 +1,44 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::transaction_vout::TransactionVout; +use anyhow::{anyhow, Result}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug)] +pub struct TransactionVoutDb { + pub db: RocksDB, +} + +impl TransactionVoutDb { + pub async fn get(&self, txid: String, n: i64) -> Result> { + match self.db.get("transaction_vout", txid.as_bytes()) { + Ok(Some(value)) => { + let master_node: TransactionVout = + serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; + Ok(Some(master_node)) + } + Ok(None) => Ok(None), + Err(e) => Err(anyhow!(e)), + } + } + pub async fn store(&self, trx_out: TransactionVout) -> Result<()> { + match serde_json::to_string(&trx_out) { + Ok(value) => { + let key = trx_out.id.clone(); + self.db + .put("transaction_vout", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self.db.delete("transaction_vout", id.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } + pub async fn query(&self, txid: String, limit: i32, lt: i32) -> Result { + todo!() + } +} diff --git a/lib/ain-ocean/src/data_acces/vault_auction_batch_history.rs b/lib/ain-ocean/src/data_acces/vault_auction_batch_history.rs new file mode 100644 index 00000000000..7d038be6477 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/vault_auction_batch_history.rs @@ -0,0 +1,41 @@ +use crate::database::db_manger::ColumnFamilyOperations; +use crate::database::db_manger::RocksDB; +use crate::model::vault_auction_batch_history::VaultAuctionBatchHistory; +use anyhow::{anyhow, Error, Result}; +use serde::{Deserialize, Serialize}; +use serde_json; + +pub struct VaultAuctionDB { + pub db: RocksDB, +} + +impl VaultAuctionDB { + pub async fn store(&self, auction: VaultAuctionBatchHistory) -> Result<()> { + match serde_json::to_string(&auction) { + Ok(value) => { + let key = auction.id.clone(); + self.db + .put("vault_auction_history", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn get(&self, id: String) -> Result> { + match self.db.get("vault_auction_history", id.as_bytes()) { + Ok(Some(value)) => { + let oracle: VaultAuctionBatchHistory = + serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; + Ok(Some(oracle)) + } + Ok(None) => Ok(None), + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self.db.delete("vault_auction_history", id.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/database/config.rs b/lib/ain-ocean/src/database/config.rs new file mode 100644 index 00000000000..39d2fa15046 --- /dev/null +++ b/lib/ain-ocean/src/database/config.rs @@ -0,0 +1,36 @@ +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; +use std::{env, fs}; +use structopt::StructOpt; + +#[derive(Debug, Clone, Serialize, Deserialize, StructOpt)] +pub struct Config { + /// Path to the RocksDB database on the local file system. + #[structopt( + long = "rocksdb-path", + env = "ROCKSDB_PATH", + default_value = "rocksdb/data" + )] + pub rocksdb_path: String, +} +impl Default for Config { + fn default() -> Self { + let mut path = match env::var("HOME") { + Ok(val) => PathBuf::from(val), + Err(_) => panic!("Couldn't find a home directory"), + }; + path.push("rocksdb/data"); + if let Err(e) = fs::create_dir_all(&path) { + panic!("Failed to create default RocksDB path: {}", e); + } + + let path_str = match path.to_str() { + Some(p) => p, + None => panic!("Failed to convert path to string"), + }; + + Self { + rocksdb_path: path_str.to_string(), + } + } +} diff --git a/lib/ain-ocean/src/database/db_manger.rs b/lib/ain-ocean/src/database/db_manger.rs new file mode 100644 index 00000000000..bdf9b851922 --- /dev/null +++ b/lib/ain-ocean/src/database/db_manger.rs @@ -0,0 +1,282 @@ +use crate::model::oracle::Oracle; +use anyhow::{anyhow, Result}; +use bitcoin::blockdata::block::Block; +use bitcoin::blockdata::block::Header; +use bitcoin::consensus::encode::serialize; +use rocksdb::Options; +use rocksdb::{ColumnFamilyDescriptor, DBIterator, IteratorMode, DB}; +use serde::{Deserialize, Serialize}; +use std::collections::HashSet; +use std::sync::Arc; + +#[derive(Debug)] +pub struct RocksDB { + db: Arc, + cfs: HashSet, +} + +pub trait ColumnFamilyOperations { + fn get(&self, cf_name: &str, key: &[u8]) -> Result>>; + fn put(&self, cf_name: &str, key: &[u8], value: &[u8]) -> Result<()>; + fn delete(&self, cf_name: &str, key: &[u8]) -> Result<()>; + fn get_total_row(&self) -> Result<()>; + fn iterator(&self, cf_name: &str, mode: IteratorMode) -> Result<(DBIterator)>; +} + +impl RocksDB { + pub fn new(db_path: &str) -> anyhow::Result { + let mut opts = Options::default(); + opts.create_if_missing(true); + opts.create_missing_column_families(true); + + let cf_names = [ + "default", + "block", + "masternode_stats", + "masternode", + "oracle_history", + "oracle_price_active", + "oracle_price_aggregated_interval", + "oracle_price_aggregated", + "oracle_price_feed", + "oracle_token_currency", + "oracle", + "pool_swap_aggregated", + "pool_swap", + "price_ticker", + "raw_block", + "script_activity", + "script_aggregation", + "script_unspent", + "transaction", + "transaction_vin", + "transaction_vout", + "vault_auction_history", + "pool_swap", + ]; + let mut cf_descriptors = vec![]; + + for cf_name in &cf_names { + let mut cf_opts = Options::default(); + cf_opts.set_max_write_buffer_number(16); + cf_descriptors.push(ColumnFamilyDescriptor::new(cf_name.to_string(), cf_opts)); + } + + let db = Arc::new(DB::open_cf_descriptors(&opts, db_path, cf_descriptors)?); + + // Keep names of the column families so you can look them up later + let cfs = cf_names + .iter() + .cloned() + .map(String::from) + .collect::>(); + + Ok(Self { db, cfs }) + } + + pub fn put_block(&self, block: &Block) -> anyhow::Result<()> { + // Serialize the header to a byte vector + let serialized_header = serialize(block); + // Convert the block hash to string (Assume it's a suitable key) + let key = block.block_hash().to_string(); + // Store the block header + self.put("block", key.as_bytes(), &serialized_header)?; + Ok(()) + } + + pub fn get_block(&self, key: &[u8]) -> anyhow::Result>> { + self.get("block", key) + } + + pub fn put_block_header(&self, header: &Header) -> anyhow::Result<()> { + // Serialize the header to a byte vector + let serialized_header = serialize(header); + // Convert the block hash to string (Assume it's a suitable key) + let key = header.block_hash().to_string(); + // Store the block header + self.put("block_header", key.as_bytes(), &serialized_header)?; + // Update the latest block hash + let latest_block_hash = header.block_hash().to_string(); + self.put_latest_block_hash( + "latest_block_hash", + b"latest_block_hash", + latest_block_hash.as_bytes(), + )?; + + Ok(()) + } + + pub fn get_block_header(&self, key: &[u8]) -> anyhow::Result>> { + self.get("block_header", key) + } + + pub fn put_latest_block_hash( + &self, + cf_name: &str, + key: &[u8], + value: &[u8], + ) -> anyhow::Result<()> { + if let Some(cf) = self.cfs.get(cf_name) { + let cf_handle = self + .db + .cf_handle(cf) + .ok_or_else(|| anyhow::anyhow!("Failed to get column family handle"))?; + // Key does not exist, proceed to store the new value + self.db + .put_cf(cf_handle, key, value) + .map_err(|_| anyhow::anyhow!("Failed to put key-value pair")) + } else { + // Log some diagnostic info here. + Err(anyhow::anyhow!("Invalid column family name")) + } + } + + pub fn count_entries_in_cf(&self, cf_name: &str) -> anyhow::Result { + if let Some(cf_name) = self.cfs.get(cf_name) { + let cf = self + .db + .cf_handle(cf_name) + .ok_or_else(|| anyhow::anyhow!("Could not get column family handle"))?; + let iter = self.db.iterator_cf(cf, IteratorMode::Start); + + let mut count: u64 = 0; + for _ in iter { + count += 1; + } + + Ok(count) + } else { + Err(anyhow::anyhow!("Invalid column family name")) + } + } + + pub fn get_latest_block_hash(&self) -> anyhow::Result> { + let _db_path = self.db.path(); + let cf_name = "latest_block_hash"; + let key = b"latest_block_hash"; + if let Some(cf_name) = self.cfs.get(cf_name) { + let cf = self + .db + .cf_handle(cf_name) + .ok_or_else(|| anyhow::anyhow!("Failed to get column family handle"))?; + + match self.db.get_cf(cf, key)? { + Some(value) => { + let value_str = String::from_utf8(value) + .map_err(|e| anyhow::anyhow!("Failed to convert to UTF-8: {}", e))?; + Ok(Some(value_str)) + } + None => Ok(None), + } + } else { + Err(anyhow::anyhow!("Invalid column family name")) + } + } + + //block_hash in block table + pub async fn block_hash_exists(&self, block_hash: &str) -> anyhow::Result { + let cf_name = "block"; + if let Some(cf_name) = self.cfs.get(cf_name) { + let cf = self + .db + .cf_handle(cf_name) + .ok_or_else(|| anyhow::anyhow!("Failed to get column family handle"))?; + + let key = block_hash.as_bytes(); + match self.db.get_cf(cf, key)? { + Some(_) => Ok(true), // Block hash exists in the "block" column family + None => Ok(false), // Block hash does not exist + } + } else { + Err(anyhow::anyhow!("Invalid column family name")) + } + } +} + +impl ColumnFamilyOperations for RocksDB { + fn get(&self, cf_name: &str, key: &[u8]) -> Result>> { + if let Some(cf_name) = self.cfs.get(cf_name) { + let cf = self + .db + .cf_handle(cf_name) + .expect("Should never fail if column family name is valid"); + let result = self.db.get_cf(cf, key)?; + Ok(result) + } else { + Err(anyhow!("Invalid column family name")) + } + } + + fn put(&self, cf_name: &str, key: &[u8], value: &[u8]) -> Result<()> { + if let Some(cf) = self.cfs.get(cf_name) { + let cf_handle = self + .db + .cf_handle(cf) + .ok_or_else(|| anyhow!("Failed to get column family handle"))?; + + // Check if the key already exists + if self.db.get_cf(cf_handle, key)?.is_none() { + self.db + .put_cf(cf_handle, key, value) + .map_err(|_| anyhow!("Failed to put key-value pair")) + } else { + Ok(()) + } + } else { + // Log some diagnostic info here. + Err(anyhow!("Invalid column family name")) + } + } + + fn delete(&self, cf_name: &str, key: &[u8]) -> Result<()> { + if let Some(cf_name) = self.cfs.get(cf_name) { + let cf = self + .db + .cf_handle(cf_name) + .expect("Should never fail if column family name is valid"); + self.db.delete_cf(cf, key)?; + Ok(()) + } else { + Err(anyhow!("Invalid column family name")) + } + } + + fn get_total_row(&self) -> anyhow::Result<()> { + let db_path = self.db.path(); + println!("{:?}", db_path); + + let block_header_cf = self + .db + .cf_handle("block_header") + .ok_or(anyhow::anyhow!("Column family 'block_header' not found"))?; + + let block_cf = self + .db + .cf_handle("block") + .ok_or(anyhow::anyhow!("Column family 'block' not found"))?; + + let mut block_header_count = 0; + let mut block_count = 0; + + for _ in self.db.iterator_cf(block_header_cf, IteratorMode::Start) { + block_header_count += 1; + } + + // Count rows in "block" column family + for _ in self.db.iterator_cf(block_cf, IteratorMode::Start) { + block_count += 1; + } + + println!("Total rows in 'block_header': {}", block_header_count); + println!("Total rows in 'block': {}", block_count); + Ok(()) + } + + fn iterator(&self, cf_name: &str, mode: IteratorMode) -> Result { + if let Some(cf_handle) = self.db.cf_handle(cf_name) { + Ok(self.db.iterator_cf(cf_handle, mode)) + } else { + Err(anyhow!("Column family not found")) + } + } +} diff --git a/lib/ain-ocean/src/database/db_test.rs b/lib/ain-ocean/src/database/db_test.rs new file mode 100644 index 00000000000..8131a626ed1 --- /dev/null +++ b/lib/ain-ocean/src/database/db_test.rs @@ -0,0 +1,180 @@ +// // In your src/lib.rs or a dedicated module for RocksDB interaction + +// extern crate rocksdb; +// extern crate tempdir; +// use crate::database::db_manger::RocksDB; +// use bitcoin::blockdata::block::Header; +// use bitcoin::blockdata::block::Version; +// use bitcoin::blockdata::script::ScriptBuf; +// use bitcoin::blockdata::transaction::OutPoint; +// use bitcoin::blockdata::transaction::Transaction; +// use bitcoin::blockdata::transaction::TxIn; +// use bitcoin::blockdata::transaction::TxOut; +// use bitcoin::blockdata::witness::Witness; +// use bitcoin::consensus::deserialize; +// use bitcoin::hash_types::TxMerkleNode; +// use bitcoin::hash_types::Txid; +// use bitcoin::pow::CompactTarget; +// use bitcoin::Block; +// use bitcoin::BlockHash; +// use bitcoin_hashes::sha256d; +// use bitcoin_hashes::Hash; +// use hex; +// use rocksdb::{Options, DB}; + +// // Function to initialize a RocksDB instance +// pub fn init_db(path: &str) -> DB { +// let mut opts = Options::default(); +// opts.create_if_missing(true); +// DB::open(&opts, path).expect("failed to open database") +// } + +// pub fn create_mock_header() -> Header { +// // Convert hex string to a byte array + +// let hash: BlockHash = BlockHash::from_slice(&[0u8; 32]).unwrap(); +// let merkle_root_bytes = +// hex::decode("c9a4892e8ab7704e5078797f74c4d684ff493e22750a528cec21bf30ef73a3b7") +// .expect("Invalid hex string for merkle root"); + +// // Convert the byte array to a Hash type +// let merkle_root_hash = +// sha256d::Hash::from_slice(&merkle_root_bytes).expect("Invalid bytes for merkle root hash"); + +// Header { +// version: Version::from_consensus(1527281788), +// prev_blockhash: hash, // Mock previous block hash +// merkle_root: TxMerkleNode::from_raw_hash(merkle_root_hash), +// time: 2236946890, +// bits: CompactTarget::from_consensus(3633759788), +// nonce: 491612868, +// } +// } + +// pub fn create_mock_block() -> Block { +// // Convert hex string to a byte array + +// let hash: BlockHash = BlockHash::from_slice(&[0u8; 32]).unwrap(); +// let merkle_root_bytes = +// hex::decode("c9a4892e8ab7704e5078797f74c4d684ff493e22750a528cec21bf30ef73a3b7") +// .expect("Invalid hex string for merkle root"); + +// // Convert the byte array to a Hash type +// let merkle_root_hash = +// sha256d::Hash::from_slice(&merkle_root_bytes).expect("Invalid bytes for merkle root hash"); + +// let tx_bytes = hex::decode("c9a4892e8ab7704e5078797f74c4d684ff493e22750a528cec21bf30ef73a3b7") +// .expect("Invalid hex string for merkle root"); +// let tx_id = sha256d::Hash::from_slice(&tx_bytes).expect("Invalid bytes for merkle root hash"); + +// let header = Header { +// version: Version::from_consensus(1527281788), +// prev_blockhash: hash, // Mock previous block hash +// merkle_root: TxMerkleNode::from_raw_hash(merkle_root_hash), +// time: 2236946890, +// bits: CompactTarget::from_consensus(3633759788), +// nonce: 491612868, +// }; + +// let input = TxIn { +// previous_output: OutPoint { +// txid: Txid::from_raw_hash(tx_id), + +// vout: 4294967295, +// }, +// script_sig: ScriptBuf::new(), +// sequence: bitcoin::Sequence(4294967295), +// witness: Witness::default(), +// }; + +// let output1 = TxOut { +// value: 5000000000, +// script_pubkey: ScriptBuf::new(), +// }; + +// let output2 = TxOut { +// value: 0, +// script_pubkey: ScriptBuf::new(), +// }; + +// // Construct the transaction +// let transaction = Transaction { +// version: 2, +// lock_time: bitcoin::absolute::LockTime::from_height(0).unwrap(), +// input: vec![input], +// output: vec![output1, output2], +// }; + +// Block { +// header, +// txdata: vec![transaction], +// } +// } + +// #[cfg(test)] +// mod tests { +// use super::*; +// use tempdir::TempDir; + +// #[test] +// fn test_db_headers_store_retrieve() { +// let temp_dir = TempDir::new("rocksdb_test").unwrap(); +// let rocks_db = RocksDB::new(temp_dir.path().to_str().unwrap()).unwrap(); +// // Create a mock header +// let header = create_mock_header(); +// rocks_db.put_block_header(&header).unwrap(); +// let bh = header.block_hash().to_string(); + +// let retrieved_data = rocks_db.get_block_header(bh.as_bytes()).unwrap(); + +// assert!( +// retrieved_data.is_some(), +// "No data was retrieved for the header" +// ); +// let retrieved_header: Header = deserialize(&retrieved_data.unwrap()).unwrap(); +// assert_eq!( +// header, retrieved_header, +// "Retrieved header should match the original header" +// ); +// } + +// #[test] +// fn test_db_block_store_retrieve() { +// let temp_dir = TempDir::new("rocksdb_test").unwrap(); +// let rocks_db = RocksDB::new(temp_dir.path().to_str().unwrap()).unwrap(); +// // Create a mock header +// let new_block = create_mock_block(); +// rocks_db.put_block(&new_block).unwrap(); +// let bh = new_block.block_hash().to_string(); +// let retrieved_data = rocks_db.get_block(bh.as_bytes()).unwrap(); +// assert!( +// retrieved_data.is_some(), +// "No data was retrieved for the header" +// ); +// let retrieved_block: Block = deserialize(&retrieved_data.unwrap()).unwrap(); +// assert_eq!( +// new_block, retrieved_block, +// "Retrieved header should match the original header" +// ); +// } + +// #[test] +// fn test_db_latest_block_hash_store_retrieve() { +// let temp_dir = TempDir::new("rocksdb_test").unwrap(); +// let rocks_db = RocksDB::new(temp_dir.path().to_str().unwrap()).unwrap(); + +// // Create and store a test block header +// let header = create_mock_header(); +// rocks_db.put_block_header(&header).unwrap(); + +// // Retrieve the latest block hash from the database +// let stored_latest_block_hash = rocks_db.get_latest_block_hash().unwrap(); + +// // Check that the retrieved hash matches the test header's block hash +// assert_eq!( +// Some(header.block_hash().to_string()), +// stored_latest_block_hash, +// "The retrieved latest block hash does not match the expected value." +// ); +// } +// } diff --git a/lib/ain-ocean/src/database/mod.rs b/lib/ain-ocean/src/database/mod.rs new file mode 100644 index 00000000000..cec892297a8 --- /dev/null +++ b/lib/ain-ocean/src/database/mod.rs @@ -0,0 +1,3 @@ +pub mod config; +pub mod db_manger; +pub mod db_test; diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 7064679280d..1a037199cc0 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -1,11 +1,13 @@ -use axum::{http::StatusCode, response::{IntoResponse, Response}}; +use axum::{ + http::StatusCode, + response::{IntoResponse, Response}, +}; use thiserror::Error; pub type OceanResult = Result; #[derive(Error, Debug)] -pub enum OceanError { -} +pub enum OceanError {} impl IntoResponse for OceanError { fn into_response(self) -> Response { diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 5d7ebdbaf24..547943eaaa7 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -1,8 +1,10 @@ -mod api; pub mod api_paged_response; pub mod error; mod indexer; -mod model; pub use api::ocean_router; pub use indexer::{index_block, invalidate_block}; +pub mod api; +mod data_acces; +pub mod database; +mod model; diff --git a/lib/ain-ocean/src/model/block.rs b/lib/ain-ocean/src/model/block.rs index fc6ea91318d..55517511da5 100644 --- a/lib/ain-ocean/src/model/block.rs +++ b/lib/ain-ocean/src/model/block.rs @@ -1,4 +1,7 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct Block { pub id: String, pub hash: String, diff --git a/lib/ain-ocean/src/model/masternode.rs b/lib/ain-ocean/src/model/masternode.rs index 8db67494927..27f1608dcac 100644 --- a/lib/ain-ocean/src/model/masternode.rs +++ b/lib/ain-ocean/src/model/masternode.rs @@ -1,6 +1,6 @@ -use bitcoin::{BlockHash, Txid}; +use serde::{Deserialize, Serialize}; -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub struct Masternode { pub id: String, pub sort: Option, @@ -16,7 +16,8 @@ pub struct Masternode { pub history: Option>, } -#[derive(Debug)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct MasternodeBlock { pub hash: String, pub height: u32, @@ -24,7 +25,8 @@ pub struct MasternodeBlock { pub median_time: u64, } -#[derive(Debug)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct HistoryItem { pub txid: String, pub owner_address: String, diff --git a/lib/ain-ocean/src/model/masternode_stats.rs b/lib/ain-ocean/src/model/masternode_stats.rs index b3060c4f2ac..f037629517b 100644 --- a/lib/ain-ocean/src/model/masternode_stats.rs +++ b/lib/ain-ocean/src/model/masternode_stats.rs @@ -1,18 +1,23 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct MasternodeStats { pub id: String, pub block: MasternodeStatsBlock, pub stats: MasternodeStatsStats, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct TimelockStats { pub weeks: i32, pub tvl: String, pub count: i32, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct MasternodeStatsBlock { pub hash: String, pub height: i32, @@ -20,7 +25,8 @@ pub struct MasternodeStatsBlock { pub median_time: i32, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct MasternodeStatsStats { pub count: i32, pub tvl: String, diff --git a/lib/ain-ocean/src/model/oracle.rs b/lib/ain-ocean/src/model/oracle.rs index fe3b35df4c2..97befdd9c71 100644 --- a/lib/ain-ocean/src/model/oracle.rs +++ b/lib/ain-ocean/src/model/oracle.rs @@ -1,4 +1,7 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct Oracle { pub id: String, pub owner_address: String, @@ -7,13 +10,15 @@ pub struct Oracle { pub block: OracleBlock, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct PriceFeedsItem { pub token: String, pub currency: String, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] +#[serde(rename_all = "camelCase")] pub struct OracleBlock { pub hash: String, pub height: i32, diff --git a/lib/ain-ocean/src/model/oracle_history.rs b/lib/ain-ocean/src/model/oracle_history.rs index c1155124f4e..0bce2e20a6d 100644 --- a/lib/ain-ocean/src/model/oracle_history.rs +++ b/lib/ain-ocean/src/model/oracle_history.rs @@ -1,4 +1,7 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OracleHistory { pub id: String, pub oracle_id: String, @@ -9,13 +12,15 @@ pub struct OracleHistory { pub block: OracleHistoryBlock, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct PriceFeedsItem { pub token: String, pub currency: String, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OracleHistoryBlock { pub hash: String, pub height: i32, diff --git a/lib/ain-ocean/src/model/oracle_price_active.rs b/lib/ain-ocean/src/model/oracle_price_active.rs index 4289fe01571..d3d7a77641a 100644 --- a/lib/ain-ocean/src/model/oracle_price_active.rs +++ b/lib/ain-ocean/src/model/oracle_price_active.rs @@ -1,4 +1,7 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OraclePriceActive { pub id: String, pub key: String, @@ -9,21 +12,24 @@ pub struct OraclePriceActive { pub block: OraclePriceActiveBlock, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OraclePriceActiveActive { pub amount: String, pub weightage: i32, pub oracles: OraclePriceActiveActiveOracles, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OraclePriceActiveNext { pub amount: String, pub weightage: i32, pub oracles: OraclePriceActiveNextOracles, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OraclePriceActiveBlock { pub hash: String, pub height: i32, @@ -31,13 +37,15 @@ pub struct OraclePriceActiveBlock { pub median_time: i32, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OraclePriceActiveActiveOracles { pub active: i32, pub total: i32, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OraclePriceActiveNextOracles { pub active: i32, pub total: i32, diff --git a/lib/ain-ocean/src/model/oracle_price_aggregated.rs b/lib/ain-ocean/src/model/oracle_price_aggregated.rs index c948a9c7b45..57e16f7b063 100644 --- a/lib/ain-ocean/src/model/oracle_price_aggregated.rs +++ b/lib/ain-ocean/src/model/oracle_price_aggregated.rs @@ -1,4 +1,7 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OraclePriceAggregated { pub id: String, pub key: String, @@ -9,14 +12,16 @@ pub struct OraclePriceAggregated { pub block: OraclePriceAggregatedBlock, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedAggregated { pub amount: String, pub weightage: i32, pub oracles: OraclePriceAggregatedAggregatedOracles, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedBlock { pub hash: String, pub height: i32, @@ -24,7 +29,8 @@ pub struct OraclePriceAggregatedBlock { pub median_time: i32, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedAggregatedOracles { pub active: i32, pub total: i32, diff --git a/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs index 6f9729fb418..867e0030d39 100644 --- a/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs +++ b/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs @@ -1,4 +1,7 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedInterval { pub id: String, pub key: String, @@ -9,7 +12,8 @@ pub struct OraclePriceAggregatedInterval { pub block: OraclePriceAggregatedIntervalBlock, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedIntervalAggregated { pub amount: String, pub weightage: i32, @@ -17,7 +21,8 @@ pub struct OraclePriceAggregatedIntervalAggregated { pub oracles: OraclePriceAggregatedIntervalAggregatedOracles, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedIntervalBlock { pub hash: String, pub height: i32, @@ -25,7 +30,8 @@ pub struct OraclePriceAggregatedIntervalBlock { pub median_time: i32, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedIntervalAggregatedOracles { pub active: i32, pub total: i32, diff --git a/lib/ain-ocean/src/model/oracle_price_feed.rs b/lib/ain-ocean/src/model/oracle_price_feed.rs index 122b99bf975..74fd34d5764 100644 --- a/lib/ain-ocean/src/model/oracle_price_feed.rs +++ b/lib/ain-ocean/src/model/oracle_price_feed.rs @@ -1,4 +1,7 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OraclePriceFeed { pub id: String, pub key: String, @@ -12,7 +15,8 @@ pub struct OraclePriceFeed { pub block: OraclePriceFeedBlock, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OraclePriceFeedBlock { pub hash: String, pub height: i32, diff --git a/lib/ain-ocean/src/model/oracle_token_currency.rs b/lib/ain-ocean/src/model/oracle_token_currency.rs index e4b431301d5..a814083e9bb 100644 --- a/lib/ain-ocean/src/model/oracle_token_currency.rs +++ b/lib/ain-ocean/src/model/oracle_token_currency.rs @@ -1,4 +1,7 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OracleTokenCurrency { pub id: String, pub key: String, @@ -9,7 +12,8 @@ pub struct OracleTokenCurrency { pub block: OracleTokenCurrencyBlock, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct OracleTokenCurrencyBlock { pub hash: String, pub height: i32, diff --git a/lib/ain-ocean/src/model/poolswap.rs b/lib/ain-ocean/src/model/poolswap.rs index f6dd97ebd28..777d7e3a3f9 100644 --- a/lib/ain-ocean/src/model/poolswap.rs +++ b/lib/ain-ocean/src/model/poolswap.rs @@ -1,4 +1,7 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct PoolSwap { pub id: String, pub txid: String, @@ -10,7 +13,8 @@ pub struct PoolSwap { pub block: PoolSwapBlock, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct PoolSwapBlock { pub hash: String, pub height: i32, diff --git a/lib/ain-ocean/src/model/poolswap_aggregated.rs b/lib/ain-ocean/src/model/poolswap_aggregated.rs index 90afba7ae21..3e997e33028 100644 --- a/lib/ain-ocean/src/model/poolswap_aggregated.rs +++ b/lib/ain-ocean/src/model/poolswap_aggregated.rs @@ -1,4 +1,7 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct PoolSwapAggregated { pub id: String, pub key: String, @@ -7,12 +10,14 @@ pub struct PoolSwapAggregated { pub block: PoolSwapAggregatedBlock, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct PoolSwapAggregatedAggregated { pub amounts: Vec, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct PoolSwapAggregatedBlock { pub median_time: i32, } diff --git a/lib/ain-ocean/src/model/price_ticker.rs b/lib/ain-ocean/src/model/price_ticker.rs index a9a334c4f2d..509350976e7 100644 --- a/lib/ain-ocean/src/model/price_ticker.rs +++ b/lib/ain-ocean/src/model/price_ticker.rs @@ -1,6 +1,8 @@ +use serde::{Deserialize, Serialize}; + use super::oracle_price_aggregated::OraclePriceAggregated; -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct PriceTicker { pub id: String, pub sort: String, diff --git a/lib/ain-ocean/src/model/raw_block.rs b/lib/ain-ocean/src/model/raw_block.rs index 3569073e51d..6219bae7c2b 100644 --- a/lib/ain-ocean/src/model/raw_block.rs +++ b/lib/ain-ocean/src/model/raw_block.rs @@ -1,4 +1,7 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct RawBlock { pub id: String, pub json: String, diff --git a/lib/ain-ocean/src/model/script_activity.rs b/lib/ain-ocean/src/model/script_activity.rs index 6440f457c33..bed279a82c7 100644 --- a/lib/ain-ocean/src/model/script_activity.rs +++ b/lib/ain-ocean/src/model/script_activity.rs @@ -1,4 +1,5 @@ -#[derive(Debug, Default, PartialEq, Eq)] +use serde::{Deserialize, Serialize}; +#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum ScriptActivityType { #[default] Vin, @@ -14,7 +15,7 @@ impl ScriptActivityType { } } -#[derive(Debug, Default, PartialEq, Eq)] +#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum ScriptActivityTypeHex { #[default] Vin, @@ -30,7 +31,8 @@ impl ScriptActivityTypeHex { } } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] + pub struct ScriptActivity { pub id: String, pub hid: String, @@ -45,7 +47,7 @@ pub struct ScriptActivity { pub token_id: i32, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct ScriptActivityBlock { pub hash: String, pub height: i32, @@ -53,19 +55,19 @@ pub struct ScriptActivityBlock { pub median_time: i32, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct ScriptActivityScript { pub r#type: String, pub hex: String, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct ScriptActivityVin { pub txid: String, pub n: i32, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct ScriptActivityVout { pub txid: String, pub n: i32, diff --git a/lib/ain-ocean/src/model/script_aggregation.rs b/lib/ain-ocean/src/model/script_aggregation.rs index e0a6b838b1e..1345920cc52 100644 --- a/lib/ain-ocean/src/model/script_aggregation.rs +++ b/lib/ain-ocean/src/model/script_aggregation.rs @@ -1,4 +1,5 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; +#[derive(Debug, Default, Serialize, Deserialize)] pub struct ScriptAggregation { pub id: String, pub hid: String, @@ -8,7 +9,7 @@ pub struct ScriptAggregation { pub amount: ScriptAggregationAmount, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct ScriptAggregationBlock { pub hash: String, pub height: i32, @@ -16,20 +17,20 @@ pub struct ScriptAggregationBlock { pub median_time: i32, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct ScriptAggregationScript { pub r#type: String, pub hex: String, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct ScriptAggregationStatistic { pub tx_count: i32, pub tx_in_count: i32, pub tx_out_count: i32, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct ScriptAggregationAmount { pub tx_in: String, pub tx_out: String, diff --git a/lib/ain-ocean/src/model/script_unspent.rs b/lib/ain-ocean/src/model/script_unspent.rs index eecbfbdecf4..1c7787247bf 100644 --- a/lib/ain-ocean/src/model/script_unspent.rs +++ b/lib/ain-ocean/src/model/script_unspent.rs @@ -1,4 +1,5 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; +#[derive(Debug, Default, Serialize, Deserialize)] pub struct ScriptUnspent { pub id: String, pub hid: String, @@ -8,7 +9,7 @@ pub struct ScriptUnspent { pub vout: ScriptUnspentVout, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct ScriptUnspentBlock { pub hash: String, pub height: i32, @@ -16,13 +17,13 @@ pub struct ScriptUnspentBlock { pub median_time: i32, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct ScriptUnspentScript { pub r#type: String, pub hex: String, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct ScriptUnspentVout { pub txid: String, pub n: i32, diff --git a/lib/ain-ocean/src/model/transaction.rs b/lib/ain-ocean/src/model/transaction.rs index 3edcb78a8aa..911c2d22b83 100644 --- a/lib/ain-ocean/src/model/transaction.rs +++ b/lib/ain-ocean/src/model/transaction.rs @@ -1,4 +1,7 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Clone)] +#[serde(rename_all = "camelCase")] pub struct Transaction { pub id: String, pub order: i32, @@ -15,7 +18,8 @@ pub struct Transaction { pub vout_count: i32, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Clone)] +#[serde(rename_all = "camelCase")] pub struct TransactionBlock { pub hash: String, pub height: i32, diff --git a/lib/ain-ocean/src/model/transaction_vin.rs b/lib/ain-ocean/src/model/transaction_vin.rs index 14081d06ff7..f3317ec5cad 100644 --- a/lib/ain-ocean/src/model/transaction_vin.rs +++ b/lib/ain-ocean/src/model/transaction_vin.rs @@ -1,4 +1,5 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; +#[derive(Debug, Default, Serialize, Deserialize)] pub struct TransactionVin { pub id: String, pub txid: String, @@ -9,7 +10,7 @@ pub struct TransactionVin { pub sequence: String, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct TransactionVinVout { pub id: String, pub txid: String, @@ -19,12 +20,12 @@ pub struct TransactionVinVout { pub script: TransactionVinVoutScript, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct TransactionVinScript { pub hex: String, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct TransactionVinVoutScript { pub hex: String, } diff --git a/lib/ain-ocean/src/model/transaction_vout.rs b/lib/ain-ocean/src/model/transaction_vout.rs index 1ba65ebf989..6e91cf07abd 100644 --- a/lib/ain-ocean/src/model/transaction_vout.rs +++ b/lib/ain-ocean/src/model/transaction_vout.rs @@ -1,4 +1,5 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; +#[derive(Debug, Default, Serialize, Deserialize)] pub struct TransactionVout { pub id: String, pub txid: String, @@ -8,7 +9,7 @@ pub struct TransactionVout { pub script: TransactionVoutScript, } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct TransactionVoutScript { pub hex: String, pub r#type: String, diff --git a/lib/ain-ocean/src/model/vault_auction_batch_history.rs b/lib/ain-ocean/src/model/vault_auction_batch_history.rs index b2f9cae2bc1..614e96a41ca 100644 --- a/lib/ain-ocean/src/model/vault_auction_batch_history.rs +++ b/lib/ain-ocean/src/model/vault_auction_batch_history.rs @@ -1,4 +1,7 @@ -#[derive(Debug, Default)] +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct VaultAuctionBatchHistory { pub id: String, pub key: String, @@ -11,7 +14,8 @@ pub struct VaultAuctionBatchHistory { pub block: VaultAuctionBatchHistoryBlock, } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] pub struct VaultAuctionBatchHistoryBlock { pub hash: String, pub height: i32, diff --git a/make.sh b/make.sh index 0dbe57eb49c..7ae297b2b95 100755 --- a/make.sh +++ b/make.sh @@ -406,11 +406,11 @@ check_py() { py_ensure_env_active _exec_black 1 # TODO Add flake as well - py_env_deactivate + py_env_deactivate } check_rs() { - lib clippy 1 + # lib clippy 1 lib fmt-check 1 } @@ -455,7 +455,7 @@ check_cpp() { check_enter_build_rs_dir() { local build_dir="${BUILD_DIR}" - _ensure_enter_dir "$build_dir/lib" || { + _ensure_enter_dir "$build_dir/lib" || { echo "Please configure first"; exit 1; } } @@ -494,19 +494,19 @@ _run_clang_format() { local fmt_args="" for ((idx=0; idx<${#clang_formatters[@]}; ++idx)); do - if "${clang_formatters[$idx]}" --version &> /dev/null; then + if "${clang_formatters[$idx]}" --version &> /dev/null; then index="$idx" break fi done if [[ "$index" == -1 ]]; then - echo "clang-format(-${clang_ver}) required" + echo "clang-format(-${clang_ver}) required" exit 1 fi if [[ "$check_only" == 1 ]]; then fmt_args="--dry-run --Werror" - fi + fi # shellcheck disable=SC2086 find src/dfi src/ffi \( -iname "*.cpp" -o -iname "*.h" \) -print0 | \ @@ -1076,9 +1076,9 @@ _bash_version_check() { echo "Bash version 5+ required."; exit 1; } [ -z "$BASH_VERSION" ] && _bash_ver_err_exit - case $BASH_VERSION in + case $BASH_VERSION in 5.*) return 0;; - *) _bash_ver_err_exit;; + *) _bash_ver_err_exit;; esac } @@ -1220,11 +1220,11 @@ lib() { local cmd="${1-}" local exit_on_err="${2:-0}" local jobs="$MAKE_JOBS" - + check_enter_build_rs_dir # shellcheck disable=SC2086 - make JOBS=${jobs} ${cmd} || { if [[ "${exit_on_err}" == "1" ]]; then - echo "Error: Please resolve all checks"; + make JOBS=${jobs} ${cmd} || { if [[ "${exit_on_err}" == "1" ]]; then + echo "Error: Please resolve all checks"; exit 1; fi; } _exit_dir diff --git a/src/dfi/validation.cpp b/src/dfi/validation.cpp index 417644f736a..1cc541dafe8 100644 --- a/src/dfi/validation.cpp +++ b/src/dfi/validation.cpp @@ -2855,7 +2855,6 @@ void ProcessDeFiEvent(const CBlock &block, // construct undo FlushCacheCreateUndo(pindex, mnview, cache, uint256()); - // Ocean archive const auto oceanArchive{true}; if (oceanArchive) { From 1865191565f26b366f9274cea4f3a29b97490736 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Mon, 11 Dec 2023 17:16:02 +0800 Subject: [PATCH 008/185] WIP: Ocean test suite CI (#2734) * wip * fail-fast false --- .github/workflows/tests-ocean.yml | 96 +++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 .github/workflows/tests-ocean.yml diff --git a/.github/workflows/tests-ocean.yml b/.github/workflows/tests-ocean.yml new file mode 100644 index 00000000000..362e42edb25 --- /dev/null +++ b/.github/workflows/tests-ocean.yml @@ -0,0 +1,96 @@ +name: Tests - Jellyfish Whale Apis + +on: + workflow_dispatch: + pull_request: + branches: + - master + +concurrency: + group: ${{ github.workflow }}-${{ github.ref || github.run_id }} + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +env: + MAKE_DEBUG: 0 + +jobs: + build: + runs-on: ubuntu-latest + container: defi/ain-builder:latest + env: + CARGO_INCREMENTAL: 0 + + steps: + - uses: actions/checkout@v4 + - run: git config --global --add safe.directory '*' + + - name: Populate environment + run: ./make.sh ci-export-vars + + - name: Setup dependencies + run: ./make.sh ci-setup-deps + + - name: Setup user dependencies + run: ./make.sh ci-setup-user-deps + + - uses: Swatinem/rust-cache@v2 + with: + workspaces: lib -> ../build/lib/target + save-if: ${{ github.ref == 'refs/heads/master' }} + + - name: Build binaries + run: ./make.sh build + + - name: Upload binaries + uses: actions/upload-artifact@v3 + with: + name: defi-bins + path: build/src/defid + + - name: Build docker + run: "docker build -t test-build-container -f ./contrib/dockerfiles/x86_64-pc-linux-gnu.dockerfile ." + + - name: Upload docker + uses: actions/upload-artifact@v3 + with: + name: defi-docker + path: . + + test: + name: Jellyfish Whale Api tests + runs-on: ubuntu-latest + needs: build + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v4 + with: + repository: birthdayresearch/jellyfishsdk + ref: 'main' + + - name: Download binaries + uses: actions/download-artifact@v3 + with: + name: defi-bins + + - name: Download docker + uses: actions/download-artifact@v3 + with: + name: defi-docker + + - name: Setup permissions + run: | + chmod uog+x "$(pwd)/defid" + + - uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: Install dependencies + run: | + npm ci + + - name: Run tests + run: | + DEFICHAIN_DOCKER_IMAGE=test-build-container DEFID="$(pwd)/defid" npm t apps/whale-api/src/module.api From 35362b2ed6107598944e1d79bd06b16b46ec4c5b Mon Sep 17 00:00:00 2001 From: jouzo Date: Mon, 11 Dec 2023 10:52:05 +0100 Subject: [PATCH 009/185] Fix manger typo --- lib/ain-ocean/src/data_acces/block.rs | 8 +++++--- lib/ain-ocean/src/data_acces/masternode.rs | 8 +++++--- .../src/data_acces/masternode_states.rs | 8 +++++--- lib/ain-ocean/src/data_acces/oracle.rs | 8 +++++--- .../src/data_acces/oracle_price_aggregated.rs | 8 +++++--- .../oracle_price_aggregated_interval.rs | 8 +++++--- .../src/data_acces/oracle_token_currency.rs | 8 +++++--- lib/ain-ocean/src/data_acces/order_history.rs | 8 +++++--- lib/ain-ocean/src/data_acces/pool_swap.rs | 8 +++++--- .../src/data_acces/pool_swap_aggregated.rs | 8 +++++--- lib/ain-ocean/src/data_acces/price_ticker.rs | 8 +++++--- lib/ain-ocean/src/data_acces/raw_block.rs | 8 +++++--- lib/ain-ocean/src/data_acces/script_activity.rs | 8 +++++--- .../src/data_acces/script_aggregation.rs | 8 +++++--- lib/ain-ocean/src/data_acces/script_unspent.rs | 8 +++++--- .../src/data_acces/test/oracle_test.rs | 9 ++++++--- .../src/data_acces/test/transaction_test.rs | 14 +++++++++----- lib/ain-ocean/src/data_acces/transaction.rs | 8 +++++--- lib/ain-ocean/src/data_acces/transaction_vin.rs | 8 +++++--- .../src/data_acces/transaction_vout.rs | 8 +++++--- .../data_acces/vault_auction_batch_history.rs | 8 +++++--- .../database/{db_manger.rs => db_manager.rs} | 17 +++++++++-------- lib/ain-ocean/src/database/mod.rs | 2 +- 23 files changed, 120 insertions(+), 74 deletions(-) rename lib/ain-ocean/src/database/{db_manger.rs => db_manager.rs} (97%) diff --git a/lib/ain-ocean/src/data_acces/block.rs b/lib/ain-ocean/src/data_acces/block.rs index 200fd033f77..41b4415a1a4 100644 --- a/lib/ain-ocean/src/data_acces/block.rs +++ b/lib/ain-ocean/src/data_acces/block.rs @@ -1,9 +1,11 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::block::Block; use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::block::Block, +}; + #[derive(Debug)] pub struct BlockDb { pub db: RocksDB, diff --git a/lib/ain-ocean/src/data_acces/masternode.rs b/lib/ain-ocean/src/data_acces/masternode.rs index 918a51ff0c6..c2e7466a63d 100644 --- a/lib/ain-ocean/src/data_acces/masternode.rs +++ b/lib/ain-ocean/src/data_acces/masternode.rs @@ -1,10 +1,12 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::masternode::Masternode; use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; use serde_json; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::masternode::Masternode, +}; + pub struct MasterNodeDB { pub db: RocksDB, } diff --git a/lib/ain-ocean/src/data_acces/masternode_states.rs b/lib/ain-ocean/src/data_acces/masternode_states.rs index 1ab26b45872..8fb54b2a779 100644 --- a/lib/ain-ocean/src/data_acces/masternode_states.rs +++ b/lib/ain-ocean/src/data_acces/masternode_states.rs @@ -1,11 +1,13 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::masternode_stats::MasternodeStats; use anyhow::{anyhow, Result}; use bitcoin::absolute::Height; use rocksdb::{ColumnFamilyDescriptor, IteratorMode, DB}; use serde::{Deserialize, Serialize}; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::masternode_stats::MasternodeStats, +}; + #[derive(Debug)] pub struct MasterStatsDb { pub db: RocksDB, diff --git a/lib/ain-ocean/src/data_acces/oracle.rs b/lib/ain-ocean/src/data_acces/oracle.rs index 8bee24254b9..2d9badd0927 100644 --- a/lib/ain-ocean/src/data_acces/oracle.rs +++ b/lib/ain-ocean/src/data_acces/oracle.rs @@ -1,10 +1,12 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::oracle::Oracle; use anyhow::{anyhow, Error, Result}; use serde::{Deserialize, Serialize}; use serde_json; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::oracle::Oracle, +}; + pub struct OracleDb { pub db: RocksDB, } diff --git a/lib/ain-ocean/src/data_acces/oracle_price_aggregated.rs b/lib/ain-ocean/src/data_acces/oracle_price_aggregated.rs index a16719eebe1..e1e89e96733 100644 --- a/lib/ain-ocean/src/data_acces/oracle_price_aggregated.rs +++ b/lib/ain-ocean/src/data_acces/oracle_price_aggregated.rs @@ -1,9 +1,11 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::oracle_price_aggregated::OraclePriceAggregated; use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::oracle_price_aggregated::OraclePriceAggregated, +}; + pub struct OraclePriceAggrigatedDb { pub db: RocksDB, } diff --git a/lib/ain-ocean/src/data_acces/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/data_acces/oracle_price_aggregated_interval.rs index 109b44ed5fd..cb36cf9c3d0 100644 --- a/lib/ain-ocean/src/data_acces/oracle_price_aggregated_interval.rs +++ b/lib/ain-ocean/src/data_acces/oracle_price_aggregated_interval.rs @@ -1,9 +1,11 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::oracle_price_aggregated_interval::OraclePriceAggregatedInterval; use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::oracle_price_aggregated_interval::OraclePriceAggregatedInterval, +}; + pub struct OraclePriceAggregatedIntervalDb { pub db: RocksDB, } diff --git a/lib/ain-ocean/src/data_acces/oracle_token_currency.rs b/lib/ain-ocean/src/data_acces/oracle_token_currency.rs index f920f9b7d88..907e1633c94 100644 --- a/lib/ain-ocean/src/data_acces/oracle_token_currency.rs +++ b/lib/ain-ocean/src/data_acces/oracle_token_currency.rs @@ -1,9 +1,11 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::oracle_token_currency::OracleTokenCurrency; use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::oracle_token_currency::OracleTokenCurrency, +}; + pub struct OracleTokenCurrencyDb { pub db: RocksDB, } diff --git a/lib/ain-ocean/src/data_acces/order_history.rs b/lib/ain-ocean/src/data_acces/order_history.rs index abe2f673fa1..9b274c279c9 100644 --- a/lib/ain-ocean/src/data_acces/order_history.rs +++ b/lib/ain-ocean/src/data_acces/order_history.rs @@ -1,9 +1,11 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::oracle_history::OracleHistory; use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::oracle_history::OracleHistory, +}; + pub struct OracleHistoryDB { pub db: RocksDB, } diff --git a/lib/ain-ocean/src/data_acces/pool_swap.rs b/lib/ain-ocean/src/data_acces/pool_swap.rs index f61078f5272..ad5a6b2d89c 100644 --- a/lib/ain-ocean/src/data_acces/pool_swap.rs +++ b/lib/ain-ocean/src/data_acces/pool_swap.rs @@ -1,9 +1,11 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::poolswap::PoolSwap; use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::poolswap::PoolSwap, +}; + pub struct PoolSwapDb { pub db: RocksDB, } diff --git a/lib/ain-ocean/src/data_acces/pool_swap_aggregated.rs b/lib/ain-ocean/src/data_acces/pool_swap_aggregated.rs index 45f756f410d..9259760086e 100644 --- a/lib/ain-ocean/src/data_acces/pool_swap_aggregated.rs +++ b/lib/ain-ocean/src/data_acces/pool_swap_aggregated.rs @@ -1,9 +1,11 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::poolswap_aggregated::PoolSwapAggregated; use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::poolswap_aggregated::PoolSwapAggregated, +}; + pub struct PoolSwapAggregatedDb { pub db: RocksDB, } diff --git a/lib/ain-ocean/src/data_acces/price_ticker.rs b/lib/ain-ocean/src/data_acces/price_ticker.rs index e1987dde9bd..ac7e1a0140e 100644 --- a/lib/ain-ocean/src/data_acces/price_ticker.rs +++ b/lib/ain-ocean/src/data_acces/price_ticker.rs @@ -1,9 +1,11 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::price_ticker::PriceTicker; use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::price_ticker::PriceTicker, +}; + pub struct price_ticker { pub db: RocksDB, } diff --git a/lib/ain-ocean/src/data_acces/raw_block.rs b/lib/ain-ocean/src/data_acces/raw_block.rs index f859fc80f57..b2beb705bf4 100644 --- a/lib/ain-ocean/src/data_acces/raw_block.rs +++ b/lib/ain-ocean/src/data_acces/raw_block.rs @@ -1,9 +1,11 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::raw_block::RawBlock; use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::raw_block::RawBlock, +}; + #[derive(Debug)] pub struct RawBlockDb { pub db: RocksDB, diff --git a/lib/ain-ocean/src/data_acces/script_activity.rs b/lib/ain-ocean/src/data_acces/script_activity.rs index fcdc9985fdc..5a24394fa0a 100644 --- a/lib/ain-ocean/src/data_acces/script_activity.rs +++ b/lib/ain-ocean/src/data_acces/script_activity.rs @@ -1,10 +1,12 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::script_activity::ScriptActivity; use anyhow::{anyhow, Error, Result}; use serde::{Deserialize, Serialize}; use serde_json; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::script_activity::ScriptActivity, +}; + pub struct ScriptUnspentDB { pub db: RocksDB, } diff --git a/lib/ain-ocean/src/data_acces/script_aggregation.rs b/lib/ain-ocean/src/data_acces/script_aggregation.rs index 0b630ff0169..ec386717bad 100644 --- a/lib/ain-ocean/src/data_acces/script_aggregation.rs +++ b/lib/ain-ocean/src/data_acces/script_aggregation.rs @@ -1,10 +1,12 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::script_aggregation::ScriptAggregation; use anyhow::{anyhow, Error, Result}; use serde::{Deserialize, Serialize}; use serde_json; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::script_aggregation::ScriptAggregation, +}; + pub struct ScriptAggretionDB { pub db: RocksDB, } diff --git a/lib/ain-ocean/src/data_acces/script_unspent.rs b/lib/ain-ocean/src/data_acces/script_unspent.rs index e414384ac45..a5c1a462f08 100644 --- a/lib/ain-ocean/src/data_acces/script_unspent.rs +++ b/lib/ain-ocean/src/data_acces/script_unspent.rs @@ -1,10 +1,12 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::script_unspent::ScriptUnspent; use anyhow::{anyhow, Error, Result}; use serde::{Deserialize, Serialize}; use serde_json; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::script_unspent::ScriptUnspent, +}; + pub struct ScriptUnspentDB { pub db: RocksDB, } diff --git a/lib/ain-ocean/src/data_acces/test/oracle_test.rs b/lib/ain-ocean/src/data_acces/test/oracle_test.rs index 234388a7824..acaeed659cb 100644 --- a/lib/ain-ocean/src/data_acces/test/oracle_test.rs +++ b/lib/ain-ocean/src/data_acces/test/oracle_test.rs @@ -1,11 +1,14 @@ #[cfg(test)] mod tests { - use crate::data_acces::oracle::OracleDb; - use crate::database::db_manger::{ColumnFamilyOperations, RocksDB}; - use crate::model::oracle::{Oracle, OracleBlock, PriceFeedsItem}; use tempfile::tempdir; use tokio::task; + use crate::{ + data_acces::oracle::OracleDb, + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::oracle::{Oracle, OracleBlock, PriceFeedsItem}, + }; + // Function to set up a test database environment fn setup_test_db() -> OracleDb { let temp_dir = tempdir().unwrap(); diff --git a/lib/ain-ocean/src/data_acces/test/transaction_test.rs b/lib/ain-ocean/src/data_acces/test/transaction_test.rs index f835b40e3e9..bde9c788fba 100644 --- a/lib/ain-ocean/src/data_acces/test/transaction_test.rs +++ b/lib/ain-ocean/src/data_acces/test/transaction_test.rs @@ -1,13 +1,17 @@ #[cfg(test)] mod tests { - use crate::data_acces::transaction::TransactionVinDb; - use crate::data_acces::transaction_vout::TransactionVoutDb; - use crate::database::db_manger::{ColumnFamilyOperations, RocksDB}; - use crate::model::transaction::{Transaction, TransactionBlock}; - use crate::model::transaction_vout::{TransactionVout, TransactionVoutScript}; use tempfile::tempdir; use tokio::task; + use crate::{ + data_acces::{transaction::TransactionVinDb, transaction_vout::TransactionVoutDb}, + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::{ + transaction::{Transaction, TransactionBlock}, + transaction_vout::{TransactionVout, TransactionVoutScript}, + }, + }; + fn setup_test_db() -> TransactionVinDb { let temp_dir = tempdir().unwrap(); let db = RocksDB::new(temp_dir.path().to_str().unwrap()).unwrap(); diff --git a/lib/ain-ocean/src/data_acces/transaction.rs b/lib/ain-ocean/src/data_acces/transaction.rs index e16701aa77b..061074eb125 100644 --- a/lib/ain-ocean/src/data_acces/transaction.rs +++ b/lib/ain-ocean/src/data_acces/transaction.rs @@ -1,9 +1,11 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::transaction::Transaction; use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::transaction::Transaction, +}; + #[derive(Debug)] pub struct TransactionVinDb { pub db: RocksDB, diff --git a/lib/ain-ocean/src/data_acces/transaction_vin.rs b/lib/ain-ocean/src/data_acces/transaction_vin.rs index 1aae77ab1f5..8964743c4d2 100644 --- a/lib/ain-ocean/src/data_acces/transaction_vin.rs +++ b/lib/ain-ocean/src/data_acces/transaction_vin.rs @@ -1,9 +1,11 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::transaction_vin::TransactionVin; use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::transaction_vin::TransactionVin, +}; + #[derive(Debug)] pub struct TransactionVinDb { pub db: RocksDB, diff --git a/lib/ain-ocean/src/data_acces/transaction_vout.rs b/lib/ain-ocean/src/data_acces/transaction_vout.rs index 145e68b282e..9f11f982789 100644 --- a/lib/ain-ocean/src/data_acces/transaction_vout.rs +++ b/lib/ain-ocean/src/data_acces/transaction_vout.rs @@ -1,9 +1,11 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::transaction_vout::TransactionVout; use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::transaction_vout::TransactionVout, +}; + #[derive(Debug)] pub struct TransactionVoutDb { pub db: RocksDB, diff --git a/lib/ain-ocean/src/data_acces/vault_auction_batch_history.rs b/lib/ain-ocean/src/data_acces/vault_auction_batch_history.rs index 7d038be6477..eaf89997f83 100644 --- a/lib/ain-ocean/src/data_acces/vault_auction_batch_history.rs +++ b/lib/ain-ocean/src/data_acces/vault_auction_batch_history.rs @@ -1,10 +1,12 @@ -use crate::database::db_manger::ColumnFamilyOperations; -use crate::database::db_manger::RocksDB; -use crate::model::vault_auction_batch_history::VaultAuctionBatchHistory; use anyhow::{anyhow, Error, Result}; use serde::{Deserialize, Serialize}; use serde_json; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB}, + model::vault_auction_batch_history::VaultAuctionBatchHistory, +}; + pub struct VaultAuctionDB { pub db: RocksDB, } diff --git a/lib/ain-ocean/src/database/db_manger.rs b/lib/ain-ocean/src/database/db_manager.rs similarity index 97% rename from lib/ain-ocean/src/database/db_manger.rs rename to lib/ain-ocean/src/database/db_manager.rs index bdf9b851922..4a7392e186c 100644 --- a/lib/ain-ocean/src/database/db_manger.rs +++ b/lib/ain-ocean/src/database/db_manager.rs @@ -1,13 +1,14 @@ -use crate::model::oracle::Oracle; +use std::{collections::HashSet, sync::Arc}; + use anyhow::{anyhow, Result}; -use bitcoin::blockdata::block::Block; -use bitcoin::blockdata::block::Header; -use bitcoin::consensus::encode::serialize; -use rocksdb::Options; -use rocksdb::{ColumnFamilyDescriptor, DBIterator, IteratorMode, DB}; +use bitcoin::{ + blockdata::block::{Block, Header}, + consensus::encode::serialize, +}; +use rocksdb::{ColumnFamilyDescriptor, DBIterator, IteratorMode, Options, DB}; use serde::{Deserialize, Serialize}; -use std::collections::HashSet; -use std::sync::Arc; + +use crate::model::oracle::Oracle; #[derive(Debug)] pub struct RocksDB { diff --git a/lib/ain-ocean/src/database/mod.rs b/lib/ain-ocean/src/database/mod.rs index cec892297a8..3509674f499 100644 --- a/lib/ain-ocean/src/database/mod.rs +++ b/lib/ain-ocean/src/database/mod.rs @@ -1,3 +1,3 @@ pub mod config; -pub mod db_manger; +pub mod db_manager; pub mod db_test; From b3aee67778c8cf3f7d6922e0f4c2fb192dd05229 Mon Sep 17 00:00:00 2001 From: jouzo Date: Mon, 11 Dec 2023 13:30:36 +0100 Subject: [PATCH 010/185] Add -oceanarchive flag --- lib/Cargo.lock | 1 + lib/Cargo.toml | 3 +++ lib/ain-cpp-imports/src/bridge.rs | 1 + lib/ain-cpp-imports/src/lib.rs | 5 +++++ lib/ain-evm/Cargo.toml | 2 +- lib/ain-grpc/Cargo.toml | 2 +- lib/ain-ocean/Cargo.toml | 2 ++ lib/ain-ocean/src/api/mod.rs | 11 +++++++++- lib/ain-ocean/src/indexer/masternode.rs | 9 --------- lib/ain-ocean/src/indexer/mod.rs | 25 +++++++++++++---------- lib/ain-rs-exports/src/core.rs | 4 ---- lib/ain-rs-exports/src/lib.rs | 10 +++++++-- lib/ain-rs-exports/src/ocean.rs | 9 +++++++++ src/dfi/validation.cpp | 27 +++++++++++++++---------- src/ffi/ffiexports.cpp | 4 ++++ src/ffi/ffiexports.h | 4 +++- src/init.cpp | 2 +- 17 files changed, 79 insertions(+), 42 deletions(-) create mode 100644 lib/ain-rs-exports/src/ocean.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 81b7e9a882a..851320579e5 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -213,6 +213,7 @@ dependencies = [ name = "ain-ocean" version = "0.1.0" dependencies = [ + "ain-cpp-imports", "anyhow", "axum 0.7.2", "bitcoin", diff --git a/lib/Cargo.toml b/lib/Cargo.toml index d25737a1d76..c93ce948edb 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -120,3 +120,6 @@ substrate-bn = "0.6" #### Ocean dependencies dftx-rs = { git = "https://github.com/Jouzo/dftx-rs.git" } bitcoin = "0.31" + +### Local crates +ain-cpp-imports = { path = "./ain-cpp-imports" } diff --git a/lib/ain-cpp-imports/src/bridge.rs b/lib/ain-cpp-imports/src/bridge.rs index 0fef2eef915..5f009290f84 100644 --- a/lib/ain-cpp-imports/src/bridge.rs +++ b/lib/ain-cpp-imports/src/bridge.rs @@ -60,5 +60,6 @@ pub mod ffi { fn getEvmNotificationChannelBufferSize() -> usize; fn isEthDebugRPCEnabled() -> bool; fn isEthDebugTraceRPCEnabled() -> bool; + fn isOceanEnabled() -> bool; } } diff --git a/lib/ain-cpp-imports/src/lib.rs b/lib/ain-cpp-imports/src/lib.rs index e7f3610f048..6a7a4875be7 100644 --- a/lib/ain-cpp-imports/src/lib.rs +++ b/lib/ain-cpp-imports/src/lib.rs @@ -305,5 +305,10 @@ pub fn is_eth_debug_trace_rpc_enabled() -> bool { ffi::isEthDebugTraceRPCEnabled() } +/// Checks if Ocean REST API is enabled +pub fn is_ocean_rest_enabled() -> bool { + ffi::isOceanEnabled() +} + #[cfg(test)] mod tests {} diff --git a/lib/ain-evm/Cargo.toml b/lib/ain-evm/Cargo.toml index f5feaea9658..debd8a18640 100644 --- a/lib/ain-evm/Cargo.toml +++ b/lib/ain-evm/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -ain-cpp-imports = { path = "../ain-cpp-imports" } +ain-cpp-imports.workspace = true ain-contracts = { path = "../ain-contracts" } evm = { workspace = true, default-features = false, features = ["with-serde", "tracing", "std"] } diff --git a/lib/ain-grpc/Cargo.toml b/lib/ain-grpc/Cargo.toml index 0615ed5d30c..87bf61c0ede 100644 --- a/lib/ain-grpc/Cargo.toml +++ b/lib/ain-grpc/Cargo.toml @@ -6,7 +6,7 @@ build = "build.rs" [dependencies] ain-evm = { path = "../ain-evm" } -ain-cpp-imports = { path = "../ain-cpp-imports" } +ain-cpp-imports.workspace = true ain-ocean = { path = "../ain-ocean" } cxx.workspace = true env_logger.workspace = true diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index a695e522ca2..3ecf06c9b23 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +ain-cpp-imports.workspace = true + axum.workspace = true hyper.workspace = true keccak-hash.workspace = true diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index 4fc8d80da8d..a81ea84f9ec 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -1,4 +1,4 @@ -use axum::Router; +use axum::{http::StatusCode, response::IntoResponse, Router}; mod address; mod block; @@ -13,8 +13,17 @@ mod rawtx; mod stats; mod tokens; mod transactions; +use axum::routing::get; + +async fn ocean_not_activated() -> impl IntoResponse { + (StatusCode::FORBIDDEN, "Ocean is not activated") +} pub fn ocean_router() -> Router { + if !ain_cpp_imports::is_ocean_rest_enabled() { + return Router::new().route("/*path", get(ocean_not_activated)); + } + Router::new() .nest("/address", address::router()) .nest("/governance", governance::router()) diff --git a/lib/ain-ocean/src/indexer/masternode.rs b/lib/ain-ocean/src/indexer/masternode.rs index fe90f1cb48c..92edb99c7af 100644 --- a/lib/ain-ocean/src/indexer/masternode.rs +++ b/lib/ain-ocean/src/indexer/masternode.rs @@ -33,15 +33,6 @@ impl Index for CreateMasternode { history: None, }; - let mut file = std::fs::OpenOptions::new() - .write(true) - .create(true) - .append(true) - .open("/tmp/masternode") - .expect("Unable to open file"); - - writeln!(file, "{:?}", masternode).expect("Unable to write to file"); - Ok(()) } diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 2bc71390a40..dba852636aa 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -14,6 +14,7 @@ pub(crate) trait Index { use bitcoin::BlockHash; use dftx_rs::{deserialize, Block, DfTx}; +use log::debug; pub(crate) struct BlockContext { height: u32, @@ -23,6 +24,8 @@ pub(crate) struct BlockContext { } pub fn index_block(block: String, block_height: u32) -> Result<()> { + debug!("[index_block] Indexing block..."); + let hex = hex::decode(block)?; let block = deserialize::(&hex)?; @@ -49,15 +52,15 @@ pub fn index_block(block: String, block_height: u32) -> Result<()> { match dftx { DfTx::CreateMasternode(data) => data.index(&context, tx)?, - DfTx::UpdateMasternode(data) => data.index(&context, tx)?, - DfTx::ResignMasternode(data) => data.index(&context, tx)?, - DfTx::AppointOracle(data) => data.index(&context, tx)?, - DfTx::RemoveOracle(data) => data.index(&context, tx)?, - DfTx::UpdateOracle(data) => data.index(&context, tx)?, - DfTx::SetOracleData(data) => data.index(&context, tx)?, - DfTx::PoolSwap(data) => data.index(&context, tx)?, - DfTx::CompositeSwap(data) => data.index(&context, tx)?, - DfTx::PlaceAuctionBid(data) => data.index(&context, tx)?, + // DfTx::UpdateMasternode(data) => data.index(&context, tx)?, + // DfTx::ResignMasternode(data) => data.index(&context, tx)?, + // DfTx::AppointOracle(data) => data.index(&context, tx)?, + // DfTx::RemoveOracle(data) => data.index(&context, tx)?, + // DfTx::UpdateOracle(data) => data.index(&context, tx)?, + // DfTx::SetOracleData(data) => data.index(&context, tx)?, + // DfTx::PoolSwap(data) => data.index(&context, tx)?, + // DfTx::CompositeSwap(data) => data.index(&context, tx)?, + // DfTx::PlaceAuctionBid(data) => data.index(&context, tx)?, _ => (), } } @@ -65,6 +68,6 @@ pub fn index_block(block: String, block_height: u32) -> Result<()> { Ok(()) } -pub fn invalidate_block() { - todo!() +pub fn invalidate_block(block: String, block_height: u32) -> Result<()> { + Ok(()) } diff --git a/lib/ain-rs-exports/src/core.rs b/lib/ain-rs-exports/src/core.rs index 29d1cc4a232..91209548ec5 100644 --- a/lib/ain-rs-exports/src/core.rs +++ b/lib/ain-rs-exports/src/core.rs @@ -61,7 +61,3 @@ pub fn ain_rs_wipe_evm_folder() -> Result<()> { ain_grpc::wipe_evm_folder()?; Ok(()) } - -pub fn ocean_index_block(block: String, block_height: u32) { - ain_ocean::index_block(block, block_height); -} diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index 0e0c3b6dc3f..1f4c68db583 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -1,12 +1,13 @@ mod core; mod debug; mod evm; +mod ocean; mod prelude; mod util; use ain_evm::blocktemplate::BlockTemplate; -use crate::{core::*, debug::*, evm::*, util::*}; +use crate::{core::*, debug::*, evm::*, ocean::*, util::*}; pub struct BlockTemplateWrapper(Option); @@ -345,7 +346,12 @@ pub mod ffi { fn evm_try_flush_db(result: &mut CrossBoundaryResult); - fn ocean_index_block(block: String, block_height: u32); + fn ocean_index_block(result: &mut CrossBoundaryResult, block: String, block_height: u32); + fn ocean_invalidate_block( + result: &mut CrossBoundaryResult, + block: String, + block_height: u32, + ); } // ========= Debug ========== diff --git a/lib/ain-rs-exports/src/ocean.rs b/lib/ain-rs-exports/src/ocean.rs new file mode 100644 index 00000000000..fd00b0a89a6 --- /dev/null +++ b/lib/ain-rs-exports/src/ocean.rs @@ -0,0 +1,9 @@ +use crate::ffi::CrossBoundaryResult; + +pub fn ocean_index_block(_result: &mut CrossBoundaryResult, block: String, block_height: u32) { + ain_ocean::index_block(block, block_height); +} + +pub fn ocean_invalidate_block(_result: &mut CrossBoundaryResult, block: String, block_height: u32) { + ain_ocean::invalidate_block(block, block_height); +} diff --git a/src/dfi/validation.cpp b/src/dfi/validation.cpp index 1cc541dafe8..7b2e50f026a 100644 --- a/src/dfi/validation.cpp +++ b/src/dfi/validation.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -2788,6 +2789,21 @@ Res ProcessDeFiEventFallible(const CBlock &block, // Construct undo FlushCacheCreateUndo(pindex, mnview, cache, uint256S(std::string(64, '1'))); + // Ocean archive + if (gArgs.GetBoolArg("-oceanarchive", DEFAULT_OCEAN_ARCHIVE_ENABLED)) { + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << block; + + // Convert the serialized data to a string + std::string serializedData = HexStr(ss.begin(), ss.end()); + + CrossBoundaryResult result; + ocean_index_block(result, serializedData, pindex->nHeight); + if (!result.ok) { + return Res::Err(result.reason.c_str()); + } + } + return Res::Ok(); } @@ -2854,15 +2870,4 @@ void ProcessDeFiEvent(const CBlock &block, // construct undo FlushCacheCreateUndo(pindex, mnview, cache, uint256()); - - // Ocean archive - const auto oceanArchive{true}; - if (oceanArchive) { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << block; - - // Convert the serialized data to a string - std::string serializedData = HexStr(ss.begin(), ss.end()); - ocean_index_block(serializedData, pindex->nHeight); - } } diff --git a/src/ffi/ffiexports.cpp b/src/ffi/ffiexports.cpp index 6d418fabf99..3eb81ba89cc 100644 --- a/src/ffi/ffiexports.cpp +++ b/src/ffi/ffiexports.cpp @@ -386,3 +386,7 @@ bool isEthDebugRPCEnabled() { bool isEthDebugTraceRPCEnabled() { return gArgs.GetBoolArg("-ethdebugtrace", DEFAULT_ETH_DEBUG_TRACE_ENABLED); } + +bool isOceanEnabled() { + return gArgs.GetBoolArg("-oceanarchive", DEFAULT_OCEAN_ARCHIVE_ENABLED); +} diff --git a/src/ffi/ffiexports.h b/src/ffi/ffiexports.h index 97a6665a2f5..748fb4c9d5c 100644 --- a/src/ffi/ffiexports.h +++ b/src/ffi/ffiexports.h @@ -29,6 +29,8 @@ static constexpr bool DEFAULT_ETH_DEBUG_ENABLED = false; static constexpr bool DEFAULT_ETH_DEBUG_TRACE_ENABLED = true; static constexpr bool DEFAULT_ETH_SUBSCRIPTION_ENABLED = true; +static constexpr bool DEFAULT_OCEAN_ARCHIVE_ENABLED = false; + struct Attributes { uint64_t blockGasTargetFactor; uint64_t blockGasLimit; @@ -99,6 +101,6 @@ size_t getEvmValidationLruCacheCount(); size_t getEvmNotificationChannelBufferSize(); bool isEthDebugRPCEnabled(); bool isEthDebugTraceRPCEnabled(); -bool isEthSubscriptionEnabled(); +bool isOceanEnabled(); #endif // DEFI_FFI_FFIEXPORTS_H diff --git a/src/init.cpp b/src/init.cpp index bd6f3f11a9b..c668d65c1ec 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -668,7 +668,7 @@ void SetupServerArgs() gArgs.AddArg("-ethmaxresponsesize=", strprintf("Set the maximum response size in MB by the ETH-RPC server (default: %u, testnet: %u, changi: %u, devnet: %u, regtest: %u)", DEFAULT_ETH_MAX_RESPONSE_SIZE_MB, DEFAULT_ETH_MAX_RESPONSE_SIZE_MB, DEFAULT_ETH_MAX_RESPONSE_SIZE_MB, DEFAULT_ETH_MAX_RESPONSE_SIZE_MB, DEFAULT_ETH_MAX_RESPONSE_SIZE_MB), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC); gArgs.AddArg("-ethdebug", strprintf("Enable debug_* ETH RPCs (default: %b)", DEFAULT_ETH_DEBUG_ENABLED), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); gArgs.AddArg("-ethdebugtrace", strprintf("Enable debug_trace* ETH RPCs (default: %b)", DEFAULT_ETH_DEBUG_TRACE_ENABLED), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); - gArgs.AddArg("-ethsubscription", strprintf("Enable subscription notifications ETH RPCs (default: %b)", DEFAULT_ETH_SUBSCRIPTION_ENABLED), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); + gArgs.AddArg("-oceanarchive", strprintf("Enable ocean archive and REST server (default: %b)", DEFAULT_OCEAN_ARCHIVE_ENABLED), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); #if HAVE_DECL_DAEMON gArgs.AddArg("-daemon", "Run in the background as a daemon and accept commands", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); From 5a067b0bc6f30607328a97f2eec48edca984ee47 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Wed, 13 Dec 2023 18:28:29 +0800 Subject: [PATCH 011/185] Ocean API MN typing (#2744) * pagination query * poolpair path api path * mild refactor on error.rs and block.rs * masternode typing * rm debug_handler * extra line * default masternodestate * fix return type * typo * pub enum state * missing import * clone * simplified mn --- lib/ain-ocean/src/api/block.rs | 29 +++++----- lib/ain-ocean/src/api/masternode.rs | 22 +++++-- lib/ain-ocean/src/api/poolpairs.rs | 4 +- lib/ain-ocean/src/api_query.rs | 8 +++ lib/ain-ocean/src/error.rs | 3 +- lib/ain-ocean/src/lib.rs | 1 + lib/ain-ocean/src/model/masternode.rs | 82 +++++++++++++++++++++++++++ 7 files changed, 124 insertions(+), 25 deletions(-) create mode 100644 lib/ain-ocean/src/api_query.rs diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 80c8191b903..8da1ba7cca3 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -1,12 +1,15 @@ use axum::{ - debug_handler, extract::{Path, Query}, routing::get, Json, Router, }; use serde::{Deserialize, Serialize}; -use crate::api_paged_response::ApiPagedResponse; +use crate::{ + api_paged_response::ApiPagedResponse, + api_query::PaginationQuery, + error::OceanResult, +}; #[derive(Deserialize)] struct BlockId { @@ -18,29 +21,23 @@ struct BlockHash { hash: String, } -#[derive(Deserialize)] -pub struct ListBlocksQuery { - pub size: usize, - pub next: Option, -} - -#[debug_handler] -async fn list_blocks(Query(query): Query) -> Json> { - // TODO(): query from db - // db::block::list(req).await... +async fn list_blocks(Query(query): Query) -> OceanResult>> { + // TODO(): query from lvldb.. or maybe pull from index let blocks = vec![ Block { id: "0".into() }, Block { id: "1".into() }, Block { id: "2".into() }, ]; - Json(ApiPagedResponse::of(blocks, query.size, |block| { + Ok(Json(ApiPagedResponse::of(blocks, query.size, |block| { block.clone().id - })) + }))) } -async fn get_block(Path(BlockId { id }): Path) -> String { - format!("Details of block with id {}", id) +async fn get_block(Path(BlockId { id }): Path) -> OceanResult> { + Ok(Json(Block { + id, + })) } async fn get_transactions(Path(BlockHash { hash }): Path) -> String { diff --git a/lib/ain-ocean/src/api/masternode.rs b/lib/ain-ocean/src/api/masternode.rs index a15e184fd23..6b7011fab93 100644 --- a/lib/ain-ocean/src/api/masternode.rs +++ b/lib/ain-ocean/src/api/masternode.rs @@ -1,11 +1,23 @@ -use axum::{extract::Path, routing::get, Router}; +use axum::{extract::{Path, Query}, routing::get, Router, Json}; -async fn list_masternodes() -> String { - "List of masternodes".to_string() +use crate::{ + api_paged_response::ApiPagedResponse, + api_query::PaginationQuery, + error::OceanResult, + model::masternode::MasternodeData, +}; + +async fn list_masternodes(Query(query): Query) -> OceanResult>> { + let masternodes = vec![ + MasternodeData::new("0"), + ]; + Ok(Json(ApiPagedResponse::of(masternodes, query.size, |masternode| { + masternode.clone().id + }))) } -async fn get_masternode(Path(masternode_id): Path) -> String { - format!("Details of masternode with id {}", masternode_id) +async fn get_masternode(Path(masternode_id): Path) -> OceanResult> { + Ok(Json(MasternodeData::new(&masternode_id))) } pub fn router() -> Router { diff --git a/lib/ain-ocean/src/api/poolpairs.rs b/lib/ain-ocean/src/api/poolpairs.rs index 59500949387..f20fd790e66 100644 --- a/lib/ain-ocean/src/api/poolpairs.rs +++ b/lib/ain-ocean/src/api/poolpairs.rs @@ -100,7 +100,7 @@ pub fn router() -> Router { get(list_pool_swap_aggregates), ) .route("/paths/swappable/:tokenId", get(get_swappable_tokens)) - .route("/paths/best", get(get_best_path)) - .route("/paths", get(get_all_paths)) + .route("/paths/best/from/:fromTokenId/to/:toTokenId", get(get_best_path)) + .route("/paths/from/:fromTokenId/to/:toTokenId", get(get_all_paths)) .route("/dexprices", get(list_dex_prices)) } diff --git a/lib/ain-ocean/src/api_query.rs b/lib/ain-ocean/src/api_query.rs new file mode 100644 index 00000000000..fcd1dadea8f --- /dev/null +++ b/lib/ain-ocean/src/api_query.rs @@ -0,0 +1,8 @@ +use serde::Deserialize; + +#[derive(Deserialize)] +pub struct PaginationQuery { + pub size: usize, + pub next: Option +} + diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 1a037199cc0..e0be55ee79c 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -2,11 +2,10 @@ use axum::{ http::StatusCode, response::{IntoResponse, Response}, }; -use thiserror::Error; pub type OceanResult = Result; -#[derive(Error, Debug)] +#[derive(thiserror::Error, Debug)] pub enum OceanError {} impl IntoResponse for OceanError { diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 547943eaaa7..15af10216db 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -1,4 +1,5 @@ pub mod api_paged_response; +pub mod api_query; pub mod error; mod indexer; diff --git a/lib/ain-ocean/src/model/masternode.rs b/lib/ain-ocean/src/model/masternode.rs index 27f1608dcac..168bfbad777 100644 --- a/lib/ain-ocean/src/model/masternode.rs +++ b/lib/ain-ocean/src/model/masternode.rs @@ -25,6 +25,88 @@ pub struct MasternodeBlock { pub median_time: u64, } +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +pub enum MasternodeState { + PreEnabled, + Enabled, + PreResigned, + Resigned, + PreBanned, + Banned, + #[default] + Unknown, +} + +impl std::fmt::Display for MasternodeState { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + MasternodeState::PreEnabled => write!(f, "PRE_ENABLED"), + MasternodeState::Enabled => write!(f, "ENABLED"), + MasternodeState::PreResigned => write!(f, "PRE_RESIGNED"), + MasternodeState::Resigned => write!(f, "RESIGNED"), + MasternodeState::PreBanned => write!(f, "PRE_BANNED"), + MasternodeState::Banned => write!(f, "BANNED"), + MasternodeState::Unknown => write!(f, "UNKNOWN"), + } + } +} + +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +pub struct MasternodeOwner { + pub address: String, +} + +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +pub struct MasternodeOperator { + pub address: String, +} + +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +pub struct MasternodeCreation { + pub height: i32, +} + +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +pub struct MasternodeResign { + pub tx: String, + pub height: i32, +} + +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +#[serde(rename_all = "camelCase")] +pub struct MasternodeData { + pub id: String, + pub sort: String, + pub state: MasternodeState, + pub minted_blocks: i32, + pub owner: MasternodeOwner, + pub operator: MasternodeOperator, + pub creation: MasternodeCreation, + pub resign: Option, + pub timelock: i32, +} +impl MasternodeData { + pub fn new(id: &str) -> Self { + Self { + id: id.repeat(64), + sort: id.repeat(72), + state: MasternodeState::Enabled, + minted_blocks: 2, + owner: MasternodeOwner { + address: id.repeat(34), + }, + operator: MasternodeOperator { + address: id.repeat(34), + }, + creation: MasternodeCreation { + height: 0 + }, + resign: None, + timelock: 0 + } + } +} + #[derive(Serialize, Deserialize, Debug, Default)] #[serde(rename_all = "camelCase")] pub struct HistoryItem { From c2885f3163e659b777161906aa1e33e677b12428 Mon Sep 17 00:00:00 2001 From: jouzo Date: Tue, 19 Dec 2023 13:24:08 +0100 Subject: [PATCH 012/185] Adds cached crate --- lib/Cargo.lock | 86 ++++++++++++++++++++++++++++++++++++++-- lib/Cargo.toml | 1 + lib/ain-ocean/Cargo.toml | 1 + 3 files changed, 84 insertions(+), 4 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 851320579e5..d633ae8b02f 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -218,6 +218,7 @@ dependencies = [ "axum 0.7.2", "bitcoin", "bitcoin_hashes 0.12.0", + "cached", "ctrlc", "dftx-rs", "futures", @@ -873,6 +874,39 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "cached" +version = "0.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c8c50262271cdf5abc979a5f76515c234e764fa025d1ba4862c0f0bcda0e95" +dependencies = [ + "ahash 0.8.6", + "cached_proc_macro", + "cached_proc_macro_types", + "hashbrown 0.14.3", + "instant", + "once_cell", + "thiserror", +] + +[[package]] +name = "cached_proc_macro" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c878c71c2821aa2058722038a59a67583a4240524687c6028571c9b395ded61f" +dependencies = [ + "darling 0.14.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cached_proc_macro_types" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663" + [[package]] name = "cc" version = "1.0.83" @@ -1223,14 +1257,38 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + [[package]] name = "darling" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.3", + "darling_macro 0.20.3", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 1.0.109", ] [[package]] @@ -1247,13 +1305,24 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + [[package]] name = "darling_macro" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ - "darling_core", + "darling_core 0.20.3", "quote", "syn 2.0.39", ] @@ -2519,6 +2588,15 @@ dependencies = [ "generic-array 0.14.7", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "io-lifetimes" version = "1.0.11" @@ -4808,7 +4886,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" dependencies = [ - "darling", + "darling 0.20.3", "proc-macro2", "quote", "syn 2.0.39", diff --git a/lib/Cargo.toml b/lib/Cargo.toml index c93ce948edb..beb7be70522 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -120,6 +120,7 @@ substrate-bn = "0.6" #### Ocean dependencies dftx-rs = { git = "https://github.com/Jouzo/dftx-rs.git" } bitcoin = "0.31" +cached = "0.46" ### Local crates ain-cpp-imports = { path = "./ain-cpp-imports" } diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index 3ecf06c9b23..defc49f40fe 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -31,3 +31,4 @@ bitcoin_hashes = "0.12.0" structopt = { version = "0.3", default-features = false } tempfile = "3.8.1" anyhow.workspace = true +cached.workspace = true From 491362b76945c2071f1d404c768fab714493ec7f Mon Sep 17 00:00:00 2001 From: jouzo Date: Wed, 20 Dec 2023 09:31:47 +0100 Subject: [PATCH 013/185] Fix format --- lib/ain-cpp-imports/src/lib.rs | 3 +++ lib/ain-ocean/src/api/block.rs | 14 +++++--------- lib/ain-ocean/src/api/masternode.rs | 26 +++++++++++++++----------- lib/ain-ocean/src/api/poolpairs.rs | 5 ++++- lib/ain-ocean/src/api_query.rs | 3 +-- lib/ain-ocean/src/database/config.rs | 4 ++-- lib/ain-ocean/src/model/masternode.rs | 26 ++++++++++++-------------- src/dfi/validation.cpp | 2 +- 8 files changed, 43 insertions(+), 40 deletions(-) diff --git a/lib/ain-cpp-imports/src/lib.rs b/lib/ain-cpp-imports/src/lib.rs index 6a7a4875be7..eeccccb108e 100644 --- a/lib/ain-cpp-imports/src/lib.rs +++ b/lib/ain-cpp-imports/src/lib.rs @@ -124,6 +124,9 @@ mod ffi { pub fn isEthDebugTraceRPCEnabled() -> bool { unimplemented!("{}", UNIMPL_MSG) } + pub fn isOceanEnabled() -> bool { + unimplemented!("{}", UNIMPL_MSG) + } } pub use ffi::Attributes; diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 8da1ba7cca3..3113f8003d4 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -5,11 +5,7 @@ use axum::{ }; use serde::{Deserialize, Serialize}; -use crate::{ - api_paged_response::ApiPagedResponse, - api_query::PaginationQuery, - error::OceanResult, -}; +use crate::{api_paged_response::ApiPagedResponse, api_query::PaginationQuery, error::OceanResult}; #[derive(Deserialize)] struct BlockId { @@ -21,7 +17,9 @@ struct BlockHash { hash: String, } -async fn list_blocks(Query(query): Query) -> OceanResult>> { +async fn list_blocks( + Query(query): Query, +) -> OceanResult>> { // TODO(): query from lvldb.. or maybe pull from index let blocks = vec![ Block { id: "0".into() }, @@ -35,9 +33,7 @@ async fn list_blocks(Query(query): Query) -> OceanResult) -> OceanResult> { - Ok(Json(Block { - id, - })) + Ok(Json(Block { id })) } async fn get_transactions(Path(BlockHash { hash }): Path) -> String { diff --git a/lib/ain-ocean/src/api/masternode.rs b/lib/ain-ocean/src/api/masternode.rs index 6b7011fab93..f0b0408e63b 100644 --- a/lib/ain-ocean/src/api/masternode.rs +++ b/lib/ain-ocean/src/api/masternode.rs @@ -1,19 +1,23 @@ -use axum::{extract::{Path, Query}, routing::get, Router, Json}; +use axum::{ + extract::{Path, Query}, + routing::get, + Json, Router, +}; use crate::{ - api_paged_response::ApiPagedResponse, - api_query::PaginationQuery, - error::OceanResult, + api_paged_response::ApiPagedResponse, api_query::PaginationQuery, error::OceanResult, model::masternode::MasternodeData, }; -async fn list_masternodes(Query(query): Query) -> OceanResult>> { - let masternodes = vec![ - MasternodeData::new("0"), - ]; - Ok(Json(ApiPagedResponse::of(masternodes, query.size, |masternode| { - masternode.clone().id - }))) +async fn list_masternodes( + Query(query): Query, +) -> OceanResult>> { + let masternodes = vec![MasternodeData::new("0")]; + Ok(Json(ApiPagedResponse::of( + masternodes, + query.size, + |masternode| masternode.clone().id, + ))) } async fn get_masternode(Path(masternode_id): Path) -> OceanResult> { diff --git a/lib/ain-ocean/src/api/poolpairs.rs b/lib/ain-ocean/src/api/poolpairs.rs index f20fd790e66..d8a89dcc1e3 100644 --- a/lib/ain-ocean/src/api/poolpairs.rs +++ b/lib/ain-ocean/src/api/poolpairs.rs @@ -100,7 +100,10 @@ pub fn router() -> Router { get(list_pool_swap_aggregates), ) .route("/paths/swappable/:tokenId", get(get_swappable_tokens)) - .route("/paths/best/from/:fromTokenId/to/:toTokenId", get(get_best_path)) + .route( + "/paths/best/from/:fromTokenId/to/:toTokenId", + get(get_best_path), + ) .route("/paths/from/:fromTokenId/to/:toTokenId", get(get_all_paths)) .route("/dexprices", get(list_dex_prices)) } diff --git a/lib/ain-ocean/src/api_query.rs b/lib/ain-ocean/src/api_query.rs index fcd1dadea8f..fd831456678 100644 --- a/lib/ain-ocean/src/api_query.rs +++ b/lib/ain-ocean/src/api_query.rs @@ -3,6 +3,5 @@ use serde::Deserialize; #[derive(Deserialize)] pub struct PaginationQuery { pub size: usize, - pub next: Option + pub next: Option, } - diff --git a/lib/ain-ocean/src/database/config.rs b/lib/ain-ocean/src/database/config.rs index 39d2fa15046..bcb21665287 100644 --- a/lib/ain-ocean/src/database/config.rs +++ b/lib/ain-ocean/src/database/config.rs @@ -1,6 +1,6 @@ +use std::{env, fs, path::PathBuf}; + use serde::{Deserialize, Serialize}; -use std::path::PathBuf; -use std::{env, fs}; use structopt::StructOpt; #[derive(Debug, Clone, Serialize, Deserialize, StructOpt)] diff --git a/lib/ain-ocean/src/model/masternode.rs b/lib/ain-ocean/src/model/masternode.rs index 168bfbad777..f180ca7aa22 100644 --- a/lib/ain-ocean/src/model/masternode.rs +++ b/lib/ain-ocean/src/model/masternode.rs @@ -39,15 +39,15 @@ pub enum MasternodeState { impl std::fmt::Display for MasternodeState { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - MasternodeState::PreEnabled => write!(f, "PRE_ENABLED"), - MasternodeState::Enabled => write!(f, "ENABLED"), - MasternodeState::PreResigned => write!(f, "PRE_RESIGNED"), - MasternodeState::Resigned => write!(f, "RESIGNED"), - MasternodeState::PreBanned => write!(f, "PRE_BANNED"), - MasternodeState::Banned => write!(f, "BANNED"), - MasternodeState::Unknown => write!(f, "UNKNOWN"), - } + match self { + MasternodeState::PreEnabled => write!(f, "PRE_ENABLED"), + MasternodeState::Enabled => write!(f, "ENABLED"), + MasternodeState::PreResigned => write!(f, "PRE_RESIGNED"), + MasternodeState::Resigned => write!(f, "RESIGNED"), + MasternodeState::PreBanned => write!(f, "PRE_BANNED"), + MasternodeState::Banned => write!(f, "BANNED"), + MasternodeState::Unknown => write!(f, "UNKNOWN"), + } } } @@ -98,12 +98,10 @@ impl MasternodeData { operator: MasternodeOperator { address: id.repeat(34), }, - creation: MasternodeCreation { - height: 0 - }, + creation: MasternodeCreation { height: 0 }, resign: None, - timelock: 0 - } + timelock: 0, + } } } diff --git a/src/dfi/validation.cpp b/src/dfi/validation.cpp index 7b2e50f026a..0574c19b129 100644 --- a/src/dfi/validation.cpp +++ b/src/dfi/validation.cpp @@ -18,8 +18,8 @@ #include #include #include -#include #include +#include #include #include From 4c5b0902c1526abc5b036464755e13acd932e88f Mon Sep 17 00:00:00 2001 From: Nagaraj <144004792+nagarajm22@users.noreply.github.com> Date: Wed, 20 Dec 2023 00:34:18 -0800 Subject: [PATCH 014/185] WIP: Ocean API database implementation to all modules (#2748) * added block indexing * added block indexing and query method * added query methods and extra table * added query methods to modules * added oracle price active and prive feed module * added oracle price active and prive feed module * rebased indexing ocean-archive * rebased indexing ocean-archive and updated query methods all modules * rebased indexing ocean-archive and updated query methods all modules * fixed white space * fixed white space * fixed query method for masternode and masterstats --- lib/Cargo.lock | 147 ++++++------ lib/ain-evm/src/storage/block_store.rs | 1 - lib/ain-ocean/Cargo.toml | 3 + lib/ain-ocean/src/data_acces/block.rs | 164 +++++++++++-- lib/ain-ocean/src/data_acces/masternode.rs | 42 +++- .../src/data_acces/masternode_states.rs | 66 ------ .../src/data_acces/masternode_stats.rs | 110 +++++++++ lib/ain-ocean/src/data_acces/mod.rs | 4 +- lib/ain-ocean/src/data_acces/oracle.rs | 35 ++- .../src/data_acces/oracle_price_active.rs | 67 ++++++ .../src/data_acces/oracle_price_aggregated.rs | 51 +++- .../oracle_price_aggregated_interval.rs | 31 ++- .../src/data_acces/oracle_price_feed.rs | 66 ++++++ .../src/data_acces/oracle_token_currency.rs | 41 +++- lib/ain-ocean/src/data_acces/order_history.rs | 45 +++- lib/ain-ocean/src/data_acces/pool_swap.rs | 39 +++- .../src/data_acces/pool_swap_aggregated.rs | 36 ++- lib/ain-ocean/src/data_acces/price_ticker.rs | 35 ++- lib/ain-ocean/src/data_acces/raw_block.rs | 1 - .../src/data_acces/script_activity.rs | 52 ++++- .../src/data_acces/script_aggregation.rs | 67 +++++- .../src/data_acces/script_unspent.rs | 45 +++- .../src/data_acces/test/block_test.rs | 217 ++++++++++++++++++ .../src/data_acces/test/masternode_test.rs | 82 +++++++ lib/ain-ocean/src/data_acces/test/mod.rs | 2 + .../src/data_acces/test/transaction_test.rs | 16 ++ lib/ain-ocean/src/data_acces/transaction.rs | 63 ++++- .../src/data_acces/transaction_vin.rs | 47 +++- .../src/data_acces/transaction_vout.rs | 70 ++++-- .../data_acces/vault_auction_batch_history.rs | 3 +- lib/ain-ocean/src/database/db_manager.rs | 17 +- lib/ain-ocean/src/model/block.rs | 2 +- lib/ain-ocean/src/model/poolswap.rs | 4 +- 33 files changed, 1399 insertions(+), 272 deletions(-) delete mode 100644 lib/ain-ocean/src/data_acces/masternode_states.rs create mode 100644 lib/ain-ocean/src/data_acces/masternode_stats.rs create mode 100644 lib/ain-ocean/src/data_acces/oracle_price_active.rs create mode 100644 lib/ain-ocean/src/data_acces/oracle_price_feed.rs create mode 100644 lib/ain-ocean/src/data_acces/test/block_test.rs create mode 100644 lib/ain-ocean/src/data_acces/test/masternode_test.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index d633ae8b02f..eb7dc80c48a 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -192,7 +192,7 @@ dependencies = [ "serde_json", "serde_with", "sha3", - "syn 2.0.39", + "syn 2.0.41", "tokio", "tonic", "tonic-build", @@ -206,7 +206,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -218,6 +218,7 @@ dependencies = [ "axum 0.7.2", "bitcoin", "bitcoin_hashes 0.12.0", + "chrono", "cached", "ctrlc", "dftx-rs", @@ -380,7 +381,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -424,7 +425,7 @@ dependencies = [ "bytes", "futures-util", "http 0.2.11", - "http-body 0.4.5", + "http-body 0.4.6", "hyper 0.14.27", "itoa", "matchit", @@ -484,7 +485,7 @@ dependencies = [ "bytes", "futures-util", "http 0.2.11", - "http-body 0.4.5", + "http-body 0.4.6", "mime", "rustversion", "tower-layer", @@ -520,7 +521,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -614,7 +615,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -940,8 +941,10 @@ checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", "serde", + "wasm-bindgen", "windows-targets 0.48.5", ] @@ -1225,7 +1228,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -1237,7 +1240,7 @@ dependencies = [ "codespan-reporting", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -1254,7 +1257,7 @@ checksum = "587663dd5fb3d10932c8aecfe7c844db1bcf0aee93eeab08fac13dc1212c2e7f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -1302,7 +1305,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -1324,7 +1327,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core 0.20.3", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -1360,9 +1363,9 @@ dependencies = [ [[package]] name = "deunicode" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a1abaf4d861455be59f64fd2b55606cb151fce304ede7165f410243ce96bde6" +checksum = "3ae2a35373c5c74340b79ae6780b498b2b183915ec5dacf263aac5a099bf485a" [[package]] name = "dftx-macro" @@ -1371,7 +1374,7 @@ source = "git+https://github.com/Jouzo/dftx-rs.git#7973f1ad240d5f7724e51c6b090bc dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -1987,7 +1990,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -2332,9 +2335,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http 0.2.11", @@ -2400,7 +2403,7 @@ dependencies = [ "futures-util", "h2 0.3.22", "http 0.2.11", - "http-body 0.4.5", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -2631,7 +2634,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi 0.3.3", - "rustix 0.38.26", + "rustix 0.38.28", "windows-sys 0.48.0", ] @@ -2655,9 +2658,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "jobserver" @@ -3071,9 +3074,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "libloading" @@ -3289,7 +3292,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix 0.38.26", + "rustix 0.38.28", ] [[package]] @@ -3571,7 +3574,7 @@ dependencies = [ "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -3597,9 +3600,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" @@ -3839,7 +3842,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -3877,7 +3880,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -3943,7 +3946,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -4297,7 +4300,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -4372,7 +4375,7 @@ dependencies = [ "futures-util", "h2 0.3.22", "http 0.2.11", - "http-body 0.4.5", + "http-body 0.4.6", "hyper 0.14.27", "hyper-rustls", "ipnet", @@ -4533,9 +4536,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.26" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ "bitflags 2.4.1", "errno", @@ -4546,9 +4549,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.9" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", "ring", @@ -4595,9 +4598,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "safe_arch" @@ -4733,7 +4736,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2acea373acb8c21ecb5a23741452acd2593ed44ee3d343e72baaa143bc89d0d5" dependencies = [ "bitcoin_hashes 0.13.0", - "secp256k1-sys 0.9.0", + "secp256k1-sys 0.9.1", ] [[package]] @@ -4747,9 +4750,9 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09e67c467c38fd24bd5499dc9a18183b31575c12ee549197e3e20d57aa4fe3b7" +checksum = "4dd97a086ec737e30053fd5c46f097465d25bb81dd3608825f65298c4c98be83" dependencies = [ "cc", ] @@ -4827,7 +4830,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -4889,7 +4892,7 @@ dependencies = [ "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -5154,7 +5157,7 @@ checksum = "f12dae7cf6c1e825d13ffd4ce16bd9309db7c539929d0302b4443ed451a9f4e5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -5248,7 +5251,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -5477,7 +5480,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -5545,9 +5548,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" dependencies = [ "proc-macro2", "quote", @@ -5647,7 +5650,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall", - "rustix 0.38.26", + "rustix 0.38.28", "windows-sys 0.48.0", ] @@ -5697,7 +5700,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -5793,9 +5796,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.34.0" +version = "1.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" dependencies = [ "backtrace", "bytes", @@ -5828,7 +5831,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -5922,7 +5925,7 @@ dependencies = [ "futures-util", "h2 0.3.22", "http 0.2.11", - "http-body 0.4.5", + "http-body 0.4.6", "hyper 0.14.27", "hyper-timeout", "percent-encoding", @@ -5982,7 +5985,7 @@ dependencies = [ "futures-core", "futures-util", "http 0.2.11", - "http-body 0.4.5", + "http-body 0.4.6", "http-range-header", "httpdate", "iri-string", @@ -6031,7 +6034,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -6145,9 +6148,9 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "twox-hash" @@ -6196,9 +6199,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" @@ -6406,7 +6409,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", "wasm-bindgen-shared", ] @@ -6440,7 +6443,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6618,7 +6621,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.26", + "rustix 0.38.28", ] [[package]] @@ -6871,9 +6874,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.25" +version = "0.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e87b8dfbe3baffbe687eef2e164e32286eff31a5ee16463ce03d991643ec94" +checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2" dependencies = [ "memchr", ] @@ -6905,22 +6908,22 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "zerocopy" -version = "0.7.29" +version = "0.7.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d075cf85bbb114e933343e087b92f2146bac0d55b534cbb8188becf0039948e" +checksum = "306dca4455518f1f31635ec308b6b3e4eb1b11758cefafc782827d0aa7acb5c7" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.29" +version = "0.7.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86cd5ca076997b97ef09d3ad65efe811fa68c9e874cb636ccb211223a813b0c2" +checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] @@ -6940,7 +6943,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.41", ] [[package]] diff --git a/lib/ain-evm/src/storage/block_store.rs b/lib/ain-evm/src/storage/block_store.rs index 40cc9197a18..d442418492a 100644 --- a/lib/ain-evm/src/storage/block_store.rs +++ b/lib/ain-evm/src/storage/block_store.rs @@ -116,7 +116,6 @@ impl BlockStorage for BlockStore { fn put_block(&self, block: &BlockAny) -> Result<()> { self.extend_transactions_from_block(block)?; - let block_number = block.header.number; let hash = block.header.hash(); let blocks_cf = self.column::(); diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index defc49f40fe..aadce6cb3de 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -4,6 +4,8 @@ version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[profile.test] +debug = true [dependencies] ain-cpp-imports.workspace = true @@ -31,4 +33,5 @@ bitcoin_hashes = "0.12.0" structopt = { version = "0.3", default-features = false } tempfile = "3.8.1" anyhow.workspace = true +chrono = "0.4.31" cached.workspace = true diff --git a/lib/ain-ocean/src/data_acces/block.rs b/lib/ain-ocean/src/data_acces/block.rs index 41b4415a1a4..8b4fd1a32ad 100644 --- a/lib/ain-ocean/src/data_acces/block.rs +++ b/lib/ain-ocean/src/data_acces/block.rs @@ -1,43 +1,171 @@ -use anyhow::{anyhow, Result}; -use serde::{Deserialize, Serialize}; - use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, model::block::Block, }; +use anyhow::{anyhow, Result}; +use rocksdb::IteratorMode; +use std::convert::TryInto; + #[derive(Debug)] pub struct BlockDb { pub db: RocksDB, } impl BlockDb { - pub async fn get_by_hash(&self) -> Result { - todo!() + pub async fn get_by_hash(&self, hash: String) -> Result> { + let number = match self.db.get("block_map", hash.as_bytes()) { + Ok(Some(value)) => { + // Convert the stored bytes to a block number + let block_number_bytes: [u8; 4] = match value.try_into() { + Ok(bytes) => bytes, + Err(e) => { + return Err(anyhow!("Error converting bytes to block number: {:?}", e)) + } + }; + let block_number = i32::from_be_bytes(block_number_bytes); + Some(block_number) + } + Ok(None) => None, + Err(e) => return Err(anyhow!("Error retrieving block number: {:?}", e)), + }; + + if let Some(block_number) = number { + let block_key = block_number.to_be_bytes(); + match self.db.get("block", &block_key) { + Ok(Some(value)) => { + let block: Block = serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; + Ok(Some(block)) + } + Ok(None) => Ok(None), + Err(e) => Err(anyhow!(e)), + } + } else { + Ok(None) + } } - pub async fn get_by_height(&self) -> Result { - todo!() + + pub async fn get_by_height(&self, height: i32) -> Result> { + match self.db.get("block", &height.to_be_bytes()) { + Ok(Some(value)) => { + let block: Block = serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; + Ok(Some(block)) + } + Ok(None) => Ok(None), + Err(e) => Err(anyhow!(e)), + } } - pub async fn get_heighest(&self) -> Result { - todo!() + + pub async fn get_highest(&self) -> Result> { + // Retrieve the latest block height + let latest_height_bytes = match self.db.get("latest_block_height", b"latest_block_height") { + Ok(Some(value)) => value, + Ok(None) => return Ok(None), // No latest block height set + Err(e) => return Err(anyhow!(e)), + }; + + // Convert the latest height bytes back to an integer + let latest_height = i32::from_be_bytes( + latest_height_bytes + .as_slice() + .try_into() + .map_err(|_| anyhow!("Byte length mismatch for latest height"))?, + ); + + // Retrieve the block with the latest height + match self.db.get("block", &latest_height.to_be_bytes()) { + Ok(Some(value)) => { + let block: Block = serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; + Ok(Some(block)) + } + Ok(None) => Ok(None), // No block found for the latest height + Err(e) => Err(anyhow!(e)), + } } - pub async fn query_by_height(&self, limit: i32, lt: i32) -> Result> { - todo!() + + pub async fn query_by_height( + &self, + limit: i32, + lt: i32, + sort_order: SortOrder, + ) -> Result> { + let mut blocks: Vec = Vec::new(); + + let iterator = self.db.iterator("block", IteratorMode::End)?; + let collected_blocks: Vec<_> = iterator.collect(); + + for result in collected_blocks.into_iter().rev() { + let (key, value) = match result { + Ok((key, value)) => (key, value), + Err(err) => return Err(anyhow!("Error during iteration: {}", err)), + }; + + let block: Block = serde_json::from_slice(&value)?; + + if block.height < lt { + blocks.push(block); + + if blocks.len() == limit as usize { + break; + } + } + } + + // Sort blocks based on the specified sort order + match sort_order { + SortOrder::Ascending => blocks.sort_by(|a, b| a.height.cmp(&b.height)), + SortOrder::Descending => blocks.sort_by(|a, b| b.height.cmp(&a.height)), + } + + Ok(blocks) } - pub async fn store_block(&self, block: Block) -> Result<()> { + + pub async fn put_block(&self, block: Block) -> Result<()> { match serde_json::to_string(&block) { Ok(value) => { - let key = block.id.clone(); - self.db.put("raw_block", key.as_bytes(), value.as_bytes())?; + let block_number = block.height; + self.db + .put("block", &block_number.to_be_bytes(), value.as_bytes())?; + let block_map_key = block.hash.as_bytes(); + self.db + .put("block_map", block_map_key, &block_number.to_be_bytes())?; + self.db + .delete("latest_block_height", b"latest_block_height")?; + self.db.put( + "latest_block_height", + b"latest_block_height", + &block_number.to_be_bytes(), + )?; Ok(()) } Err(e) => Err(anyhow!(e)), } } pub async fn delete_block(&self, hash: String) -> Result<()> { - match self.db.delete("raw_block", hash.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), + let number = match self.db.get("block_map", hash.as_bytes()) { + Ok(Some(value)) => { + // Convert the stored bytes to a block number + let block_number_bytes: [u8; 4] = match value.try_into() { + Ok(bytes) => bytes, + Err(e) => { + return Err(anyhow!("Error converting bytes to block number: {:?}", e)) + } + }; + let block_number = i32::from_be_bytes(block_number_bytes); + Some(block_number) + } + Ok(None) => None, + Err(e) => return Err(anyhow!("Error retrieving block number: {:?}", e)), + }; + + if let Some(block_number) = number { + let block_key = block_number.to_be_bytes(); + match self.db.delete("block", &block_key) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } else { + Ok(()) } } } diff --git a/lib/ain-ocean/src/data_acces/masternode.rs b/lib/ain-ocean/src/data_acces/masternode.rs index c2e7466a63d..cdf54f8d6fc 100644 --- a/lib/ain-ocean/src/data_acces/masternode.rs +++ b/lib/ain-ocean/src/data_acces/masternode.rs @@ -1,19 +1,47 @@ -use anyhow::{anyhow, Result}; -use serde::{Deserialize, Serialize}; -use serde_json; - use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, model::masternode::Masternode, }; +use anyhow::{anyhow, Result}; +use rocksdb::IteratorMode; +use serde_json; pub struct MasterNodeDB { pub db: RocksDB, } impl MasterNodeDB { - pub async fn query(&self, limit: i32, lt: i32) -> Result> { - todo!() + pub async fn query( + &self, + limit: i32, + lt: u32, + sort_order: SortOrder, + ) -> Result> { + let iter_mode: IteratorMode = sort_order.into(); + let master_node: Result> = self + .db + .iterator("masternode", iter_mode)? + .into_iter() + .take(limit as usize) + .map(|result| { + result + .map_err(|e| { + anyhow!("Error during iteration: {}", e) + .context("error master_node query error") + }) + .and_then(|(_key, value)| { + let stats: Masternode = serde_json::from_slice(&value)?; + if stats.block.height < lt { + Ok(stats) + } else { + Err(anyhow!("Value is not less than lt") + .context("Contextual error message")) + } + }) + }) + .collect(); + + master_node.and_then(|result| Ok(result)) } pub async fn get(&self, id: String) -> Result> { match self.db.get("masternode", id.as_bytes()) { diff --git a/lib/ain-ocean/src/data_acces/masternode_states.rs b/lib/ain-ocean/src/data_acces/masternode_states.rs deleted file mode 100644 index 8fb54b2a779..00000000000 --- a/lib/ain-ocean/src/data_acces/masternode_states.rs +++ /dev/null @@ -1,66 +0,0 @@ -use anyhow::{anyhow, Result}; -use bitcoin::absolute::Height; -use rocksdb::{ColumnFamilyDescriptor, IteratorMode, DB}; -use serde::{Deserialize, Serialize}; - -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, - model::masternode_stats::MasternodeStats, -}; - -#[derive(Debug)] -pub struct MasterStatsDb { - pub db: RocksDB, -} -impl MasterStatsDb { - pub async fn get_latest(&self) -> Result { - // let mut latest_stats: Option = None; - // let mut highest_height = -1; - - // let iter = self.db.iterator("masternode_stats", IteratorMode::End); // Start from the end of the DB - - // for (key, value) in iter { - // let stats: MasternodeStats = serde_json::from_slice(&value)?; - // if stats.block.height > highest_height { - // highest_height = stats.block.height; - // latest_stats = Some(stats); - // } - // } - - // Ok(latest_stats); - todo!() - } - pub async fn query(&self, limit: i32, lt: i32) -> Result> { - todo!() - } - pub async fn get(&self, height: i32) -> Result> { - let bytes: &[u8] = &height.to_be_bytes(); - match self.db.get("masternode_stats", bytes) { - Ok(Some(value)) => { - let master_states: MasternodeStats = - serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; - Ok(Some(master_states)) - } - Ok(None) => Ok(None), - Err(e) => Err(anyhow!(e)), - } - } - pub async fn store(&self, stats: MasternodeStats) -> Result<()> { - match serde_json::to_string(&stats) { - Ok(value) => { - let key = stats.block.height.clone(); - let bytes: &[u8] = &key.to_be_bytes(); - self.db.put("masternode_stats", bytes, value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, height: i32) -> Result<()> { - let bytes: &[u8] = &height.to_be_bytes(); - match self.db.delete("masternode_stats", bytes) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/masternode_stats.rs b/lib/ain-ocean/src/data_acces/masternode_stats.rs new file mode 100644 index 00000000000..4cb7ed20f76 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/masternode_stats.rs @@ -0,0 +1,110 @@ +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, + model::masternode_stats::MasternodeStats, +}; +use anyhow::Context; +use anyhow::{anyhow, Result}; +use rocksdb::IteratorMode; +#[derive(Debug)] +pub struct MasterStatsDb { + pub db: RocksDB, +} +impl MasterStatsDb { + pub async fn get_latest(&self) -> Result> { + let latest_height_bytes = match self + .db + .get("masternode_block_height", b"master_block_height") + { + Ok(Some(value)) => value, + Ok(None) => return Ok(None), // No latest block height set + Err(e) => return Err(anyhow!(e)), + }; + + // Convert the latest height bytes back to an integer + let latest_height = i32::from_be_bytes( + latest_height_bytes + .as_slice() + .try_into() + .map_err(|_| anyhow!("Byte length mismatch for latest height"))?, + ); + + // Retrieve the block with the latest height + match self.db.get("block", &latest_height.to_be_bytes()) { + Ok(Some(value)) => { + let block: MasternodeStats = + serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; + Ok(Some(block)) + } + Ok(None) => Ok(None), // No block found for the latest height + Err(e) => Err(anyhow!(e)), + } + } + + pub async fn query( + &self, + limit: i32, + lt: i32, + sort_order: SortOrder, + ) -> Result> { + let iter_mode: IteratorMode = sort_order.into(); + let master_node: Result> = self + .db + .iterator("masternode_stats", iter_mode)? + .into_iter() + .take(limit as usize) + .map(|result| { + result + .map_err(|e| { + anyhow!("Error during iteration: {}", e).context("Contextual error message") + }) + .and_then(|(_key, value)| { + let stats: MasternodeStats = serde_json::from_slice(&value)?; + if stats.block.height < lt { + Ok(stats) + } else { + Err(anyhow!("Value is not less than lt") + .context("Contextual error message")) + } + }) + }) + .collect(); + Ok(master_node?) + } + + pub async fn get(&self, height: i32) -> Result> { + let bytes: &[u8] = &height.to_be_bytes(); + match self.db.get("masternode_stats", bytes) { + Ok(Some(value)) => { + let master_states: MasternodeStats = + serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; + Ok(Some(master_states)) + } + Ok(None) => Ok(None), + Err(e) => Err(anyhow!(e)), + } + } + pub async fn store(&self, stats: MasternodeStats) -> Result<()> { + match serde_json::to_string(&stats) { + Ok(value) => { + let key = stats.block.height.clone(); + let height: &[u8] = &key.to_be_bytes(); + self.db.put("masternode_stats", height, value.as_bytes())?; + self.db + .put("masternode_map", stats.block.hash.as_bytes(), height)?; + self.db + .delete("masternode_block_height", b"master_block_height")?; + self.db + .put("masternode_block_height", b"master_block_height", height)?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, height: i32) -> Result<()> { + let bytes: &[u8] = &height.to_be_bytes(); + match self.db.delete("masternode_stats", bytes) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/mod.rs b/lib/ain-ocean/src/data_acces/mod.rs index 4072333a14e..426541e79e2 100644 --- a/lib/ain-ocean/src/data_acces/mod.rs +++ b/lib/ain-ocean/src/data_acces/mod.rs @@ -1,9 +1,11 @@ pub mod block; pub mod masternode; -pub mod masternode_states; +pub mod masternode_stats; pub mod oracle; +pub mod oracle_price_active; pub mod oracle_price_aggregated; pub mod oracle_price_aggregated_interval; +pub mod oracle_price_feed; pub mod oracle_token_currency; pub mod order_history; pub mod pool_swap; diff --git a/lib/ain-ocean/src/data_acces/oracle.rs b/lib/ain-ocean/src/data_acces/oracle.rs index 2d9badd0927..e106b94c0ce 100644 --- a/lib/ain-ocean/src/data_acces/oracle.rs +++ b/lib/ain-ocean/src/data_acces/oracle.rs @@ -1,9 +1,10 @@ use anyhow::{anyhow, Error, Result}; +use rocksdb::IteratorMode; use serde::{Deserialize, Serialize}; use serde_json; use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, model::oracle::Oracle, }; @@ -12,9 +13,37 @@ pub struct OracleDb { } impl OracleDb { - pub async fn query(&self, limit: i32, lt: String) -> Result> { - todo!() + pub async fn query( + &self, + limit: i32, + lt: String, + sort_order: SortOrder, + ) -> Result> { + let iterator = self.db.iterator("oracle", IteratorMode::End)?; + let mut oracles: Vec = Vec::new(); + let collected_items: Vec<_> = iterator.collect(); + + for result in collected_items.into_iter().rev() { + let value = match result { + Ok((_, value)) => value, + Err(err) => return Err(anyhow!("Error during iteration: {}", err)), + }; + + let oracle: Oracle = serde_json::from_slice(&value)?; + oracles.push(oracle); + if oracles.len() as i32 >= limit { + break; + } + } + + match sort_order { + SortOrder::Ascending => oracles.sort_by(|a, b| a.id.cmp(&b.id)), + SortOrder::Descending => oracles.sort_by(|a, b| b.id.cmp(&a.id)), + } + + Ok(oracles) } + pub async fn store(&self, oracle: Oracle) -> Result<()> { match serde_json::to_string(&oracle) { Ok(value) => { diff --git a/lib/ain-ocean/src/data_acces/oracle_price_active.rs b/lib/ain-ocean/src/data_acces/oracle_price_active.rs new file mode 100644 index 00000000000..aa3a08a1141 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/oracle_price_active.rs @@ -0,0 +1,67 @@ +use crate::model::oracle_price_feed::OraclePriceFeed; +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, + model::oracle_price_active::OraclePriceActive, +}; +use anyhow::{anyhow, Result}; +use rocksdb::IteratorMode; + +pub struct OraclePriceActiveDb { + pub db: RocksDB, +} + +impl OraclePriceActiveDb { + pub async fn query( + &self, + oracle_id: String, + limit: i32, + lt: String, + sort_order: SortOrder, + ) -> Result> { + let iterator = self.db.iterator("oracle_price_active", IteratorMode::End)?; + let mut oracle_price_feed: Vec = Vec::new(); + let collected_blocks: Vec<_> = iterator.collect(); + + for result in collected_blocks.into_iter().rev() { + let (key, value) = match result { + Ok((key, value)) => (key, value), + Err(err) => return Err(anyhow!("Error during iteration: {}", err)), + }; + + let oracle: OraclePriceActive = serde_json::from_slice(&value)?; + if oracle.key == oracle_id { + oracle_price_feed.push(oracle); + if oracle_price_feed.len() as i32 >= limit { + break; + } + } + } + + // Sort blocks based on the specified sort order + match sort_order { + SortOrder::Ascending => { + oracle_price_feed.sort_by(|a: &OraclePriceActive, b| a.id.cmp(&b.id)) + } + SortOrder::Descending => oracle_price_feed.sort_by(|a, b| b.id.cmp(&a.id)), + } + + Ok(oracle_price_feed) + } + pub async fn put(&self, oracle_price_feed: OraclePriceActive) -> Result<()> { + match serde_json::to_string(&oracle_price_feed) { + Ok(value) => { + let key = oracle_price_feed.id.clone(); + self.db + .put("oracle_price_active", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self.db.delete("oracle_price_active", id.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/oracle_price_aggregated.rs b/lib/ain-ocean/src/data_acces/oracle_price_aggregated.rs index e1e89e96733..182cdea9c56 100644 --- a/lib/ain-ocean/src/data_acces/oracle_price_aggregated.rs +++ b/lib/ain-ocean/src/data_acces/oracle_price_aggregated.rs @@ -1,10 +1,9 @@ -use anyhow::{anyhow, Result}; -use serde::{Deserialize, Serialize}; - use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, model::oracle_price_aggregated::OraclePriceAggregated, }; +use anyhow::{anyhow, Result}; +use rocksdb::IteratorMode; pub struct OraclePriceAggrigatedDb { pub db: RocksDB, @@ -13,16 +12,46 @@ pub struct OraclePriceAggrigatedDb { impl OraclePriceAggrigatedDb { pub async fn query( &self, - key: String, + oracle_key: String, limit: i32, lt: String, + sort_order: SortOrder, ) -> Result> { - todo!() + let iterator = self + .db + .iterator("oracle_price_aggregated", IteratorMode::End)?; + let mut oracle_pa: Vec = Vec::new(); + let collected_blocks: Vec<_> = iterator.collect(); + + for result in collected_blocks.into_iter().rev() { + let (key, value) = match result { + Ok((key, value)) => (key, value), + Err(err) => return Err(anyhow!("Error during iteration: {}", err)), + }; + + let oracle: OraclePriceAggregated = serde_json::from_slice(&value)?; + if oracle.key == oracle_key { + oracle_pa.push(oracle); + if oracle_pa.len() as i32 >= limit { + break; + } + } + } + + // Sort blocks based on the specified sort order + match sort_order { + SortOrder::Ascending => { + oracle_pa.sort_by(|a: &OraclePriceAggregated, b| a.id.cmp(&b.id)) + } + SortOrder::Descending => oracle_pa.sort_by(|a, b| b.id.cmp(&a.id)), + } + + Ok(oracle_pa) } pub async fn put(&self, oracle: OraclePriceAggregated) -> Result<()> { match serde_json::to_string(&oracle) { Ok(value) => { - let key = oracle.id.clone(); + let key = oracle.key.clone(); self.db .put("oracle_price_aggregated", key.as_bytes(), value.as_bytes())?; Ok(()) @@ -30,14 +59,14 @@ impl OraclePriceAggrigatedDb { Err(e) => Err(anyhow!(e)), } } - pub async fn get(&self, id: String) -> Option { - match self.db.get("oracle_price_aggregated", id.as_bytes()) { + pub async fn get(&self, key: String) -> Option { + match self.db.get("oracle_price_aggregated", key.as_bytes()) { Ok(Some(value)) => serde_json::from_slice(&value).ok(), _ => None, } } - pub async fn delete(&self, id: String) -> Result<()> { - match self.db.delete("oracle_price_aggregated", id.as_bytes()) { + pub async fn delete(&self, key: String) -> Result<()> { + match self.db.delete("oracle_price_aggregated", key.as_bytes()) { Ok(_) => Ok(()), Err(e) => Err(anyhow!(e)), } diff --git a/lib/ain-ocean/src/data_acces/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/data_acces/oracle_price_aggregated_interval.rs index cb36cf9c3d0..4ff3977e85d 100644 --- a/lib/ain-ocean/src/data_acces/oracle_price_aggregated_interval.rs +++ b/lib/ain-ocean/src/data_acces/oracle_price_aggregated_interval.rs @@ -1,10 +1,9 @@ -use anyhow::{anyhow, Result}; -use serde::{Deserialize, Serialize}; - use crate::{ database::db_manager::{ColumnFamilyOperations, RocksDB}, model::oracle_price_aggregated_interval::OraclePriceAggregatedInterval, }; +use anyhow::{anyhow, Result}; +use rocksdb::{ColumnFamilyDescriptor, IteratorMode, DB}; pub struct OraclePriceAggregatedIntervalDb { pub db: RocksDB, @@ -17,7 +16,31 @@ impl OraclePriceAggregatedIntervalDb { limit: i32, lt: String, ) -> Result> { - todo!() + let iterator = self + .db + .iterator("oracle_price_aggregated_interval", IteratorMode::End)?; + let mut oracle_prices: Vec = Vec::new(); + let collected_items: Vec<_> = iterator.collect(); + + for result in collected_items.into_iter().rev() { + let (key, value) = match result { + Ok((key, value)) => (key, value), + Err(err) => return Err(anyhow!("Error during iteration: {}", err)), + }; + + let oracle_price: OraclePriceAggregatedInterval = serde_json::from_slice(&value)?; + + // Check if the id is less than 'lt' + if String::from_utf8(key.to_vec())? < lt { + oracle_prices.push(oracle_price); + + if oracle_prices.len() == limit as usize { + break; + } + } + } + + Ok(oracle_prices) } pub async fn put(&self, oracle: OraclePriceAggregatedInterval) -> Result<()> { match serde_json::to_string(&oracle) { diff --git a/lib/ain-ocean/src/data_acces/oracle_price_feed.rs b/lib/ain-ocean/src/data_acces/oracle_price_feed.rs new file mode 100644 index 00000000000..05cc2e90f01 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/oracle_price_feed.rs @@ -0,0 +1,66 @@ +use crate::{ + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, + model::oracle_price_feed::OraclePriceFeed, +}; +use anyhow::{anyhow, Result}; +use rocksdb::IteratorMode; + +pub struct OraclePriceFeedDb { + pub db: RocksDB, +} + +impl OraclePriceFeedDb { + pub async fn query( + &self, + oracle_id: String, + limit: i32, + lt: String, + sort_order: SortOrder, + ) -> Result> { + let iterator = self.db.iterator("oracle_price_feed", IteratorMode::End)?; + let mut oracle_price_feed: Vec = Vec::new(); + let collected_blocks: Vec<_> = iterator.collect(); + + for result in collected_blocks.into_iter().rev() { + let (key, value) = match result { + Ok((key, value)) => (key, value), + Err(err) => return Err(anyhow!("Error during iteration: {}", err)), + }; + + let oracle: OraclePriceFeed = serde_json::from_slice(&value)?; + if oracle.key == oracle_id { + oracle_price_feed.push(oracle); + if oracle_price_feed.len() as i32 >= limit { + break; + } + } + } + + // Sort blocks based on the specified sort order + match sort_order { + SortOrder::Ascending => { + oracle_price_feed.sort_by(|a: &OraclePriceFeed, b| a.id.cmp(&b.id)) + } + SortOrder::Descending => oracle_price_feed.sort_by(|a, b| b.id.cmp(&a.id)), + } + + Ok(oracle_price_feed) + } + pub async fn put(&self, oracle_price_feed: OraclePriceFeed) -> Result<()> { + match serde_json::to_string(&oracle_price_feed) { + Ok(value) => { + let key = oracle_price_feed.id.clone(); + self.db + .put("oracle_price_feed", key.as_bytes(), value.as_bytes())?; + Ok(()) + } + Err(e) => Err(anyhow!(e)), + } + } + pub async fn delete(&self, id: String) -> Result<()> { + match self.db.delete("oracle_price_feed", id.as_bytes()) { + Ok(_) => Ok(()), + Err(e) => Err(anyhow!(e)), + } + } +} diff --git a/lib/ain-ocean/src/data_acces/oracle_token_currency.rs b/lib/ain-ocean/src/data_acces/oracle_token_currency.rs index 907e1633c94..e66e7421599 100644 --- a/lib/ain-ocean/src/data_acces/oracle_token_currency.rs +++ b/lib/ain-ocean/src/data_acces/oracle_token_currency.rs @@ -1,8 +1,8 @@ use anyhow::{anyhow, Result}; -use serde::{Deserialize, Serialize}; +use rocksdb::IteratorMode; use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, model::oracle_token_currency::OracleTokenCurrency, }; @@ -11,8 +11,41 @@ pub struct OracleTokenCurrencyDb { } impl OracleTokenCurrencyDb { - pub async fn query(&self, limit: i32, lt: String) -> Result> { - todo!() + pub async fn query( + &self, + oracle_id: String, + limit: i32, + lt: String, + sort_order: SortOrder, + ) -> Result> { + let iterator = self + .db + .iterator("oracle_token_currency", IteratorMode::End)?; + let mut oracle_tc: Vec = Vec::new(); + let collected_blocks: Vec<_> = iterator.collect(); + + for result in collected_blocks.into_iter().rev() { + let (key, value) = match result { + Ok((key, value)) => (key, value), + Err(err) => return Err(anyhow!("Error during iteration: {}", err)), + }; + + let oracle: OracleTokenCurrency = serde_json::from_slice(&value)?; + if oracle.key == oracle_id { + oracle_tc.push(oracle); + if oracle_tc.len() as i32 >= limit { + break; + } + } + } + + // Sort blocks based on the specified sort order + match sort_order { + SortOrder::Ascending => oracle_tc.sort_by(|a: &OracleTokenCurrency, b| a.id.cmp(&b.id)), + SortOrder::Descending => oracle_tc.sort_by(|a, b| b.id.cmp(&a.id)), + } + + Ok(oracle_tc) } pub async fn put(&self, oracle_token: OracleTokenCurrency) -> Result<()> { match serde_json::to_string(&oracle_token) { diff --git a/lib/ain-ocean/src/data_acces/order_history.rs b/lib/ain-ocean/src/data_acces/order_history.rs index 9b274c279c9..6f5fff45ba2 100644 --- a/lib/ain-ocean/src/data_acces/order_history.rs +++ b/lib/ain-ocean/src/data_acces/order_history.rs @@ -1,8 +1,8 @@ use anyhow::{anyhow, Result}; -use serde::{Deserialize, Serialize}; +use rocksdb::IteratorMode; use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, model::oracle_history::OracleHistory, }; @@ -11,14 +11,45 @@ pub struct OracleHistoryDB { } impl OracleHistoryDB { - pub async fn query(&self, oracleId: String, limit: i32, lt: String) -> Result { - todo!() + pub async fn query( + &self, + oracle_id: String, + limit: i32, + lt: String, + sort_order: SortOrder, + ) -> Result> { + let iterator = self.db.iterator("oracle_history", IteratorMode::End)?; + let mut oracle_history: Vec = Vec::new(); + let collected_blocks: Vec<_> = iterator.collect(); + + for result in collected_blocks.into_iter().rev() { + let (key, value) = match result { + Ok((key, value)) => (key, value), + Err(err) => return Err(anyhow!("Error during iteration: {}", err)), + }; + + let oracle: OracleHistory = serde_json::from_slice(&value)?; + if oracle.id == oracle_id { + oracle_history.push(oracle); + if oracle_history.len() as i32 >= limit { + break; + } + } + } + + // Sort blocks based on the specified sort order + match sort_order { + SortOrder::Ascending => oracle_history.sort_by(|a, b| a.oracle_id.cmp(&b.oracle_id)), + SortOrder::Descending => oracle_history.sort_by(|a, b| b.oracle_id.cmp(&a.oracle_id)), + } + + Ok(oracle_history) } pub async fn store(&self, oracle_history: OracleHistory) -> Result<()> { match serde_json::to_string(&oracle_history) { Ok(value) => { - let key = oracle_history.id.clone(); + let key = oracle_history.oracle_id.clone(); self.db .put("oracle_history", key.as_bytes(), value.as_bytes())?; Ok(()) @@ -26,8 +57,8 @@ impl OracleHistoryDB { Err(e) => Err(anyhow!(e)), } } - pub async fn delete(&self, id: String) -> Result<()> { - match self.db.delete("oracle_history", id.as_bytes()) { + pub async fn delete(&self, oracle_id: String) -> Result<()> { + match self.db.delete("oracle_history", oracle_id.as_bytes()) { Ok(_) => Ok(()), Err(e) => Err(anyhow!(e)), } diff --git a/lib/ain-ocean/src/data_acces/pool_swap.rs b/lib/ain-ocean/src/data_acces/pool_swap.rs index ad5a6b2d89c..25e857d4bfb 100644 --- a/lib/ain-ocean/src/data_acces/pool_swap.rs +++ b/lib/ain-ocean/src/data_acces/pool_swap.rs @@ -1,8 +1,8 @@ use anyhow::{anyhow, Result}; -use serde::{Deserialize, Serialize}; +use rocksdb::IteratorMode; use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, model::poolswap::PoolSwap, }; @@ -11,8 +11,39 @@ pub struct PoolSwapDb { } impl PoolSwapDb { - pub async fn query(&self, key: String, limit: i32, lt: String) -> Result> { - todo!() + pub async fn query( + &self, + id: String, + limit: i32, + lt: String, + sort_order: SortOrder, + ) -> Result> { + let iterator = self.db.iterator("pool_swap", IteratorMode::End)?; + let mut pool_vin: Vec = Vec::new(); + let collected_blocks: Vec<_> = iterator.collect(); + + for result in collected_blocks.into_iter().rev() { + let (key, value) = match result { + Ok((key, value)) => (key, value), + Err(err) => return Err(anyhow!("Error during iteration: {}", err)), + }; + + let vin: PoolSwap = serde_json::from_slice(&value)?; + if vin.id == id { + pool_vin.push(vin); + if pool_vin.len() as i32 >= limit { + break; + } + } + } + + // Sort blocks based on the specified sort order + match sort_order { + SortOrder::Ascending => pool_vin.sort_by(|a, b| a.txid.cmp(&b.txid)), + SortOrder::Descending => pool_vin.sort_by(|a, b| b.txid.cmp(&a.txid)), + } + + Ok(pool_vin) } pub async fn put(&self, swap: PoolSwap) -> Result<()> { match serde_json::to_string(&swap) { diff --git a/lib/ain-ocean/src/data_acces/pool_swap_aggregated.rs b/lib/ain-ocean/src/data_acces/pool_swap_aggregated.rs index 9259760086e..1af6936a46f 100644 --- a/lib/ain-ocean/src/data_acces/pool_swap_aggregated.rs +++ b/lib/ain-ocean/src/data_acces/pool_swap_aggregated.rs @@ -1,8 +1,8 @@ use anyhow::{anyhow, Result}; -use serde::{Deserialize, Serialize}; +use rocksdb::IteratorMode; use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, model::poolswap_aggregated::PoolSwapAggregated, }; @@ -13,11 +13,39 @@ pub struct PoolSwapAggregatedDb { impl PoolSwapAggregatedDb { pub async fn query( &self, - key: String, + id: String, limit: i32, lt: String, + sort_order: SortOrder, ) -> Result<(Vec)> { - todo!() + let iterator = self + .db + .iterator("pool_swap_aggregated", IteratorMode::End)?; + let mut pool_swap: Vec = Vec::new(); + let collected_blocks: Vec<_> = iterator.collect(); + + for result in collected_blocks.into_iter().rev() { + let (key, value) = match result { + Ok((key, value)) => (key, value), + Err(err) => return Err(anyhow!("Error during iteration: {}", err)), + }; + + let ps: PoolSwapAggregated = serde_json::from_slice(&value)?; + if ps.id == id { + pool_swap.push(ps); + if pool_swap.len() as i32 >= limit { + break; + } + } + } + + // Sort blocks based on the specified sort order + match sort_order { + SortOrder::Ascending => pool_swap.sort_by(|a, b| a.id.cmp(&b.id)), + SortOrder::Descending => pool_swap.sort_by(|a, b| b.id.cmp(&a.id)), + } + + Ok(pool_swap) } pub async fn put(&self, aggregated: PoolSwapAggregated) -> Result<()> { match serde_json::to_string(&aggregated) { diff --git a/lib/ain-ocean/src/data_acces/price_ticker.rs b/lib/ain-ocean/src/data_acces/price_ticker.rs index ac7e1a0140e..e6491f888b5 100644 --- a/lib/ain-ocean/src/data_acces/price_ticker.rs +++ b/lib/ain-ocean/src/data_acces/price_ticker.rs @@ -1,8 +1,8 @@ use anyhow::{anyhow, Result}; -use serde::{Deserialize, Serialize}; +use rocksdb::IteratorMode; use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, model::price_ticker::PriceTicker, }; @@ -11,8 +11,35 @@ pub struct price_ticker { } impl price_ticker { - pub async fn query(&self, limit: i32, lt: String) -> Result> { - todo!() + pub async fn query( + &self, + limit: i32, + lt: String, + sort_order: SortOrder, + ) -> Result> { + let iterator = self.db.iterator("price_ticker", IteratorMode::End)?; + let mut pt: Vec = Vec::new(); + let collected_items: Vec<_> = iterator.collect(); + + for result in collected_items.into_iter().rev() { + let value = match result { + Ok((_, value)) => value, + Err(err) => return Err(anyhow!("Error during iteration: {}", err)), + }; + + let price_ticker: PriceTicker = serde_json::from_slice(&value)?; + pt.push(price_ticker); + if pt.len() as i32 >= limit { + break; + } + } + + match sort_order { + SortOrder::Ascending => pt.sort_by(|a, b| a.id.cmp(&b.id)), + SortOrder::Descending => pt.sort_by(|a, b| b.id.cmp(&a.id)), + } + + Ok(pt) } pub async fn get(&self, id: String) -> Result { match self.db.get("price_ticker", id.as_bytes()) { diff --git a/lib/ain-ocean/src/data_acces/raw_block.rs b/lib/ain-ocean/src/data_acces/raw_block.rs index b2beb705bf4..024222dcba4 100644 --- a/lib/ain-ocean/src/data_acces/raw_block.rs +++ b/lib/ain-ocean/src/data_acces/raw_block.rs @@ -1,5 +1,4 @@ use anyhow::{anyhow, Result}; -use serde::{Deserialize, Serialize}; use crate::{ database::db_manager::{ColumnFamilyOperations, RocksDB}, diff --git a/lib/ain-ocean/src/data_acces/script_activity.rs b/lib/ain-ocean/src/data_acces/script_activity.rs index 5a24394fa0a..feeaa12abc9 100644 --- a/lib/ain-ocean/src/data_acces/script_activity.rs +++ b/lib/ain-ocean/src/data_acces/script_activity.rs @@ -1,24 +1,56 @@ -use anyhow::{anyhow, Error, Result}; -use serde::{Deserialize, Serialize}; -use serde_json; - use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, model::script_activity::ScriptActivity, }; +use anyhow::{anyhow, Result}; +use rocksdb::{Direction, IteratorMode}; +use serde_json; pub struct ScriptUnspentDB { pub db: RocksDB, } impl ScriptUnspentDB { - pub async fn query(&self, limit: i32, lt: String) -> Result> { - todo!() + pub async fn query( + &self, + hid: String, + limit: i32, + lt: Option, + ) -> Result> { + let prefix = format!("script_activity_hid_sort:{}:", lt.unwrap_or_default()); + let iterator_result = self.db.iterator( + "script_activity", + IteratorMode::From(prefix.as_bytes(), Direction::Forward), + )?; + let mut results = Vec::new(); + for item in iterator_result { + match item { + Ok((key, value)) => { + let key_str = String::from_utf8_lossy(&key); + if !key_str.starts_with(&prefix) { + break; + } + + let script_unspent: ScriptActivity = serde_json::from_slice(&value)?; + + results.push(script_unspent); + + if results.len() >= limit as usize { + break; + } + } + Err(err) => { + eprintln!("Error iterating over the database: {:?}", err); + return Err(err.into()); + } + } + } + Ok(results) } pub async fn store(&self, unspent: ScriptActivity) -> Result<()> { match serde_json::to_string(&unspent) { Ok(value) => { - let key = unspent.id.clone(); + let key = unspent.hid.clone(); self.db .put("script_activity", key.as_bytes(), value.as_bytes())?; Ok(()) @@ -26,8 +58,8 @@ impl ScriptUnspentDB { Err(e) => Err(anyhow!(e)), } } - pub async fn delete(&self, id: String) -> Result<()> { - match self.db.delete("script_activity", id.as_bytes()) { + pub async fn delete(&self, hid: String) -> Result<()> { + match self.db.delete("script_activity", hid.as_bytes()) { Ok(_) => Ok(()), Err(e) => Err(anyhow!(e)), } diff --git a/lib/ain-ocean/src/data_acces/script_aggregation.rs b/lib/ain-ocean/src/data_acces/script_aggregation.rs index ec386717bad..2f2788aaf5d 100644 --- a/lib/ain-ocean/src/data_acces/script_aggregation.rs +++ b/lib/ain-ocean/src/data_acces/script_aggregation.rs @@ -1,9 +1,9 @@ -use anyhow::{anyhow, Error, Result}; -use serde::{Deserialize, Serialize}; +use anyhow::{anyhow, Result}; +use rocksdb::{Direction, IteratorMode}; use serde_json; use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, model::script_aggregation::ScriptAggregation, }; @@ -12,22 +12,69 @@ pub struct ScriptAggretionDB { } impl ScriptAggretionDB { - pub async fn query(&self, limit: i32, lt: String) -> Result> { - todo!() + pub async fn query( + &self, + hid: String, + limit: i32, + lt: String, + sort_order: SortOrder, + ) -> Result> { + let iterator = self.db.iterator( + "script_aggregation", + IteratorMode::From(lt.as_bytes(), Direction::Reverse), + )?; + + let mut script_aggre: Vec = Vec::new(); + + for item in iterator { + match item { + Ok((key, value)) => { + let key_str = String::from_utf8_lossy(&key); + + if !key_str.starts_with(&hid) { + break; + } + + let vout: ScriptAggregation = serde_json::from_slice(&value)?; + script_aggre.push(vout); + + if script_aggre.len() >= limit as usize { + break; + } + } + Err(err) => { + eprintln!("Error iterating over the database: {:?}", err); + return Err(err.into()); + } + } + } + + // Sorting based on the SortOrder + match sort_order { + SortOrder::Ascending => script_aggre.sort_by(|a, b| a.id.cmp(&b.id)), + SortOrder::Descending => script_aggre.sort_by(|a, b| b.id.cmp(&a.id)), + } + + Ok(script_aggre) } pub async fn store(&self, aggregation: ScriptAggregation) -> Result<()> { match serde_json::to_string(&aggregation) { Ok(value) => { - let key = aggregation.id.clone(); + let key = aggregation.hid.clone(); self.db .put("script_aggregation", key.as_bytes(), value.as_bytes())?; + + let h = aggregation.block.height.clone(); + let height: &[u8] = &h.to_be_bytes(); + self.db + .put("script_aggregation_mapper", height, key.as_bytes())?; Ok(()) } Err(e) => Err(anyhow!(e)), } } - pub async fn get(&self, id: String) -> Result> { - match self.db.get("script_aggregation", id.as_bytes()) { + pub async fn get(&self, hid: String) -> Result> { + match self.db.get("script_aggregation", hid.as_bytes()) { Ok(Some(value)) => { let oracle: ScriptAggregation = serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; @@ -37,8 +84,8 @@ impl ScriptAggretionDB { Err(e) => Err(anyhow!(e)), } } - pub async fn delete(&self, id: String) -> Result<()> { - match self.db.delete("script_aggregation", id.as_bytes()) { + pub async fn delete(&self, hid: String) -> Result<()> { + match self.db.delete("script_aggregation", hid.as_bytes()) { Ok(_) => Ok(()), Err(e) => Err(anyhow!(e)), } diff --git a/lib/ain-ocean/src/data_acces/script_unspent.rs b/lib/ain-ocean/src/data_acces/script_unspent.rs index a5c1a462f08..5db7c88e066 100644 --- a/lib/ain-ocean/src/data_acces/script_unspent.rs +++ b/lib/ain-ocean/src/data_acces/script_unspent.rs @@ -1,5 +1,5 @@ use anyhow::{anyhow, Error, Result}; -use serde::{Deserialize, Serialize}; +use rocksdb::{Direction, IteratorMode}; use serde_json; use crate::{ @@ -12,13 +12,46 @@ pub struct ScriptUnspentDB { } impl ScriptUnspentDB { - pub async fn query(&self, limit: i32, lt: String) -> Result> { - todo!() + pub async fn query( + &self, + hid: String, + limit: i32, + gt: Option, + ) -> Result> { + let prefix = format!("script_unspent_hid_sort:{}:", gt.unwrap_or_default()); + let iterator_result = self.db.iterator( + "script_unspent", + IteratorMode::From(prefix.as_bytes(), Direction::Forward), + )?; + let mut results = Vec::new(); + for item in iterator_result { + match item { + Ok((key, value)) => { + let key_str = String::from_utf8_lossy(&key); + if !key_str.starts_with(&prefix) { + break; + } + + let script_unspent: ScriptUnspent = serde_json::from_slice(&value)?; + + results.push(script_unspent); + + if results.len() >= limit as usize { + break; + } + } + Err(err) => { + eprintln!("Error iterating over the database: {:?}", err); + return Err(err.into()); + } + } + } + Ok(results) } pub async fn store(&self, unspent: ScriptUnspent) -> Result<()> { match serde_json::to_string(&unspent) { Ok(value) => { - let key = unspent.id.clone(); + let key = unspent.hid.clone(); self.db .put("script_unspent", key.as_bytes(), value.as_bytes())?; Ok(()) @@ -26,8 +59,8 @@ impl ScriptUnspentDB { Err(e) => Err(anyhow!(e)), } } - pub async fn delete(&self, id: String) -> Result<()> { - match self.db.delete("script_unspent", id.as_bytes()) { + pub async fn delete(&self, hid: String) -> Result<()> { + match self.db.delete("script_unspent", hid.as_bytes()) { Ok(_) => Ok(()), Err(e) => Err(anyhow!(e)), } diff --git a/lib/ain-ocean/src/data_acces/test/block_test.rs b/lib/ain-ocean/src/data_acces/test/block_test.rs new file mode 100644 index 00000000000..4fa1d2d5cb2 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/test/block_test.rs @@ -0,0 +1,217 @@ +#[cfg(test)] +mod tests { + use super::*; + use crate::data_acces::block::BlockDb; + use crate::database::db_manager::SortOrder; + use crate::database::db_manager::{ColumnFamilyOperations, RocksDB}; + use crate::model::block::Block; + use tempdir::TempDir; + + pub fn create_dummy_block(height: i32) -> Block { + Block { + id: "1".to_string(), + hash: "block_hash_1".to_string(), + previous_hash: "previous_block_hash".to_string(), + height: height, + version: 1, + time: 1634054400, // Replace with an actual timestamp + median_time: 1634054400, // Replace with an actual timestamp + transaction_count: 10, + difficulty: 12345, + masternode: "masternode_address".to_string(), + minter: "minter_address".to_string(), + minter_block_count: 5, + reward: "10.0".to_string(), + stake_modifier: "stake_modifier_value".to_string(), + merkleroot: "merkleroot_value".to_string(), + size: 2000, + size_stripped: 1800, + weight: 1900, + } + } + + #[tokio::test] + async fn test_put_get_by_hash_and_height() { + // Create a temporary RocksDB instance for testing + let temp_dir = TempDir::new("test_rocksdb").expect("Failed to create temp directory"); + let rocksdb = RocksDB::new(temp_dir.path().to_str().unwrap()) + .expect("Failed to create RocksDB instance"); + let block_db = BlockDb { db: rocksdb }; + + // Create a dummy block for testing + let dummy_block = create_dummy_block(1); + + // Test the put_block method + block_db.put_block(dummy_block.clone()).await.unwrap(); + + // Test the get_by_hash method + let result_by_hash = block_db + .get_by_hash(dummy_block.hash.clone()) + .await + .unwrap(); + assert_eq!(result_by_hash.unwrap(), dummy_block.clone()); + + // Test the get_by_height method + let result_by_height = block_db.get_by_height(dummy_block.height).await.unwrap(); + assert_eq!(result_by_height.unwrap(), dummy_block); + } + + #[tokio::test] + async fn test_get_nonexistent_block_by_hash() { + let temp_dir = TempDir::new("test_rocksdb").expect("Failed to create temp directory"); + let rocksdb = RocksDB::new(temp_dir.path().to_str().unwrap()) + .expect("Failed to create RocksDB instance"); + let block_db = BlockDb { db: rocksdb }; + + // Attempt to get a block using a hash that doesn't exist + let result = block_db + .get_by_hash("nonexistent_hash".to_string()) + .await + .unwrap(); + assert_eq!(result, None); + } + + #[tokio::test] + async fn test_get_nonexistent_block_by_height() { + let temp_dir = TempDir::new("test_rocksdb").expect("Failed to create temp directory"); + let rocksdb = RocksDB::new(temp_dir.path().to_str().unwrap()) + .expect("Failed to create RocksDB instance"); + let block_db = BlockDb { db: rocksdb }; + + // Attempt to get a block using a height that doesn't exist + let result = block_db.get_by_height(999).await.unwrap(); + assert_eq!(result, None); + } + + #[tokio::test] + async fn test_delete_block() { + let temp_dir = TempDir::new("test_rocksdb").expect("Failed to create temp directory"); + let rocksdb = RocksDB::new(temp_dir.path().to_str().unwrap()) + .expect("Failed to create RocksDB instance"); + let block_db = BlockDb { db: rocksdb }; + + // Create a dummy block for testing + let dummy_block = create_dummy_block(1); + + // Put the block + block_db.put_block(dummy_block.clone()).await.unwrap(); + + // Delete the block + block_db + .delete_block(dummy_block.hash.clone()) + .await + .unwrap(); + + // Attempt to get the block after deletion + let result_by_hash = block_db + .get_by_hash(dummy_block.hash.clone()) + .await + .unwrap(); + + assert!(result_by_hash.is_none()); + } + + #[tokio::test] + async fn test_query_by_height_descending() { + // Create a temporary RocksDB instance for testing + let temp_dir = TempDir::new("test_rocksdb").expect("Failed to create temp directory"); + let rocksdb = RocksDB::new(temp_dir.path().to_str().unwrap()) + .expect("Failed to create RocksDB instance"); + let block_db = BlockDb { db: rocksdb }; + + // Create dummy blocks with heights 1 to 5 and insert them into the database + for height in 1..=10 { + let dummy_block = create_dummy_block(height); + block_db.put_block(dummy_block.clone()).await.unwrap(); + } + + // Test the query_by_height method + let result_blocks = block_db + .query_by_height(3, 4, SortOrder::Descending) + .await + .unwrap(); + // Verify that the result contains the expected blocks + assert_eq!(result_blocks.len(), 3); + assert_eq!(result_blocks[0].height, 3); + assert_eq!(result_blocks[1].height, 2); + } + + #[tokio::test] + async fn test_query_by_height_ascending() { + // Create a temporary RocksDB instance for testing + let temp_dir = TempDir::new("test_rocksdb").expect("Failed to create temp directory"); + let rocksdb = RocksDB::new(temp_dir.path().to_str().unwrap()) + .expect("Failed to create RocksDB instance"); + let block_db = BlockDb { db: rocksdb }; + + // Create dummy blocks with heights 1 to 5 and insert them into the database + for height in 1..=10 { + let dummy_block = create_dummy_block(height); + block_db.put_block(dummy_block.clone()).await.unwrap(); + } + + // Test the query_by_height method + let result_blocks = block_db + .query_by_height(5, 6, SortOrder::Ascending) + .await + .unwrap(); + // Verify that the result contains the expected blocks + assert_eq!(result_blocks.len(), 5); + assert_eq!(result_blocks[0].height, 1); + assert_eq!(result_blocks[1].height, 2); + } + + #[tokio::test] + async fn test_put_block_updates_latest_height() { + // Setup test environment + let temp_dir = TempDir::new("test_rocksdb").expect("Failed to create temp directory"); + let rocksdb = RocksDB::new(temp_dir.path().to_str().unwrap()) + .expect("Failed to create RocksDB instance"); + let block_db = BlockDb { db: rocksdb }; + + // Create and insert sample blocks + for height in 1..=10 { + let dummy_block = create_dummy_block(height); + block_db.put_block(dummy_block).await.unwrap(); + } + + // Retrieve latest block height + let latest_height_bytes = block_db + .db + .get("latest_block_height", b"latest_block_height") + .expect("Failed to retrieve latest block height") + .expect("Latest block height not found"); + let latest_height = i32::from_be_bytes( + latest_height_bytes + .as_slice() + .try_into() + .expect("Byte length mismatch"), + ); + + // Assert correctness + assert_eq!(latest_height, 10); // Assert that latest height is 10 + } + + #[tokio::test] + async fn test_get_highest_retrieves_correct_block() -> Result<(), Box> { + // Setup test environment + let temp_dir = TempDir::new("test_rocksdb").expect("Failed to create temp directory"); + let rocksdb = RocksDB::new(temp_dir.path().to_str().unwrap()) + .expect("Failed to create RocksDB instance"); + let block_db = BlockDb { db: rocksdb }; + + // Insert sample blocks + for height in 1..=5 { + let dummy_block = create_dummy_block(height); + block_db.put_block(dummy_block).await.unwrap(); + } + + // Call get_highest + let highest_block = block_db.get_highest().await.unwrap().unwrap(); + + // Assert that the highest block is the one with height 5 + assert_eq!(highest_block.height, 5); + + Ok(()) + } +} diff --git a/lib/ain-ocean/src/data_acces/test/masternode_test.rs b/lib/ain-ocean/src/data_acces/test/masternode_test.rs new file mode 100644 index 00000000000..7ad29de0228 --- /dev/null +++ b/lib/ain-ocean/src/data_acces/test/masternode_test.rs @@ -0,0 +1,82 @@ +#[cfg(test)] +mod tests { + use super::*; + use crate::data_acces::masternode::MasterNodeDB; + use crate::database::db_manager::{RocksDB, SortOrder}; + use crate::model::masternode::{HistoryItem, Masternode, MasternodeBlock}; + use chrono::Utc; + use tempfile::tempdir; + + fn setup_test_db() -> MasterNodeDB { + let temp_dir = tempdir().unwrap(); + let db = RocksDB::new(temp_dir.path().to_str().unwrap()).unwrap(); // Adjust this according to your RocksDB struct + MasterNodeDB { db } + } + fn create_dummy_masternode(id: &str) -> Masternode { + Masternode { + id: id.to_string(), + sort: Some("dummy_sort".to_string()), + owner_address: "dummy_owner_address".to_string(), + operator_address: "dummy_operator_address".to_string(), + creation_height: 100, + resign_height: 200, + resign_tx: Some("dummy_resign_tx".to_string()), + minted_blocks: 50, + timelock: 10, + collateral: "dummy_collateral".to_string(), + block: create_dummy_masternode_block(), + history: Some(vec![create_dummy_history_item()]), + } + } + + fn create_dummy_masternode_block() -> MasternodeBlock { + MasternodeBlock { + hash: "dummy_hash".to_string(), + height: 100, + time: Utc::now().timestamp() as u64, + median_time: Utc::now().timestamp() as u64, + } + } + + fn create_dummy_history_item() -> HistoryItem { + HistoryItem { + txid: "dummy_txid".to_string(), + owner_address: "dummy_history_owner_address".to_string(), + operator_address: "dummy_history_operator_address".to_string(), + } + } + + #[tokio::test] + async fn test_query_with_dummy_data() { + let master_node = setup_test_db(); + let request = create_dummy_masternode("1"); + let result = master_node.store(request).await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_store_and_query_dummy_data() { + let master_node = setup_test_db(); + let dummy_data = vec![ + create_dummy_masternode("1"), + create_dummy_masternode("2"), + create_dummy_masternode("3"), + create_dummy_masternode("4"), + create_dummy_masternode("5"), + create_dummy_masternode("6"), + create_dummy_masternode("7"), + create_dummy_masternode("8"), + create_dummy_masternode("9"), + create_dummy_masternode("10"), + ]; + + for masternode in dummy_data { + let result = master_node.store(masternode).await; + assert!(result.is_ok()); + } + // let query_result = master_node.query(5, 8, SortOrder::Ascending).await; + // assert!(query_result.is_err()); + // let queried_masternodes = query_result.unwrap(); + // assert_eq!(queried_masternodes.len(), 5); + } +} diff --git a/lib/ain-ocean/src/data_acces/test/mod.rs b/lib/ain-ocean/src/data_acces/test/mod.rs index bd9b68cbdc5..350db04c962 100644 --- a/lib/ain-ocean/src/data_acces/test/mod.rs +++ b/lib/ain-ocean/src/data_acces/test/mod.rs @@ -1,2 +1,4 @@ +mod block_test; +mod masternode_test; mod oracle_test; mod transaction_test; diff --git a/lib/ain-ocean/src/data_acces/test/transaction_test.rs b/lib/ain-ocean/src/data_acces/test/transaction_test.rs index bde9c788fba..e87196a35a2 100644 --- a/lib/ain-ocean/src/data_acces/test/transaction_test.rs +++ b/lib/ain-ocean/src/data_acces/test/transaction_test.rs @@ -100,4 +100,20 @@ mod tests { let result = txn_vin_db.delete(trx_id).await; assert!(result.is_ok()); } + + #[tokio::test] + async fn test_query_transaction() { + let txn_vin_db = setup_test_db(); + + let test_transaction = sample_transaction("tx1"); + let trx_id = test_transaction.id.clone(); + + let result = txn_vin_db.store(test_transaction.clone()).await; + assert!(result.is_ok()); + + let result = txn_vin_db + .query_by_block_hash(test_transaction.block.hash.to_string(), 10, 0) + .await; + assert!(result.is_ok()); + } } diff --git a/lib/ain-ocean/src/data_acces/transaction.rs b/lib/ain-ocean/src/data_acces/transaction.rs index 061074eb125..487a954c4a6 100644 --- a/lib/ain-ocean/src/data_acces/transaction.rs +++ b/lib/ain-ocean/src/data_acces/transaction.rs @@ -23,15 +23,29 @@ impl TransactionVinDb { } } pub async fn store(&self, txn: Transaction) -> Result<()> { - match serde_json::to_string(&txn) { - Ok(value) => { - let key = txn.id.clone(); - self.db - .put("transaction", key.as_bytes(), value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } + let value = serde_json::to_string(&txn)?; + let txid_key = txn.txid.clone(); + self.db + .put("transaction", txid_key.as_bytes(), value.as_bytes())?; + + // Retrieve existing transaction IDs for the block hash, if any + let mut txn_ids = match self + .db + .get("transaction_mapper", txn.block.hash.as_bytes())? + { + Some(bytes) => serde_json::from_slice::>(&bytes)?, + None => vec![], + }; + + // Add the new transaction ID to the list + txn_ids.push(txn.txid); + let txn_ids_value = serde_json::to_string(&txn_ids)?; + self.db.put( + "transaction_mapper", + txn.block.hash.as_bytes(), + txn_ids_value.as_bytes(), + )?; + Ok(()) } pub async fn delete(&self, txid: String) -> Result<()> { match self.db.delete("transaction", txid.as_bytes()) { @@ -39,12 +53,39 @@ impl TransactionVinDb { Err(e) => Err(anyhow!(e)), } } - pub async fn query_by_blockhash( + pub async fn query_by_block_hash( &self, hash: String, limit: i32, lt: i32, ) -> Result> { - todo!() + let mut transactions = Vec::new(); + + // Retrieve the transaction ID(s) associated with the block hash + match self.db.get("transaction_mapper", hash.as_bytes()) { + Ok(Some(txn_id_bytes)) => { + // Assuming one block hash maps to multiple transaction IDs + println!("the value in trx{:?}", txn_id_bytes); + let txn_ids: Vec = serde_json::from_slice::>(&txn_id_bytes)?; + + for txn_id in txn_ids.iter().take(limit as usize) { + // Retrieve the transaction details for each transaction ID + match self.db.get("transaction", txn_id.as_bytes()) { + Ok(Some(txn_bytes)) => { + let txn: Transaction = serde_json::from_slice(&txn_bytes)?; + transactions.push(txn); + } + Ok(None) => { + return Err(anyhow!("Transaction not found for ID: {}", txn_id)) + } + Err(e) => return Err(anyhow!("Database error: {}", e)), + } + } + } + Ok(None) => return Err(anyhow!("No transactions found for block hash: {}", hash)), + Err(e) => return Err(anyhow!("Database error: {}", e)), + } + + Ok(transactions) } } diff --git a/lib/ain-ocean/src/data_acces/transaction_vin.rs b/lib/ain-ocean/src/data_acces/transaction_vin.rs index 8964743c4d2..20b80f81093 100644 --- a/lib/ain-ocean/src/data_acces/transaction_vin.rs +++ b/lib/ain-ocean/src/data_acces/transaction_vin.rs @@ -1,8 +1,8 @@ use anyhow::{anyhow, Result}; -use serde::{Deserialize, Serialize}; +use rocksdb::IteratorMode; use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, model::transaction_vin::TransactionVin, }; @@ -16,7 +16,13 @@ impl TransactionVinDb { match serde_json::to_string(&trx_vin) { Ok(value) => { let key = trx_vin.id.clone(); - self.db.put("oracle", key.as_bytes(), value.as_bytes())?; + self.db + .put("transaction_vin", key.as_bytes(), value.as_bytes())?; + self.db.put( + "transaction_vin_mapper", + trx_vin.txid.as_bytes(), + trx_vin.id.as_bytes(), + )?; Ok(()) } Err(e) => Err(anyhow!(e)), @@ -28,7 +34,38 @@ impl TransactionVinDb { Err(e) => Err(anyhow!(e)), } } - pub async fn query(&self, txid: String, limit: i32, lt: i32) -> Result> { - todo!() + pub async fn query( + &self, + tx_id: String, + limit: i32, + lt: i32, + sort_order: SortOrder, + ) -> Result> { + let iterator = self.db.iterator("transaction_vin", IteratorMode::End)?; + let mut trx_vin: Vec = Vec::new(); + let collected_blocks: Vec<_> = iterator.collect(); + + for result in collected_blocks.into_iter().rev() { + let (key, value) = match result { + Ok((key, value)) => (key, value), + Err(err) => return Err(anyhow!("Error during iteration: {}", err)), + }; + + let vin: TransactionVin = serde_json::from_slice(&value)?; + if vin.txid == tx_id { + trx_vin.push(vin); + if trx_vin.len() as i32 >= limit { + break; + } + } + } + + // Sort blocks based on the specified sort order + match sort_order { + SortOrder::Ascending => trx_vin.sort_by(|a, b| a.txid.cmp(&b.txid)), + SortOrder::Descending => trx_vin.sort_by(|a, b| b.txid.cmp(&a.txid)), + } + + Ok(trx_vin) } } diff --git a/lib/ain-ocean/src/data_acces/transaction_vout.rs b/lib/ain-ocean/src/data_acces/transaction_vout.rs index 9f11f982789..aab89713d08 100644 --- a/lib/ain-ocean/src/data_acces/transaction_vout.rs +++ b/lib/ain-ocean/src/data_acces/transaction_vout.rs @@ -1,8 +1,8 @@ use anyhow::{anyhow, Result}; -use serde::{Deserialize, Serialize}; +use rocksdb::IteratorMode; use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, model::transaction_vout::TransactionVout, }; @@ -12,8 +12,8 @@ pub struct TransactionVoutDb { } impl TransactionVoutDb { - pub async fn get(&self, txid: String, n: i64) -> Result> { - match self.db.get("transaction_vout", txid.as_bytes()) { + pub async fn get(&self, tx_id: String, n: i64) -> Result> { + match self.db.get("transaction_vout", tx_id.as_bytes()) { Ok(Some(value)) => { let master_node: TransactionVout = serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; @@ -24,23 +24,59 @@ impl TransactionVoutDb { } } pub async fn store(&self, trx_out: TransactionVout) -> Result<()> { - match serde_json::to_string(&trx_out) { - Ok(value) => { - let key = trx_out.id.clone(); - self.db - .put("transaction_vout", key.as_bytes(), value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } + let value = serde_json::to_string(&trx_out)?; + let key = trx_out.id.clone(); + self.db + .put("transaction_vout", key.as_bytes(), value.as_bytes())?; + + // Accumulate transaction vout IDs for each txid + let mut vout_ids = match self + .db + .get("transaction_vout_mapper", trx_out.txid.as_bytes())? + { + Some(bytes) => serde_json::from_slice::>(&bytes)?, + None => vec![], + }; + vout_ids.push(trx_out.id); + let vout_ids_value = serde_json::to_string(&vout_ids)?; + self.db.put( + "transaction_vout_mapper", + trx_out.txid.as_bytes(), + vout_ids_value.as_bytes(), + )?; + + Ok(()) } - pub async fn delete(&self, id: String) -> Result<()> { - match self.db.delete("transaction_vout", id.as_bytes()) { + pub async fn delete(&self, trx_id: String) -> Result<()> { + match self.db.delete("transaction_vout", trx_id.as_bytes()) { Ok(_) => Ok(()), Err(e) => Err(anyhow!(e)), } } - pub async fn query(&self, txid: String, limit: i32, lt: i32) -> Result { - todo!() + pub async fn query( + &self, + tx_id: String, + limit: i32, + lt: i32, + sort_order: SortOrder, + ) -> Result> { + let iterator = self.db.iterator("transaction_vout", IteratorMode::End)?; + let mut trx_vout: Vec = Vec::new(); + if let Some(bytes) = self.db.get("transaction_vout_mapper", tx_id.as_bytes())? { + let vout_ids: Vec = serde_json::from_slice(&bytes)?; + for vout_id in vout_ids.iter().take(limit as usize) { + if let Some(vout_bytes) = self.db.get("transaction_vout", vout_id.as_bytes())? { + let vout: TransactionVout = serde_json::from_slice(&vout_bytes)?; + trx_vout.push(vout); + } + } + } + + match sort_order { + SortOrder::Ascending => trx_vout.sort_by(|a, b| a.n.cmp(&b.n)), + SortOrder::Descending => trx_vout.sort_by(|a, b| b.n.cmp(&a.n)), + } + + Ok(trx_vout) } } diff --git a/lib/ain-ocean/src/data_acces/vault_auction_batch_history.rs b/lib/ain-ocean/src/data_acces/vault_auction_batch_history.rs index eaf89997f83..1f91c9c20a4 100644 --- a/lib/ain-ocean/src/data_acces/vault_auction_batch_history.rs +++ b/lib/ain-ocean/src/data_acces/vault_auction_batch_history.rs @@ -1,5 +1,4 @@ -use anyhow::{anyhow, Error, Result}; -use serde::{Deserialize, Serialize}; +use anyhow::{anyhow, Result}; use serde_json; use crate::{ diff --git a/lib/ain-ocean/src/database/db_manager.rs b/lib/ain-ocean/src/database/db_manager.rs index 4a7392e186c..1c06b1901c8 100644 --- a/lib/ain-ocean/src/database/db_manager.rs +++ b/lib/ain-ocean/src/database/db_manager.rs @@ -5,7 +5,7 @@ use bitcoin::{ blockdata::block::{Block, Header}, consensus::encode::serialize, }; -use rocksdb::{ColumnFamilyDescriptor, DBIterator, IteratorMode, Options, DB}; +use rocksdb::{ColumnFamilyDescriptor, DBIterator, Direction, IteratorMode, Options, DB}; use serde::{Deserialize, Serialize}; use crate::model::oracle::Oracle; @@ -16,6 +16,12 @@ pub struct RocksDB { cfs: HashSet, } +#[derive(Debug, PartialEq, Clone)] +pub enum SortOrder { + Ascending, + Descending, +} + pub trait ColumnFamilyOperations { fn get(&self, cf_name: &str, key: &[u8]) -> Result>>; fn put(&self, cf_name: &str, key: &[u8], value: &[u8]) -> Result<()>; @@ -281,3 +287,12 @@ impl ColumnFamilyOperations for RocksDB { } } } + +impl<'a> From for IteratorMode<'a> { + fn from(sort_order: SortOrder) -> Self { + match sort_order { + SortOrder::Ascending => IteratorMode::Start, + SortOrder::Descending => IteratorMode::From(b"", Direction::Reverse), + } + } +} diff --git a/lib/ain-ocean/src/model/block.rs b/lib/ain-ocean/src/model/block.rs index 55517511da5..bf542a2c276 100644 --- a/lib/ain-ocean/src/model/block.rs +++ b/lib/ain-ocean/src/model/block.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Block { pub id: String, diff --git a/lib/ain-ocean/src/model/poolswap.rs b/lib/ain-ocean/src/model/poolswap.rs index 777d7e3a3f9..16dd5d0ba58 100644 --- a/lib/ain-ocean/src/model/poolswap.rs +++ b/lib/ain-ocean/src/model/poolswap.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default, PartialEq)] #[serde(rename_all = "camelCase")] pub struct PoolSwap { pub id: String, @@ -13,7 +13,7 @@ pub struct PoolSwap { pub block: PoolSwapBlock, } -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default, PartialEq)] #[serde(rename_all = "camelCase")] pub struct PoolSwapBlock { pub hash: String, From b675feadbe5a20ffe025f692da9102820b409106 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Wed, 27 Dec 2023 08:07:48 +0100 Subject: [PATCH 015/185] Enhance Ocean database implementation (#2762) * OceanStore building * With RepositoryOps trait * Cleanup columns * Implement put/get/list masternode * Fix MasternodeByHeight get_key * Cleanup MasternodeData * Invalidate masternode * Remove comments * cfg(test_off) --------- Co-authored-by: canonbrother --- lib/Cargo.lock | 18 +- lib/Cargo.toml | 2 + lib/ain-db/Cargo.toml | 13 + lib/ain-db/src/lib.rs | 232 ++++++++++++++ lib/ain-evm/Cargo.toml | 1 + lib/ain-evm/src/lib.rs | 2 + lib/ain-evm/src/storage/block_store.rs | 41 ++- lib/ain-evm/src/storage/db.rs | 239 ++------------ lib/ain-macros/src/lib.rs | 80 ++++- lib/ain-ocean/Cargo.toml | 4 + lib/ain-ocean/src/api/masternode.rs | 118 ++++++- lib/ain-ocean/src/data_acces/block.rs | 171 ---------- lib/ain-ocean/src/data_acces/masternode.rs | 74 ----- .../src/data_acces/masternode_stats.rs | 110 ------- lib/ain-ocean/src/data_acces/mod.rs | 22 -- lib/ain-ocean/src/data_acces/oracle.rs | 73 ----- .../src/data_acces/oracle_price_active.rs | 67 ---- .../src/data_acces/oracle_price_aggregated.rs | 74 ----- .../oracle_price_aggregated_interval.rs | 68 ---- .../src/data_acces/oracle_price_feed.rs | 66 ---- .../src/data_acces/oracle_token_currency.rs | 67 ---- lib/ain-ocean/src/data_acces/order_history.rs | 66 ---- lib/ain-ocean/src/data_acces/pool_swap.rs | 64 ---- .../src/data_acces/pool_swap_aggregated.rs | 78 ----- lib/ain-ocean/src/data_acces/price_ticker.rs | 72 ----- lib/ain-ocean/src/data_acces/raw_block.rs | 41 --- .../src/data_acces/script_activity.rs | 67 ---- .../src/data_acces/script_aggregation.rs | 93 ------ .../src/data_acces/script_unspent.rs | 68 ---- lib/ain-ocean/src/data_acces/transaction.rs | 91 ------ .../src/data_acces/transaction_vin.rs | 71 ----- .../src/data_acces/transaction_vout.rs | 82 ----- .../data_acces/vault_auction_batch_history.rs | 42 --- lib/ain-ocean/src/database/config.rs | 36 --- lib/ain-ocean/src/database/db_manager.rs | 298 ------------------ lib/ain-ocean/src/database/db_test.rs | 180 ----------- lib/ain-ocean/src/database/mod.rs | 3 - lib/ain-ocean/src/error.rs | 29 +- lib/ain-ocean/src/indexer/auction.rs | 4 +- lib/ain-ocean/src/indexer/masternode.rs | 37 ++- lib/ain-ocean/src/indexer/mod.rs | 30 +- lib/ain-ocean/src/indexer/oracle.rs | 16 +- lib/ain-ocean/src/indexer/pool.rs | 8 +- lib/ain-ocean/src/lib.rs | 43 ++- lib/ain-ocean/src/model/masternode.rs | 100 +----- lib/ain-ocean/src/model/mod.rs | 64 ++-- lib/ain-ocean/src/repository/block.rs | 1 + lib/ain-ocean/src/repository/masternode.rs | 41 +++ .../src/repository/masternode_stats.rs | 23 ++ lib/ain-ocean/src/repository/mod.rs | 50 +++ .../src/repository/oracle_price_active.rs | 1 + .../src/repository/oracle_price_aggregated.rs | 1 + .../oracle_price_aggregated_interval.rs | 1 + .../src/repository/oracle_price_feed.rs | 1 + .../src/repository/oracle_token_currency.rs | 1 + lib/ain-ocean/src/repository/pool_swap.rs | 1 + .../src/repository/pool_swap_aggregated.rs | 1 + lib/ain-ocean/src/repository/price_ticker.rs | 1 + lib/ain-ocean/src/repository/raw_block.rs | 1 + .../src/repository/script_activity.rs | 1 + .../src/repository/script_aggregation.rs | 1 + .../src/repository/script_unspent.rs | 1 + .../test/block_test.rs | 2 +- .../test/masternode_test.rs | 2 +- .../{data_acces => repository}/test/mod.rs | 0 .../test/oracle_test.rs | 2 +- .../test/transaction_test.rs | 2 +- lib/ain-ocean/src/repository/transaction.rs | 1 + .../src/repository/transaction_vin.rs | 1 + .../src/repository/transaction_vout.rs | 1 + .../repository/vault_auction_batch_history.rs | 1 + lib/ain-ocean/src/storage/columns/block.rs | 24 ++ .../src/storage/columns/masternode.rs | 71 +++++ .../src/storage/columns/masternode_stats.rs | 29 ++ lib/ain-ocean/src/storage/columns/mod.rs | 66 ++++ .../src/storage/columns/oracle_history.rs | 28 ++ .../storage/columns/oracle_price_active.rs | 28 ++ .../columns/oracle_price_aggregated.rs | 28 ++ .../oracle_price_aggregated_interval.rs | 28 ++ .../src/storage/columns/oracle_price_feed.rs | 28 ++ .../storage/columns/oracle_token_currency.rs | 28 ++ .../src/storage/columns/pool_swap.rs | 28 ++ .../storage/columns/pool_swap_aggregated.rs | 27 ++ .../src/storage/columns/price_ticker.rs | 28 ++ .../src/storage/columns/raw_block.rs | 28 ++ .../src/storage/columns/script_activity.rs | 28 ++ .../src/storage/columns/script_aggregation.rs | 28 ++ .../src/storage/columns/script_unspent.rs | 28 ++ .../src/storage/columns/transaction.rs | 28 ++ .../src/storage/columns/transaction_vin.rs | 28 ++ .../src/storage/columns/transaction_vout.rs | 28 ++ .../storage/columns/vault_auction_history.rs | 28 ++ lib/ain-ocean/src/storage/mod.rs | 19 ++ lib/ain-ocean/src/storage/ocean_store.rs | 63 ++++ lib/ain-rs-exports/src/ocean.rs | 20 +- src/dfi/validation.cpp | 6 +- 96 files changed, 1586 insertions(+), 2551 deletions(-) create mode 100644 lib/ain-db/Cargo.toml create mode 100644 lib/ain-db/src/lib.rs delete mode 100644 lib/ain-ocean/src/data_acces/block.rs delete mode 100644 lib/ain-ocean/src/data_acces/masternode.rs delete mode 100644 lib/ain-ocean/src/data_acces/masternode_stats.rs delete mode 100644 lib/ain-ocean/src/data_acces/mod.rs delete mode 100644 lib/ain-ocean/src/data_acces/oracle.rs delete mode 100644 lib/ain-ocean/src/data_acces/oracle_price_active.rs delete mode 100644 lib/ain-ocean/src/data_acces/oracle_price_aggregated.rs delete mode 100644 lib/ain-ocean/src/data_acces/oracle_price_aggregated_interval.rs delete mode 100644 lib/ain-ocean/src/data_acces/oracle_price_feed.rs delete mode 100644 lib/ain-ocean/src/data_acces/oracle_token_currency.rs delete mode 100644 lib/ain-ocean/src/data_acces/order_history.rs delete mode 100644 lib/ain-ocean/src/data_acces/pool_swap.rs delete mode 100644 lib/ain-ocean/src/data_acces/pool_swap_aggregated.rs delete mode 100644 lib/ain-ocean/src/data_acces/price_ticker.rs delete mode 100644 lib/ain-ocean/src/data_acces/raw_block.rs delete mode 100644 lib/ain-ocean/src/data_acces/script_activity.rs delete mode 100644 lib/ain-ocean/src/data_acces/script_aggregation.rs delete mode 100644 lib/ain-ocean/src/data_acces/script_unspent.rs delete mode 100644 lib/ain-ocean/src/data_acces/transaction.rs delete mode 100644 lib/ain-ocean/src/data_acces/transaction_vin.rs delete mode 100644 lib/ain-ocean/src/data_acces/transaction_vout.rs delete mode 100644 lib/ain-ocean/src/data_acces/vault_auction_batch_history.rs delete mode 100644 lib/ain-ocean/src/database/config.rs delete mode 100644 lib/ain-ocean/src/database/db_manager.rs delete mode 100644 lib/ain-ocean/src/database/db_test.rs delete mode 100644 lib/ain-ocean/src/database/mod.rs create mode 100644 lib/ain-ocean/src/repository/block.rs create mode 100644 lib/ain-ocean/src/repository/masternode.rs create mode 100644 lib/ain-ocean/src/repository/masternode_stats.rs create mode 100644 lib/ain-ocean/src/repository/mod.rs create mode 100644 lib/ain-ocean/src/repository/oracle_price_active.rs create mode 100644 lib/ain-ocean/src/repository/oracle_price_aggregated.rs create mode 100644 lib/ain-ocean/src/repository/oracle_price_aggregated_interval.rs create mode 100644 lib/ain-ocean/src/repository/oracle_price_feed.rs create mode 100644 lib/ain-ocean/src/repository/oracle_token_currency.rs create mode 100644 lib/ain-ocean/src/repository/pool_swap.rs create mode 100644 lib/ain-ocean/src/repository/pool_swap_aggregated.rs create mode 100644 lib/ain-ocean/src/repository/price_ticker.rs create mode 100644 lib/ain-ocean/src/repository/raw_block.rs create mode 100644 lib/ain-ocean/src/repository/script_activity.rs create mode 100644 lib/ain-ocean/src/repository/script_aggregation.rs create mode 100644 lib/ain-ocean/src/repository/script_unspent.rs rename lib/ain-ocean/src/{data_acces => repository}/test/block_test.rs (99%) rename lib/ain-ocean/src/{data_acces => repository}/test/masternode_test.rs (99%) rename lib/ain-ocean/src/{data_acces => repository}/test/mod.rs (100%) rename lib/ain-ocean/src/{data_acces => repository}/test/oracle_test.rs (99%) rename lib/ain-ocean/src/{data_acces => repository}/test/transaction_test.rs (99%) create mode 100644 lib/ain-ocean/src/repository/transaction.rs create mode 100644 lib/ain-ocean/src/repository/transaction_vin.rs create mode 100644 lib/ain-ocean/src/repository/transaction_vout.rs create mode 100644 lib/ain-ocean/src/repository/vault_auction_batch_history.rs create mode 100644 lib/ain-ocean/src/storage/columns/block.rs create mode 100644 lib/ain-ocean/src/storage/columns/masternode.rs create mode 100644 lib/ain-ocean/src/storage/columns/masternode_stats.rs create mode 100644 lib/ain-ocean/src/storage/columns/mod.rs create mode 100644 lib/ain-ocean/src/storage/columns/oracle_history.rs create mode 100644 lib/ain-ocean/src/storage/columns/oracle_price_active.rs create mode 100644 lib/ain-ocean/src/storage/columns/oracle_price_aggregated.rs create mode 100644 lib/ain-ocean/src/storage/columns/oracle_price_aggregated_interval.rs create mode 100644 lib/ain-ocean/src/storage/columns/oracle_price_feed.rs create mode 100644 lib/ain-ocean/src/storage/columns/oracle_token_currency.rs create mode 100644 lib/ain-ocean/src/storage/columns/pool_swap.rs create mode 100644 lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs create mode 100644 lib/ain-ocean/src/storage/columns/price_ticker.rs create mode 100644 lib/ain-ocean/src/storage/columns/raw_block.rs create mode 100644 lib/ain-ocean/src/storage/columns/script_activity.rs create mode 100644 lib/ain-ocean/src/storage/columns/script_aggregation.rs create mode 100644 lib/ain-ocean/src/storage/columns/script_unspent.rs create mode 100644 lib/ain-ocean/src/storage/columns/transaction.rs create mode 100644 lib/ain-ocean/src/storage/columns/transaction_vin.rs create mode 100644 lib/ain-ocean/src/storage/columns/transaction_vout.rs create mode 100644 lib/ain-ocean/src/storage/columns/vault_auction_history.rs create mode 100644 lib/ain-ocean/src/storage/mod.rs create mode 100644 lib/ain-ocean/src/storage/ocean_store.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index eb7dc80c48a..15d68bce0a1 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -105,12 +105,24 @@ dependencies = [ "serde", ] +[[package]] +name = "ain-db" +version = "0.1.0" +dependencies = [ + "ain-cpp-imports", + "anyhow", + "bincode", + "rocksdb", + "serde", +] + [[package]] name = "ain-evm" version = "0.1.0" dependencies = [ "ain-contracts", "ain-cpp-imports", + "ain-db", "anyhow", "axum 0.7.2", "bincode", @@ -214,12 +226,15 @@ name = "ain-ocean" version = "0.1.0" dependencies = [ "ain-cpp-imports", + "ain-db", + "ain-macros", "anyhow", "axum 0.7.2", + "bincode", "bitcoin", "bitcoin_hashes 0.12.0", - "chrono", "cached", + "chrono", "ctrlc", "dftx-rs", "futures", @@ -228,6 +243,7 @@ dependencies = [ "json", "jsonrpsee 0.20.3", "keccak-hash", + "lazy_static", "log", "rocksdb", "serde", diff --git a/lib/Cargo.toml b/lib/Cargo.toml index beb7be70522..340905285b1 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -124,3 +124,5 @@ cached = "0.46" ### Local crates ain-cpp-imports = { path = "./ain-cpp-imports" } +ain-db = { path = "./ain-db" } +ain-macros = { path = "./ain-macros" } diff --git a/lib/ain-db/Cargo.toml b/lib/ain-db/Cargo.toml new file mode 100644 index 00000000000..8230f3971a8 --- /dev/null +++ b/lib/ain-db/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "ain-db" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde.workspace = true +bincode.workspace = true +rocksdb.workspace = true +ain-cpp-imports.workspace = true +anyhow.workspace = true diff --git a/lib/ain-db/src/lib.rs b/lib/ain-db/src/lib.rs new file mode 100644 index 00000000000..683bc98411a --- /dev/null +++ b/lib/ain-db/src/lib.rs @@ -0,0 +1,232 @@ +use std::{ + fmt::Debug, + iter::Iterator, + marker::PhantomData, + path::{Path, PathBuf}, + sync::Arc, +}; + +use bincode; +use rocksdb::{ + BlockBasedOptions, Cache, ColumnFamily, ColumnFamilyDescriptor, DBIterator, IteratorMode, + Options, DB, +}; +use serde::{de::DeserializeOwned, Serialize}; + +pub type Result = result::Result; + +fn get_db_options() -> Options { + let mut options = Options::default(); + options.create_if_missing(true); + options.create_missing_column_families(true); + + let n = ain_cpp_imports::get_num_cores(); + options.increase_parallelism(n); + + let mut env = rocksdb::Env::new().unwrap(); + + // While a compaction is ongoing, all the background threads + // could be used by the compaction. This can stall writes which + // need to flush the memtable. Add some high-priority background threads + // which can service these writes. + env.set_high_priority_background_threads(4); + options.set_env(&env); + + // Set max total wal size to 4G. + options.set_max_total_wal_size(4 * 1024 * 1024 * 1024); + + let cache = Cache::new_lru_cache(512 * 1024 * 1024); + let mut block_opts = BlockBasedOptions::default(); + block_opts.set_block_cache(&cache); + block_opts.set_bloom_filter(10.0, false); + options.set_block_based_table_factory(&block_opts); + + options +} + +#[derive(Debug)] +pub struct Rocks(DB); + +impl Rocks { + pub fn open(path: &PathBuf, cf_names: &[&'static str]) -> Result { + let cf_descriptors = cf_names + .into_iter() + .map(|cf_name| ColumnFamilyDescriptor::new(*cf_name, Options::default())); + + let db_opts = get_db_options(); + let db = DB::open_cf_descriptors(&db_opts, path, cf_descriptors)?; + + Ok(Self(db)) + } + + #[allow(dead_code)] + fn destroy(path: &Path) -> Result<()> { + DB::destroy(&Options::default(), path)?; + + Ok(()) + } + + pub fn cf_handle(&self, cf: &str) -> &ColumnFamily { + self.0 + .cf_handle(cf) + .expect("should never get an unknown column") + } + + fn get_cf(&self, cf: &ColumnFamily, key: &[u8]) -> Result>> { + let opt = self.0.get_cf(cf, key)?; + Ok(opt) + } + + fn put_cf(&self, cf: &ColumnFamily, key: &[u8], value: &[u8]) -> Result<()> { + self.0.put_cf(cf, key, value)?; + Ok(()) + } + + fn delete_cf(&self, cf: &ColumnFamily, key: &[u8]) -> Result<()> { + self.0.delete_cf(cf, key)?; + Ok(()) + } + + pub fn iterator_cf(&self, cf: &ColumnFamily, iterator_mode: IteratorMode) -> DBIterator + where + C: Column, + { + self.0.iterator_cf(cf, iterator_mode) + } + + pub fn flush(&self) -> Result<()> { + self.0.flush()?; + Ok(()) + } +} + +// +// ColumnName trait. Define associated column family NAME +// +pub trait ColumnName { + const NAME: &'static str; +} + +// +// Column trait. Define associated index type +// +pub trait Column { + type Index: Debug; + + fn key(index: &Self::Index) -> Vec; + + fn get_key(raw_key: Box<[u8]>) -> Result; +} + +// +// TypedColumn trait. Define associated value type +// +pub trait TypedColumn: Column { + type Type: Serialize + DeserializeOwned + Debug; +} + +#[derive(Debug, Clone)] +pub struct LedgerColumn +where + C: Column + ColumnName, +{ + pub backend: Arc, + pub column: PhantomData, +} + +impl LedgerColumn +where + C: Column + ColumnName, +{ + pub fn get_bytes(&self, key: &C::Index) -> Result>> { + self.backend.get_cf(self.handle(), &C::key(key)) + } + + pub fn put_bytes(&self, key: &C::Index, value: &[u8]) -> Result<()> { + self.backend.put_cf(self.handle(), &C::key(key), value) + } + + pub fn handle(&self) -> &ColumnFamily { + self.backend.cf_handle(C::NAME) + } +} + +impl LedgerColumn +where + C: TypedColumn + ColumnName, +{ + pub fn get(&self, key: &C::Index) -> Result> { + if let Some(serialized_value) = self.get_bytes(key)? { + let value = bincode::deserialize(&serialized_value)?; + Ok(Some(value)) + } else { + Ok(None) + } + } + + pub fn put(&self, key: &C::Index, value: &C::Type) -> Result<()> { + let serialized_value = bincode::serialize(value)?; + self.put_bytes(key, &serialized_value) + } + + pub fn delete(&self, key: &C::Index) -> Result<()> { + self.backend.delete_cf(self.handle(), &C::key(key)) + } + + pub fn iter( + &self, + from: Option, + limit: usize, + ) -> impl Iterator + '_ { + let index = from.as_ref().map(|i| C::key(i)).unwrap_or_default(); + let iterator_mode = from.map_or(IteratorMode::Start, |_| { + IteratorMode::From(&index, rocksdb::Direction::Forward) + }); + self.backend + .iterator_cf::(self.handle(), iterator_mode) + .filter_map(|k| { + k.ok().and_then(|(k, v)| { + let value = bincode::deserialize(&v).ok()?; + let key = C::get_key(k).ok()?; + Some((key, value)) + }) + }) + .take(limit) + } +} + +use std::{error::Error, fmt, result}; + +use bincode::Error as BincodeError; +use rocksdb::Error as RocksDBError; + +#[derive(Debug)] +pub enum DBError { + RocksDBError(RocksDBError), + Bincode(BincodeError), + Custom(anyhow::Error), +} + +impl fmt::Display for DBError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DBError::RocksDBError(e) => write!(f, "RocksDB Error: {e}"), + DBError::Bincode(e) => write!(f, "Bincode Error: {e}"), + DBError::Custom(e) => write!(f, "Custom Error: {e}"), + } + } +} + +impl Error for DBError {} + +impl From for DBError { + fn from(e: RocksDBError) -> Self { + DBError::RocksDBError(e) + } +} + +impl From for DBError { + fn from(e: BincodeError) -> Self { + DBError::Bincode(e) + } +} diff --git a/lib/ain-evm/Cargo.toml b/lib/ain-evm/Cargo.toml index debd8a18640..7d88c289b23 100644 --- a/lib/ain-evm/Cargo.toml +++ b/lib/ain-evm/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] ain-cpp-imports.workspace = true +ain-db.workspace = true ain-contracts = { path = "../ain-contracts" } evm = { workspace = true, default-features = false, features = ["with-serde", "tracing", "std"] } diff --git a/lib/ain-evm/src/lib.rs b/lib/ain-evm/src/lib.rs index 0ad5d685e48..88884eda41c 100644 --- a/lib/ain-evm/src/lib.rs +++ b/lib/ain-evm/src/lib.rs @@ -59,6 +59,8 @@ pub enum EVMError { JsonRpcError(#[from] jsonrpsee_core::Error), #[error("EVM: rocksdb error")] RocksDBError(#[from] rocksdb::Error), + #[error("EVM: db error")] + DBError(#[from] ain_db::DBError), #[error("EVM: ethabi error")] EthAbiError(#[from] ethabi::Error), #[error(transparent)] diff --git a/lib/ain-evm/src/storage/block_store.rs b/lib/ain-evm/src/storage/block_store.rs index d442418492a..b3f1be5ae52 100644 --- a/lib/ain-evm/src/storage/block_store.rs +++ b/lib/ain-evm/src/storage/block_store.rs @@ -2,13 +2,14 @@ use std::{ collections::HashMap, fmt::Write, fs, marker::PhantomData, path::Path, str::FromStr, sync::Arc, }; +use ain_db::{Column, ColumnName, LedgerColumn, Rocks, TypedColumn}; use anyhow::format_err; use ethereum::{BlockAny, TransactionV2}; use ethereum_types::{H160, H256, U256}; use log::debug; use super::{ - db::{Column, ColumnName, LedgerColumn, Rocks, TypedColumn}, + db::COLUMN_NAMES, traits::{BlockStorage, FlushableStorage, ReceiptStorage, Rollback, TransactionStorage}, }; use crate::{ @@ -25,7 +26,7 @@ impl BlockStore { pub fn new(path: &Path) -> Result { let path = path.join("indexes"); fs::create_dir_all(&path)?; - let backend = Arc::new(Rocks::open(&path)?); + let backend = Arc::new(Rocks::open(&path, &COLUMN_NAMES)?); Ok(Self(backend)) } @@ -52,7 +53,7 @@ impl TransactionStorage for BlockStore { fn get_transaction_by_hash(&self, hash: &H256) -> Result> { let transactions_cf = self.column::(); - transactions_cf.get(hash) + Ok(transactions_cf.get(hash)?) } fn get_transaction_by_block_hash_and_index( @@ -95,22 +96,21 @@ impl TransactionStorage for BlockStore { transaction.hash(), transaction ); - transactions_cf.put(&transaction.hash(), transaction) + Ok(transactions_cf.put(&transaction.hash(), transaction)?) } } impl BlockStorage for BlockStore { fn get_block_by_number(&self, number: &U256) -> Result> { let blocks_cf = self.column::(); - blocks_cf.get(number) + Ok(blocks_cf.get(number)?) } fn get_block_by_hash(&self, block_hash: &H256) -> Result> { let blocks_map_cf = self.column::(); - match blocks_map_cf.get(block_hash) { - Ok(Some(block_number)) => self.get_block_by_number(&block_number), - Ok(None) => Ok(None), - Err(e) => Err(e), + match blocks_map_cf.get(block_hash)? { + Some(block_number) => self.get_block_by_number(&block_number), + None => Ok(None), } } @@ -122,16 +122,15 @@ impl BlockStorage for BlockStore { let blocks_map_cf = self.column::(); blocks_cf.put(&block_number, block)?; - blocks_map_cf.put(&hash, &block_number) + Ok(blocks_map_cf.put(&hash, &block_number)?) } fn get_latest_block(&self) -> Result> { let latest_block_cf = self.column::(); - match latest_block_cf.get(&"") { - Ok(Some(block_number)) => self.get_block_by_number(&block_number), - Ok(None) => Ok(None), - Err(e) => Err(e), + match latest_block_cf.get(&"")? { + Some(block_number) => self.get_block_by_number(&block_number), + None => Ok(None), } } @@ -148,7 +147,7 @@ impl BlockStorage for BlockStore { impl ReceiptStorage for BlockStore { fn get_receipt(&self, tx: &H256) -> Result> { let receipts_cf = self.column::(); - receipts_cf.get(tx) + Ok(receipts_cf.get(tx)?) } fn put_receipts(&self, receipts: Vec) -> Result<()> { @@ -163,31 +162,31 @@ impl ReceiptStorage for BlockStore { impl LogStorage for BlockStore { fn get_logs(&self, block_number: &U256) -> Result>>> { let logs_cf = self.column::(); - logs_cf.get(block_number) + Ok(logs_cf.get(block_number)?) } fn put_logs(&self, address: H160, logs: Vec, block_number: U256) -> Result<()> { let logs_cf = self.column::(); if let Some(mut map) = self.get_logs(&block_number)? { map.insert(address, logs); - logs_cf.put(&block_number, &map) + Ok(logs_cf.put(&block_number, &map)?) } else { let map = HashMap::from([(address, logs)]); - logs_cf.put(&block_number, &map) + Ok(logs_cf.put(&block_number, &map)?) } } } impl FlushableStorage for BlockStore { fn flush(&self) -> Result<()> { - self.0.flush() + Ok(self.0.flush()?) } } impl BlockStore { pub fn get_code_by_hash(&self, address: H160, hash: &H256) -> Result>> { let address_codes_cf = self.column::(); - address_codes_cf.get_bytes(&(address, *hash)) + Ok(address_codes_cf.get_bytes(&(address, *hash))?) } pub fn put_code( @@ -201,7 +200,7 @@ impl BlockStore { address_codes_cf.put_bytes(&(address, *hash), code)?; let block_deployed_codes_cf = self.column::(); - block_deployed_codes_cf.put(&(block_number, address), hash) + Ok(block_deployed_codes_cf.put(&(block_number, address), hash)?) } } diff --git a/lib/ain-evm/src/storage/db.rs b/lib/ain-evm/src/storage/db.rs index d48a927bbf8..fbe168359c7 100644 --- a/lib/ain-evm/src/storage/db.rs +++ b/lib/ain-evm/src/storage/db.rs @@ -7,6 +7,7 @@ use std::{ sync::Arc, }; +use ain_db::{Column, ColumnName, DBError, LedgerColumn, TypedColumn}; use bincode; use ethereum::{BlockAny, TransactionV2}; use ethereum_types::{H160, H256, U256}; @@ -16,131 +17,7 @@ use rocksdb::{ }; use serde::{de::DeserializeOwned, Serialize}; -use crate::{log::LogIndex, receipt::Receipt, Result}; - -fn get_db_options() -> Options { - let mut options = Options::default(); - options.create_if_missing(true); - options.create_missing_column_families(true); - - let n = ain_cpp_imports::get_num_cores(); - options.increase_parallelism(n); - - let mut env = rocksdb::Env::new().unwrap(); - - // While a compaction is ongoing, all the background threads - // could be used by the compaction. This can stall writes which - // need to flush the memtable. Add some high-priority background threads - // which can service these writes. - env.set_high_priority_background_threads(4); - options.set_env(&env); - - // Set max total wal size to 4G. - options.set_max_total_wal_size(4 * 1024 * 1024 * 1024); - - let cache = Cache::new_lru_cache(512 * 1024 * 1024); - let mut block_opts = BlockBasedOptions::default(); - block_opts.set_block_cache(&cache); - block_opts.set_bloom_filter(10.0, false); - options.set_block_based_table_factory(&block_opts); - - options -} - -#[derive(Debug)] -pub struct Rocks(DB); - -impl Rocks { - pub fn open(path: &PathBuf) -> Result { - let cf_descriptors = Self::column_names() - .into_iter() - .map(|cf_name| ColumnFamilyDescriptor::new(cf_name, Options::default())); - - let db_opts = get_db_options(); - let db = DB::open_cf_descriptors(&db_opts, path, cf_descriptors)?; - - Ok(Self(db)) - } - - fn column_names() -> Vec<&'static str> { - vec![ - columns::Blocks::NAME, - columns::Transactions::NAME, - columns::Receipts::NAME, - columns::BlockMap::NAME, - columns::LatestBlockNumber::NAME, - columns::AddressLogsMap::NAME, - columns::AddressCodeMap::NAME, - columns::BlockDeployedCodeHashes::NAME, - ] - } - - #[allow(dead_code)] - fn destroy(path: &Path) -> Result<()> { - DB::destroy(&Options::default(), path)?; - - Ok(()) - } - - pub fn cf_handle(&self, cf: &str) -> &ColumnFamily { - self.0 - .cf_handle(cf) - .expect("should never get an unknown column") - } - - fn get_cf(&self, cf: &ColumnFamily, key: &[u8]) -> Result>> { - let opt = self.0.get_cf(cf, key)?; - Ok(opt) - } - - fn put_cf(&self, cf: &ColumnFamily, key: &[u8], value: &[u8]) -> Result<()> { - self.0.put_cf(cf, key, value)?; - Ok(()) - } - - fn delete_cf(&self, cf: &ColumnFamily, key: &[u8]) -> Result<()> { - self.0.delete_cf(cf, key)?; - Ok(()) - } - - pub fn iterator_cf(&self, cf: &ColumnFamily, iterator_mode: IteratorMode) -> DBIterator - where - C: Column, - { - self.0.iterator_cf(cf, iterator_mode) - } - - pub fn flush(&self) -> Result<()> { - self.0.flush()?; - Ok(()) - } -} - -#[derive(Debug, Clone)] -pub struct LedgerColumn -where - C: Column + ColumnName, -{ - pub backend: Arc, - pub column: PhantomData, -} - -impl LedgerColumn -where - C: Column + ColumnName, -{ - pub fn get_bytes(&self, key: &C::Index) -> Result>> { - self.backend.get_cf(self.handle(), &C::key(key)) - } - - pub fn put_bytes(&self, key: &C::Index, value: &[u8]) -> Result<()> { - self.backend.put_cf(self.handle(), &C::key(key), value) - } - - pub fn handle(&self) -> &ColumnFamily { - self.backend.cf_handle(C::NAME) - } -} +use crate::{log::LogIndex, receipt::Receipt}; pub mod columns { @@ -177,13 +54,6 @@ pub mod columns { pub struct BlockDeployedCodeHashes; } -// -// ColumnName trait. Define associated column family NAME -// -pub trait ColumnName { - const NAME: &'static str; -} - const BLOCKS_CF: &str = "blocks"; const TRANSACTIONS_CF: &str = "transactions"; const RECEIPTS_CF: &str = "receipts"; @@ -228,16 +98,16 @@ impl ColumnName for columns::BlockDeployedCodeHashes { const NAME: &'static str = BLOCK_DEPLOYED_CODES_CF; } -// -// Column trait. Define associated index type -// -pub trait Column { - type Index: Debug; - - fn key(index: &Self::Index) -> Vec; - - fn get_key(raw_key: Box<[u8]>) -> Self::Index; -} +pub const COLUMN_NAMES: [&'static str; 8] = [ + columns::Blocks::NAME, + columns::Transactions::NAME, + columns::Receipts::NAME, + columns::BlockMap::NAME, + columns::LatestBlockNumber::NAME, + columns::AddressLogsMap::NAME, + columns::AddressCodeMap::NAME, + columns::BlockDeployedCodeHashes::NAME, +]; // // Column trait impl @@ -250,8 +120,8 @@ impl Column for columns::Transactions { index.as_bytes().to_vec() } - fn get_key(raw_key: Box<[u8]>) -> Self::Index { - Self::Index::from_slice(&raw_key) + fn get_key(raw_key: Box<[u8]>) -> Result { + Ok(Self::Index::from_slice(&raw_key)) } } @@ -264,8 +134,8 @@ impl Column for columns::Blocks { bytes.to_vec() } - fn get_key(raw_key: Box<[u8]>) -> Self::Index { - Self::Index::from(&*raw_key) + fn get_key(raw_key: Box<[u8]>) -> Result { + Ok(Self::Index::from(&*raw_key)) } } @@ -276,8 +146,8 @@ impl Column for columns::Receipts { index.to_fixed_bytes().to_vec() } - fn get_key(raw_key: Box<[u8]>) -> Self::Index { - Self::Index::from_slice(&raw_key) + fn get_key(raw_key: Box<[u8]>) -> Result { + Ok(Self::Index::from_slice(&raw_key)) } } @@ -288,8 +158,8 @@ impl Column for columns::BlockMap { index.to_fixed_bytes().to_vec() } - fn get_key(raw_key: Box<[u8]>) -> Self::Index { - Self::Index::from_slice(&raw_key) + fn get_key(raw_key: Box<[u8]>) -> Result { + Ok(Self::Index::from_slice(&raw_key)) } } @@ -300,8 +170,8 @@ impl Column for columns::LatestBlockNumber { b"latest".to_vec() } - fn get_key(_raw_key: Box<[u8]>) -> Self::Index { - "latest" + fn get_key(_raw_key: Box<[u8]>) -> Result { + Ok("latest") } } @@ -314,8 +184,8 @@ impl Column for columns::AddressLogsMap { bytes.to_vec() } - fn get_key(raw_key: Box<[u8]>) -> Self::Index { - Self::Index::from(&*raw_key) + fn get_key(raw_key: Box<[u8]>) -> Result { + Ok(Self::Index::from(&*raw_key)) } } @@ -329,10 +199,10 @@ impl Column for columns::AddressCodeMap { bytes } - fn get_key(raw_key: Box<[u8]>) -> Self::Index { + fn get_key(raw_key: Box<[u8]>) -> Result { let address = H160::from_slice(&raw_key[..20]); let code_hash = H256::from_slice(&raw_key[20..]); - (address, code_hash) + Ok((address, code_hash)) } } @@ -349,24 +219,17 @@ impl Column for columns::BlockDeployedCodeHashes { bytes } - fn get_key(raw_key: Box<[u8]>) -> Self::Index { + fn get_key(raw_key: Box<[u8]>) -> Result { let u256_bytes = &raw_key[0..32]; let h160_bytes = &raw_key[32..52]; let u256 = U256::from_big_endian(u256_bytes); let h160 = H160::from_slice(h160_bytes); - (u256, h160) + Ok((u256, h160)) } } -// -// TypedColumn trait. Define associated value type -// -pub trait TypedColumn: Column { - type Type: Serialize + DeserializeOwned + Debug; -} - // // TypedColumn impl // @@ -401,49 +264,3 @@ impl TypedColumn for columns::AddressCodeMap { impl TypedColumn for columns::BlockDeployedCodeHashes { type Type = H256; } - -impl LedgerColumn -where - C: TypedColumn + ColumnName, -{ - pub fn get(&self, key: &C::Index) -> Result> { - if let Some(serialized_value) = self.get_bytes(key)? { - let value = bincode::deserialize(&serialized_value)?; - - Ok(Some(value)) - } else { - Ok(None) - } - } - - pub fn put(&self, key: &C::Index, value: &C::Type) -> Result<()> { - let serialized_value = bincode::serialize(value)?; - - self.put_bytes(key, &serialized_value) - } - - pub fn delete(&self, key: &C::Index) -> Result<()> { - self.backend.delete_cf(self.handle(), &C::key(key)) - } - - pub fn iter( - &self, - from: Option, - limit: usize, - ) -> impl Iterator + '_ { - let index = from.as_ref().map(|i| C::key(i)).unwrap_or_default(); - let iterator_mode = from.map_or(IteratorMode::Start, |_| { - IteratorMode::From(&index, rocksdb::Direction::Forward) - }); - self.backend - .iterator_cf::(self.handle(), iterator_mode) - .filter_map(|k| { - k.ok().and_then(|(k, v)| { - let value = bincode::deserialize(&v).ok()?; - let key = C::get_key(k); - Some((key, value)) - }) - }) - .take(limit) - } -} diff --git a/lib/ain-macros/src/lib.rs b/lib/ain-macros/src/lib.rs index 2cb2b42c6fc..a219dd81217 100644 --- a/lib/ain-macros/src/lib.rs +++ b/lib/ain-macros/src/lib.rs @@ -2,7 +2,7 @@ extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; -use syn::{parse_macro_input, ItemFn, ReturnType, Type}; +use syn::{parse_macro_input, Attribute, DeriveInput, ItemFn, LitStr, ReturnType, Type}; #[proc_macro_attribute] pub fn ffi_fallible(_attr: TokenStream, item: TokenStream) -> TokenStream { @@ -53,3 +53,81 @@ pub fn ffi_fallible(_attr: TokenStream, item: TokenStream) -> TokenStream { TokenStream::from(expanded) } + +fn parse_repository_attr(attr: &Attribute) -> syn::Result<(String, String, String)> { + let mut key_type = None; + let mut value_type = None; + let mut column_type = None; + + attr.parse_nested_meta(|meta| { + if meta.path.is_ident("K") { + let val = meta.value()?; + let s: LitStr = val.parse()?; + key_type = Some(s); + } + if meta.path.is_ident("V") { + let val = meta.value()?; + let s: LitStr = val.parse()?; + value_type = Some(s); + } + if meta.path.is_ident("Column") { + let val = meta.value()?; + let s: LitStr = val.parse()?; + column_type = Some(s); + } + Ok(()) + })?; + + Ok(( + key_type.expect("Missing attribute 'K'").value(), + value_type.expect("Missing attribute 'V'").value(), + column_type.expect("Missing attribute 'column'").value(), + )) +} + +#[proc_macro_derive(Repository, attributes(repository))] +pub fn repository_derive(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let name = &input.ident; // Struct name + + let mut key_type_str = String::new(); + let mut value_type_str = String::new(); + let mut column_type_str = String::new(); + + for attr in &input.attrs { + if attr.path().is_ident("repository") { + let (key, value, column) = + parse_repository_attr(attr).expect("Error parsing 'repository' attribute"); + key_type_str = key; + value_type_str = value; + column_type_str = column; + } + } + + let key_type_ident = syn::Ident::new(&key_type_str, proc_macro2::Span::call_site()); + let value_type_ident = syn::Ident::new(&value_type_str, proc_macro2::Span::call_site()); + let column_type_ident = syn::Ident::new(&column_type_str, proc_macro2::Span::call_site()); + println!("column_type_ident : {:?}", column_type_ident); + // Generate the implementation + let expanded = quote! { + impl RepositoryOps<#key_type_ident, #value_type_ident> for #name { + fn get(&self, id: #key_type_ident) -> Result> { + Ok(self.store.get::(id)?) + } + + fn put(&self, id: &#key_type_ident, item: &#value_type_ident) -> Result<()> { + Ok(self.store.put::(id, item)?) + } + + fn delete(&self, id: &#key_type_ident) -> Result<()> { + Ok(self.store.delete::(id)?) + } + + fn list(&self, from: Option<#key_type_ident>, limit: usize) -> Result> { + Ok(self.store.list::(from, limit)?) + } + } + }; + + TokenStream::from(expanded) +} diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index aadce6cb3de..4d689ac674e 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -9,6 +9,8 @@ debug = true [dependencies] ain-cpp-imports.workspace = true +ain-db.workspace = true +ain-macros.workspace = true axum.workspace = true hyper.workspace = true @@ -35,3 +37,5 @@ tempfile = "3.8.1" anyhow.workspace = true chrono = "0.4.31" cached.workspace = true +lazy_static.workspace = true +bincode.workspace = true diff --git a/lib/ain-ocean/src/api/masternode.rs b/lib/ain-ocean/src/api/masternode.rs index f0b0408e63b..737f0b2d5b8 100644 --- a/lib/ain-ocean/src/api/masternode.rs +++ b/lib/ain-ocean/src/api/masternode.rs @@ -3,16 +3,121 @@ use axum::{ routing::get, Json, Router, }; +use serde::{Deserialize, Serialize}; use crate::{ api_paged_response::ApiPagedResponse, api_query::PaginationQuery, error::OceanResult, - model::masternode::MasternodeData, + model::Masternode, repository::RepositoryOps, SERVICES, }; +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum MasternodeState { + PreEnabled, + Enabled, + PreResigned, + Resigned, + PreBanned, + Banned, + #[default] + Unknown, +} + +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +pub struct MasternodeOwner { + pub address: String, +} + +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +pub struct MasternodeOperator { + pub address: String, +} + +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +pub struct MasternodeCreation { + pub height: u32, +} + +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +pub struct MasternodeResign { + pub tx: String, + pub height: i32, +} + +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +#[serde(rename_all = "camelCase")] +pub struct MasternodeData { + pub id: String, + pub sort: String, + pub state: MasternodeState, + pub minted_blocks: i32, + pub owner: MasternodeOwner, + pub operator: MasternodeOperator, + pub creation: MasternodeCreation, + pub resign: Option, + pub timelock: u16, +} + +impl From for MasternodeData { + fn from(v: Masternode) -> Self { + MasternodeData { + id: v.id, + sort: v.sort, + state: MasternodeState::default(), // TODO Handle mn state + minted_blocks: v.minted_blocks, + owner: MasternodeOwner { + address: v.owner_address, + }, + operator: MasternodeOperator { + address: v.operator_address, + }, + creation: MasternodeCreation { + height: v.creation_height, + }, + resign: v.resign_tx.map(|tx| MasternodeResign { + tx, + height: v.resign_height, + }), + timelock: v.timelock, + } + } +} + async fn list_masternodes( Query(query): Query, ) -> OceanResult>> { - let masternodes = vec![MasternodeData::new("0")]; + let next = query + .next + .map(|q| { + let parts = q.split('-').collect::>(); + if parts.len() != 2 { + return Err("Invalid query format"); + } + + let height = parts[0].parse::().map_err(|_| "Invalid height")?; + let txno = parts[1].parse::().map_err(|_| "Invalid txno")?; + + Ok((height, txno)) + }) + .transpose()?; + + let masternodes = SERVICES + .masternode + .by_height + .list(next, query.size)? + .iter() + .map(|(_, mn_id)| { + let id: bitcoin::Txid = mn_id.parse()?; + let mn = SERVICES + .masternode + .by_id + .get(id)? + .ok_or("Missing masternode index")?; + + Ok(mn.into()) + }) + .collect::>>()?; + Ok(Json(ApiPagedResponse::of( masternodes, query.size, @@ -20,8 +125,13 @@ async fn list_masternodes( ))) } -async fn get_masternode(Path(masternode_id): Path) -> OceanResult> { - Ok(Json(MasternodeData::new(&masternode_id))) +async fn get_masternode( + Path(masternode_id): Path, +) -> OceanResult>> { + let id: bitcoin::Txid = masternode_id.parse()?; + let mn = SERVICES.masternode.by_id.get(id)?.map(Into::into); + + Ok(Json(mn)) } pub fn router() -> Router { diff --git a/lib/ain-ocean/src/data_acces/block.rs b/lib/ain-ocean/src/data_acces/block.rs deleted file mode 100644 index 8b4fd1a32ad..00000000000 --- a/lib/ain-ocean/src/data_acces/block.rs +++ /dev/null @@ -1,171 +0,0 @@ -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::block::Block, -}; - -use anyhow::{anyhow, Result}; -use rocksdb::IteratorMode; -use std::convert::TryInto; - -#[derive(Debug)] -pub struct BlockDb { - pub db: RocksDB, -} - -impl BlockDb { - pub async fn get_by_hash(&self, hash: String) -> Result> { - let number = match self.db.get("block_map", hash.as_bytes()) { - Ok(Some(value)) => { - // Convert the stored bytes to a block number - let block_number_bytes: [u8; 4] = match value.try_into() { - Ok(bytes) => bytes, - Err(e) => { - return Err(anyhow!("Error converting bytes to block number: {:?}", e)) - } - }; - let block_number = i32::from_be_bytes(block_number_bytes); - Some(block_number) - } - Ok(None) => None, - Err(e) => return Err(anyhow!("Error retrieving block number: {:?}", e)), - }; - - if let Some(block_number) = number { - let block_key = block_number.to_be_bytes(); - match self.db.get("block", &block_key) { - Ok(Some(value)) => { - let block: Block = serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; - Ok(Some(block)) - } - Ok(None) => Ok(None), - Err(e) => Err(anyhow!(e)), - } - } else { - Ok(None) - } - } - - pub async fn get_by_height(&self, height: i32) -> Result> { - match self.db.get("block", &height.to_be_bytes()) { - Ok(Some(value)) => { - let block: Block = serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; - Ok(Some(block)) - } - Ok(None) => Ok(None), - Err(e) => Err(anyhow!(e)), - } - } - - pub async fn get_highest(&self) -> Result> { - // Retrieve the latest block height - let latest_height_bytes = match self.db.get("latest_block_height", b"latest_block_height") { - Ok(Some(value)) => value, - Ok(None) => return Ok(None), // No latest block height set - Err(e) => return Err(anyhow!(e)), - }; - - // Convert the latest height bytes back to an integer - let latest_height = i32::from_be_bytes( - latest_height_bytes - .as_slice() - .try_into() - .map_err(|_| anyhow!("Byte length mismatch for latest height"))?, - ); - - // Retrieve the block with the latest height - match self.db.get("block", &latest_height.to_be_bytes()) { - Ok(Some(value)) => { - let block: Block = serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; - Ok(Some(block)) - } - Ok(None) => Ok(None), // No block found for the latest height - Err(e) => Err(anyhow!(e)), - } - } - - pub async fn query_by_height( - &self, - limit: i32, - lt: i32, - sort_order: SortOrder, - ) -> Result> { - let mut blocks: Vec = Vec::new(); - - let iterator = self.db.iterator("block", IteratorMode::End)?; - let collected_blocks: Vec<_> = iterator.collect(); - - for result in collected_blocks.into_iter().rev() { - let (key, value) = match result { - Ok((key, value)) => (key, value), - Err(err) => return Err(anyhow!("Error during iteration: {}", err)), - }; - - let block: Block = serde_json::from_slice(&value)?; - - if block.height < lt { - blocks.push(block); - - if blocks.len() == limit as usize { - break; - } - } - } - - // Sort blocks based on the specified sort order - match sort_order { - SortOrder::Ascending => blocks.sort_by(|a, b| a.height.cmp(&b.height)), - SortOrder::Descending => blocks.sort_by(|a, b| b.height.cmp(&a.height)), - } - - Ok(blocks) - } - - pub async fn put_block(&self, block: Block) -> Result<()> { - match serde_json::to_string(&block) { - Ok(value) => { - let block_number = block.height; - self.db - .put("block", &block_number.to_be_bytes(), value.as_bytes())?; - let block_map_key = block.hash.as_bytes(); - self.db - .put("block_map", block_map_key, &block_number.to_be_bytes())?; - self.db - .delete("latest_block_height", b"latest_block_height")?; - self.db.put( - "latest_block_height", - b"latest_block_height", - &block_number.to_be_bytes(), - )?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete_block(&self, hash: String) -> Result<()> { - let number = match self.db.get("block_map", hash.as_bytes()) { - Ok(Some(value)) => { - // Convert the stored bytes to a block number - let block_number_bytes: [u8; 4] = match value.try_into() { - Ok(bytes) => bytes, - Err(e) => { - return Err(anyhow!("Error converting bytes to block number: {:?}", e)) - } - }; - let block_number = i32::from_be_bytes(block_number_bytes); - Some(block_number) - } - Ok(None) => None, - Err(e) => return Err(anyhow!("Error retrieving block number: {:?}", e)), - }; - - if let Some(block_number) = number { - let block_key = block_number.to_be_bytes(); - match self.db.delete("block", &block_key) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } else { - Ok(()) - } - } -} diff --git a/lib/ain-ocean/src/data_acces/masternode.rs b/lib/ain-ocean/src/data_acces/masternode.rs deleted file mode 100644 index cdf54f8d6fc..00000000000 --- a/lib/ain-ocean/src/data_acces/masternode.rs +++ /dev/null @@ -1,74 +0,0 @@ -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::masternode::Masternode, -}; -use anyhow::{anyhow, Result}; -use rocksdb::IteratorMode; -use serde_json; - -pub struct MasterNodeDB { - pub db: RocksDB, -} - -impl MasterNodeDB { - pub async fn query( - &self, - limit: i32, - lt: u32, - sort_order: SortOrder, - ) -> Result> { - let iter_mode: IteratorMode = sort_order.into(); - let master_node: Result> = self - .db - .iterator("masternode", iter_mode)? - .into_iter() - .take(limit as usize) - .map(|result| { - result - .map_err(|e| { - anyhow!("Error during iteration: {}", e) - .context("error master_node query error") - }) - .and_then(|(_key, value)| { - let stats: Masternode = serde_json::from_slice(&value)?; - if stats.block.height < lt { - Ok(stats) - } else { - Err(anyhow!("Value is not less than lt") - .context("Contextual error message")) - } - }) - }) - .collect(); - - master_node.and_then(|result| Ok(result)) - } - pub async fn get(&self, id: String) -> Result> { - match self.db.get("masternode", id.as_bytes()) { - Ok(Some(value)) => { - let master_node: Masternode = - serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; - Ok(Some(master_node)) - } - Ok(None) => Ok(None), - Err(e) => Err(anyhow!(e)), - } - } - pub async fn store(&self, stats: Masternode) -> Result<()> { - match serde_json::to_string(&stats) { - Ok(value) => { - let key = stats.id.clone(); - self.db - .put("masternode", key.as_bytes(), value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, id: String) -> Result<()> { - match self.db.delete("masternode", id.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/masternode_stats.rs b/lib/ain-ocean/src/data_acces/masternode_stats.rs deleted file mode 100644 index 4cb7ed20f76..00000000000 --- a/lib/ain-ocean/src/data_acces/masternode_stats.rs +++ /dev/null @@ -1,110 +0,0 @@ -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::masternode_stats::MasternodeStats, -}; -use anyhow::Context; -use anyhow::{anyhow, Result}; -use rocksdb::IteratorMode; -#[derive(Debug)] -pub struct MasterStatsDb { - pub db: RocksDB, -} -impl MasterStatsDb { - pub async fn get_latest(&self) -> Result> { - let latest_height_bytes = match self - .db - .get("masternode_block_height", b"master_block_height") - { - Ok(Some(value)) => value, - Ok(None) => return Ok(None), // No latest block height set - Err(e) => return Err(anyhow!(e)), - }; - - // Convert the latest height bytes back to an integer - let latest_height = i32::from_be_bytes( - latest_height_bytes - .as_slice() - .try_into() - .map_err(|_| anyhow!("Byte length mismatch for latest height"))?, - ); - - // Retrieve the block with the latest height - match self.db.get("block", &latest_height.to_be_bytes()) { - Ok(Some(value)) => { - let block: MasternodeStats = - serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; - Ok(Some(block)) - } - Ok(None) => Ok(None), // No block found for the latest height - Err(e) => Err(anyhow!(e)), - } - } - - pub async fn query( - &self, - limit: i32, - lt: i32, - sort_order: SortOrder, - ) -> Result> { - let iter_mode: IteratorMode = sort_order.into(); - let master_node: Result> = self - .db - .iterator("masternode_stats", iter_mode)? - .into_iter() - .take(limit as usize) - .map(|result| { - result - .map_err(|e| { - anyhow!("Error during iteration: {}", e).context("Contextual error message") - }) - .and_then(|(_key, value)| { - let stats: MasternodeStats = serde_json::from_slice(&value)?; - if stats.block.height < lt { - Ok(stats) - } else { - Err(anyhow!("Value is not less than lt") - .context("Contextual error message")) - } - }) - }) - .collect(); - Ok(master_node?) - } - - pub async fn get(&self, height: i32) -> Result> { - let bytes: &[u8] = &height.to_be_bytes(); - match self.db.get("masternode_stats", bytes) { - Ok(Some(value)) => { - let master_states: MasternodeStats = - serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; - Ok(Some(master_states)) - } - Ok(None) => Ok(None), - Err(e) => Err(anyhow!(e)), - } - } - pub async fn store(&self, stats: MasternodeStats) -> Result<()> { - match serde_json::to_string(&stats) { - Ok(value) => { - let key = stats.block.height.clone(); - let height: &[u8] = &key.to_be_bytes(); - self.db.put("masternode_stats", height, value.as_bytes())?; - self.db - .put("masternode_map", stats.block.hash.as_bytes(), height)?; - self.db - .delete("masternode_block_height", b"master_block_height")?; - self.db - .put("masternode_block_height", b"master_block_height", height)?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, height: i32) -> Result<()> { - let bytes: &[u8] = &height.to_be_bytes(); - match self.db.delete("masternode_stats", bytes) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/mod.rs b/lib/ain-ocean/src/data_acces/mod.rs deleted file mode 100644 index 426541e79e2..00000000000 --- a/lib/ain-ocean/src/data_acces/mod.rs +++ /dev/null @@ -1,22 +0,0 @@ -pub mod block; -pub mod masternode; -pub mod masternode_stats; -pub mod oracle; -pub mod oracle_price_active; -pub mod oracle_price_aggregated; -pub mod oracle_price_aggregated_interval; -pub mod oracle_price_feed; -pub mod oracle_token_currency; -pub mod order_history; -pub mod pool_swap; -pub mod pool_swap_aggregated; -pub mod price_ticker; -pub mod raw_block; -pub mod script_activity; -pub mod script_aggregation; -pub mod script_unspent; -pub mod test; -pub mod transaction; -pub mod transaction_vin; -pub mod transaction_vout; -pub mod vault_auction_batch_history; diff --git a/lib/ain-ocean/src/data_acces/oracle.rs b/lib/ain-ocean/src/data_acces/oracle.rs deleted file mode 100644 index e106b94c0ce..00000000000 --- a/lib/ain-ocean/src/data_acces/oracle.rs +++ /dev/null @@ -1,73 +0,0 @@ -use anyhow::{anyhow, Error, Result}; -use rocksdb::IteratorMode; -use serde::{Deserialize, Serialize}; -use serde_json; - -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::oracle::Oracle, -}; - -pub struct OracleDb { - pub db: RocksDB, -} - -impl OracleDb { - pub async fn query( - &self, - limit: i32, - lt: String, - sort_order: SortOrder, - ) -> Result> { - let iterator = self.db.iterator("oracle", IteratorMode::End)?; - let mut oracles: Vec = Vec::new(); - let collected_items: Vec<_> = iterator.collect(); - - for result in collected_items.into_iter().rev() { - let value = match result { - Ok((_, value)) => value, - Err(err) => return Err(anyhow!("Error during iteration: {}", err)), - }; - - let oracle: Oracle = serde_json::from_slice(&value)?; - oracles.push(oracle); - if oracles.len() as i32 >= limit { - break; - } - } - - match sort_order { - SortOrder::Ascending => oracles.sort_by(|a, b| a.id.cmp(&b.id)), - SortOrder::Descending => oracles.sort_by(|a, b| b.id.cmp(&a.id)), - } - - Ok(oracles) - } - - pub async fn store(&self, oracle: Oracle) -> Result<()> { - match serde_json::to_string(&oracle) { - Ok(value) => { - let key = oracle.id.clone(); - self.db.put("oracle", key.as_bytes(), value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn get(&self, id: String) -> Result> { - match self.db.get("oracle", id.as_bytes()) { - Ok(Some(value)) => { - let oracle: Oracle = serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; - Ok(Some(oracle)) - } - Ok(None) => Ok(None), - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, id: String) -> Result<()> { - match self.db.delete("oracle", id.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/oracle_price_active.rs b/lib/ain-ocean/src/data_acces/oracle_price_active.rs deleted file mode 100644 index aa3a08a1141..00000000000 --- a/lib/ain-ocean/src/data_acces/oracle_price_active.rs +++ /dev/null @@ -1,67 +0,0 @@ -use crate::model::oracle_price_feed::OraclePriceFeed; -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::oracle_price_active::OraclePriceActive, -}; -use anyhow::{anyhow, Result}; -use rocksdb::IteratorMode; - -pub struct OraclePriceActiveDb { - pub db: RocksDB, -} - -impl OraclePriceActiveDb { - pub async fn query( - &self, - oracle_id: String, - limit: i32, - lt: String, - sort_order: SortOrder, - ) -> Result> { - let iterator = self.db.iterator("oracle_price_active", IteratorMode::End)?; - let mut oracle_price_feed: Vec = Vec::new(); - let collected_blocks: Vec<_> = iterator.collect(); - - for result in collected_blocks.into_iter().rev() { - let (key, value) = match result { - Ok((key, value)) => (key, value), - Err(err) => return Err(anyhow!("Error during iteration: {}", err)), - }; - - let oracle: OraclePriceActive = serde_json::from_slice(&value)?; - if oracle.key == oracle_id { - oracle_price_feed.push(oracle); - if oracle_price_feed.len() as i32 >= limit { - break; - } - } - } - - // Sort blocks based on the specified sort order - match sort_order { - SortOrder::Ascending => { - oracle_price_feed.sort_by(|a: &OraclePriceActive, b| a.id.cmp(&b.id)) - } - SortOrder::Descending => oracle_price_feed.sort_by(|a, b| b.id.cmp(&a.id)), - } - - Ok(oracle_price_feed) - } - pub async fn put(&self, oracle_price_feed: OraclePriceActive) -> Result<()> { - match serde_json::to_string(&oracle_price_feed) { - Ok(value) => { - let key = oracle_price_feed.id.clone(); - self.db - .put("oracle_price_active", key.as_bytes(), value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, id: String) -> Result<()> { - match self.db.delete("oracle_price_active", id.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/oracle_price_aggregated.rs b/lib/ain-ocean/src/data_acces/oracle_price_aggregated.rs deleted file mode 100644 index 182cdea9c56..00000000000 --- a/lib/ain-ocean/src/data_acces/oracle_price_aggregated.rs +++ /dev/null @@ -1,74 +0,0 @@ -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::oracle_price_aggregated::OraclePriceAggregated, -}; -use anyhow::{anyhow, Result}; -use rocksdb::IteratorMode; - -pub struct OraclePriceAggrigatedDb { - pub db: RocksDB, -} - -impl OraclePriceAggrigatedDb { - pub async fn query( - &self, - oracle_key: String, - limit: i32, - lt: String, - sort_order: SortOrder, - ) -> Result> { - let iterator = self - .db - .iterator("oracle_price_aggregated", IteratorMode::End)?; - let mut oracle_pa: Vec = Vec::new(); - let collected_blocks: Vec<_> = iterator.collect(); - - for result in collected_blocks.into_iter().rev() { - let (key, value) = match result { - Ok((key, value)) => (key, value), - Err(err) => return Err(anyhow!("Error during iteration: {}", err)), - }; - - let oracle: OraclePriceAggregated = serde_json::from_slice(&value)?; - if oracle.key == oracle_key { - oracle_pa.push(oracle); - if oracle_pa.len() as i32 >= limit { - break; - } - } - } - - // Sort blocks based on the specified sort order - match sort_order { - SortOrder::Ascending => { - oracle_pa.sort_by(|a: &OraclePriceAggregated, b| a.id.cmp(&b.id)) - } - SortOrder::Descending => oracle_pa.sort_by(|a, b| b.id.cmp(&a.id)), - } - - Ok(oracle_pa) - } - pub async fn put(&self, oracle: OraclePriceAggregated) -> Result<()> { - match serde_json::to_string(&oracle) { - Ok(value) => { - let key = oracle.key.clone(); - self.db - .put("oracle_price_aggregated", key.as_bytes(), value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn get(&self, key: String) -> Option { - match self.db.get("oracle_price_aggregated", key.as_bytes()) { - Ok(Some(value)) => serde_json::from_slice(&value).ok(), - _ => None, - } - } - pub async fn delete(&self, key: String) -> Result<()> { - match self.db.delete("oracle_price_aggregated", key.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/data_acces/oracle_price_aggregated_interval.rs deleted file mode 100644 index 4ff3977e85d..00000000000 --- a/lib/ain-ocean/src/data_acces/oracle_price_aggregated_interval.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, - model::oracle_price_aggregated_interval::OraclePriceAggregatedInterval, -}; -use anyhow::{anyhow, Result}; -use rocksdb::{ColumnFamilyDescriptor, IteratorMode, DB}; - -pub struct OraclePriceAggregatedIntervalDb { - pub db: RocksDB, -} - -impl OraclePriceAggregatedIntervalDb { - pub async fn query( - &self, - key: String, - limit: i32, - lt: String, - ) -> Result> { - let iterator = self - .db - .iterator("oracle_price_aggregated_interval", IteratorMode::End)?; - let mut oracle_prices: Vec = Vec::new(); - let collected_items: Vec<_> = iterator.collect(); - - for result in collected_items.into_iter().rev() { - let (key, value) = match result { - Ok((key, value)) => (key, value), - Err(err) => return Err(anyhow!("Error during iteration: {}", err)), - }; - - let oracle_price: OraclePriceAggregatedInterval = serde_json::from_slice(&value)?; - - // Check if the id is less than 'lt' - if String::from_utf8(key.to_vec())? < lt { - oracle_prices.push(oracle_price); - - if oracle_prices.len() == limit as usize { - break; - } - } - } - - Ok(oracle_prices) - } - pub async fn put(&self, oracle: OraclePriceAggregatedInterval) -> Result<()> { - match serde_json::to_string(&oracle) { - Ok(value) => { - let key = oracle.id.clone(); - self.db.put( - "oracle_price_aggregated_interval", - key.as_bytes(), - value.as_bytes(), - )?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, id: String) -> Result<()> { - match self - .db - .delete("oracle_price_aggregated_interval", id.as_bytes()) - { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/oracle_price_feed.rs b/lib/ain-ocean/src/data_acces/oracle_price_feed.rs deleted file mode 100644 index 05cc2e90f01..00000000000 --- a/lib/ain-ocean/src/data_acces/oracle_price_feed.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::oracle_price_feed::OraclePriceFeed, -}; -use anyhow::{anyhow, Result}; -use rocksdb::IteratorMode; - -pub struct OraclePriceFeedDb { - pub db: RocksDB, -} - -impl OraclePriceFeedDb { - pub async fn query( - &self, - oracle_id: String, - limit: i32, - lt: String, - sort_order: SortOrder, - ) -> Result> { - let iterator = self.db.iterator("oracle_price_feed", IteratorMode::End)?; - let mut oracle_price_feed: Vec = Vec::new(); - let collected_blocks: Vec<_> = iterator.collect(); - - for result in collected_blocks.into_iter().rev() { - let (key, value) = match result { - Ok((key, value)) => (key, value), - Err(err) => return Err(anyhow!("Error during iteration: {}", err)), - }; - - let oracle: OraclePriceFeed = serde_json::from_slice(&value)?; - if oracle.key == oracle_id { - oracle_price_feed.push(oracle); - if oracle_price_feed.len() as i32 >= limit { - break; - } - } - } - - // Sort blocks based on the specified sort order - match sort_order { - SortOrder::Ascending => { - oracle_price_feed.sort_by(|a: &OraclePriceFeed, b| a.id.cmp(&b.id)) - } - SortOrder::Descending => oracle_price_feed.sort_by(|a, b| b.id.cmp(&a.id)), - } - - Ok(oracle_price_feed) - } - pub async fn put(&self, oracle_price_feed: OraclePriceFeed) -> Result<()> { - match serde_json::to_string(&oracle_price_feed) { - Ok(value) => { - let key = oracle_price_feed.id.clone(); - self.db - .put("oracle_price_feed", key.as_bytes(), value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, id: String) -> Result<()> { - match self.db.delete("oracle_price_feed", id.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/oracle_token_currency.rs b/lib/ain-ocean/src/data_acces/oracle_token_currency.rs deleted file mode 100644 index e66e7421599..00000000000 --- a/lib/ain-ocean/src/data_acces/oracle_token_currency.rs +++ /dev/null @@ -1,67 +0,0 @@ -use anyhow::{anyhow, Result}; -use rocksdb::IteratorMode; - -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::oracle_token_currency::OracleTokenCurrency, -}; - -pub struct OracleTokenCurrencyDb { - pub db: RocksDB, -} - -impl OracleTokenCurrencyDb { - pub async fn query( - &self, - oracle_id: String, - limit: i32, - lt: String, - sort_order: SortOrder, - ) -> Result> { - let iterator = self - .db - .iterator("oracle_token_currency", IteratorMode::End)?; - let mut oracle_tc: Vec = Vec::new(); - let collected_blocks: Vec<_> = iterator.collect(); - - for result in collected_blocks.into_iter().rev() { - let (key, value) = match result { - Ok((key, value)) => (key, value), - Err(err) => return Err(anyhow!("Error during iteration: {}", err)), - }; - - let oracle: OracleTokenCurrency = serde_json::from_slice(&value)?; - if oracle.key == oracle_id { - oracle_tc.push(oracle); - if oracle_tc.len() as i32 >= limit { - break; - } - } - } - - // Sort blocks based on the specified sort order - match sort_order { - SortOrder::Ascending => oracle_tc.sort_by(|a: &OracleTokenCurrency, b| a.id.cmp(&b.id)), - SortOrder::Descending => oracle_tc.sort_by(|a, b| b.id.cmp(&a.id)), - } - - Ok(oracle_tc) - } - pub async fn put(&self, oracle_token: OracleTokenCurrency) -> Result<()> { - match serde_json::to_string(&oracle_token) { - Ok(value) => { - let key = oracle_token.id.clone(); - self.db - .put("oracle_token_currency", key.as_bytes(), value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, id: String) -> Result<()> { - match self.db.delete("oracle_token_currency", id.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/order_history.rs b/lib/ain-ocean/src/data_acces/order_history.rs deleted file mode 100644 index 6f5fff45ba2..00000000000 --- a/lib/ain-ocean/src/data_acces/order_history.rs +++ /dev/null @@ -1,66 +0,0 @@ -use anyhow::{anyhow, Result}; -use rocksdb::IteratorMode; - -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::oracle_history::OracleHistory, -}; - -pub struct OracleHistoryDB { - pub db: RocksDB, -} - -impl OracleHistoryDB { - pub async fn query( - &self, - oracle_id: String, - limit: i32, - lt: String, - sort_order: SortOrder, - ) -> Result> { - let iterator = self.db.iterator("oracle_history", IteratorMode::End)?; - let mut oracle_history: Vec = Vec::new(); - let collected_blocks: Vec<_> = iterator.collect(); - - for result in collected_blocks.into_iter().rev() { - let (key, value) = match result { - Ok((key, value)) => (key, value), - Err(err) => return Err(anyhow!("Error during iteration: {}", err)), - }; - - let oracle: OracleHistory = serde_json::from_slice(&value)?; - if oracle.id == oracle_id { - oracle_history.push(oracle); - if oracle_history.len() as i32 >= limit { - break; - } - } - } - - // Sort blocks based on the specified sort order - match sort_order { - SortOrder::Ascending => oracle_history.sort_by(|a, b| a.oracle_id.cmp(&b.oracle_id)), - SortOrder::Descending => oracle_history.sort_by(|a, b| b.oracle_id.cmp(&a.oracle_id)), - } - - Ok(oracle_history) - } - - pub async fn store(&self, oracle_history: OracleHistory) -> Result<()> { - match serde_json::to_string(&oracle_history) { - Ok(value) => { - let key = oracle_history.oracle_id.clone(); - self.db - .put("oracle_history", key.as_bytes(), value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, oracle_id: String) -> Result<()> { - match self.db.delete("oracle_history", oracle_id.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/pool_swap.rs b/lib/ain-ocean/src/data_acces/pool_swap.rs deleted file mode 100644 index 25e857d4bfb..00000000000 --- a/lib/ain-ocean/src/data_acces/pool_swap.rs +++ /dev/null @@ -1,64 +0,0 @@ -use anyhow::{anyhow, Result}; -use rocksdb::IteratorMode; - -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::poolswap::PoolSwap, -}; - -pub struct PoolSwapDb { - pub db: RocksDB, -} - -impl PoolSwapDb { - pub async fn query( - &self, - id: String, - limit: i32, - lt: String, - sort_order: SortOrder, - ) -> Result> { - let iterator = self.db.iterator("pool_swap", IteratorMode::End)?; - let mut pool_vin: Vec = Vec::new(); - let collected_blocks: Vec<_> = iterator.collect(); - - for result in collected_blocks.into_iter().rev() { - let (key, value) = match result { - Ok((key, value)) => (key, value), - Err(err) => return Err(anyhow!("Error during iteration: {}", err)), - }; - - let vin: PoolSwap = serde_json::from_slice(&value)?; - if vin.id == id { - pool_vin.push(vin); - if pool_vin.len() as i32 >= limit { - break; - } - } - } - - // Sort blocks based on the specified sort order - match sort_order { - SortOrder::Ascending => pool_vin.sort_by(|a, b| a.txid.cmp(&b.txid)), - SortOrder::Descending => pool_vin.sort_by(|a, b| b.txid.cmp(&a.txid)), - } - - Ok(pool_vin) - } - pub async fn put(&self, swap: PoolSwap) -> Result<()> { - match serde_json::to_string(&swap) { - Ok(value) => { - let key = swap.id.clone(); - self.db.put("pool_swap", key.as_bytes(), value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, id: String) -> Result<()> { - match self.db.delete("pool_swap", id.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/pool_swap_aggregated.rs b/lib/ain-ocean/src/data_acces/pool_swap_aggregated.rs deleted file mode 100644 index 1af6936a46f..00000000000 --- a/lib/ain-ocean/src/data_acces/pool_swap_aggregated.rs +++ /dev/null @@ -1,78 +0,0 @@ -use anyhow::{anyhow, Result}; -use rocksdb::IteratorMode; - -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::poolswap_aggregated::PoolSwapAggregated, -}; - -pub struct PoolSwapAggregatedDb { - pub db: RocksDB, -} - -impl PoolSwapAggregatedDb { - pub async fn query( - &self, - id: String, - limit: i32, - lt: String, - sort_order: SortOrder, - ) -> Result<(Vec)> { - let iterator = self - .db - .iterator("pool_swap_aggregated", IteratorMode::End)?; - let mut pool_swap: Vec = Vec::new(); - let collected_blocks: Vec<_> = iterator.collect(); - - for result in collected_blocks.into_iter().rev() { - let (key, value) = match result { - Ok((key, value)) => (key, value), - Err(err) => return Err(anyhow!("Error during iteration: {}", err)), - }; - - let ps: PoolSwapAggregated = serde_json::from_slice(&value)?; - if ps.id == id { - pool_swap.push(ps); - if pool_swap.len() as i32 >= limit { - break; - } - } - } - - // Sort blocks based on the specified sort order - match sort_order { - SortOrder::Ascending => pool_swap.sort_by(|a, b| a.id.cmp(&b.id)), - SortOrder::Descending => pool_swap.sort_by(|a, b| b.id.cmp(&a.id)), - } - - Ok(pool_swap) - } - pub async fn put(&self, aggregated: PoolSwapAggregated) -> Result<()> { - match serde_json::to_string(&aggregated) { - Ok(value) => { - let key = aggregated.id.clone(); - self.db - .put("pool_swap_aggregated", key.as_bytes(), value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn get(&self, id: String) -> Result { - match self.db.get("pool_swap_aggregated", id.as_bytes()) { - Ok(Some(value)) => { - let pool_swap: PoolSwapAggregated = - serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; - Ok(pool_swap) - } - Ok(None) => Err(anyhow!("No data found for the given ID")), - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, id: String) -> Result<()> { - match self.db.delete("pool_swap_aggregated", id.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/price_ticker.rs b/lib/ain-ocean/src/data_acces/price_ticker.rs deleted file mode 100644 index e6491f888b5..00000000000 --- a/lib/ain-ocean/src/data_acces/price_ticker.rs +++ /dev/null @@ -1,72 +0,0 @@ -use anyhow::{anyhow, Result}; -use rocksdb::IteratorMode; - -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::price_ticker::PriceTicker, -}; - -pub struct price_ticker { - pub db: RocksDB, -} - -impl price_ticker { - pub async fn query( - &self, - limit: i32, - lt: String, - sort_order: SortOrder, - ) -> Result> { - let iterator = self.db.iterator("price_ticker", IteratorMode::End)?; - let mut pt: Vec = Vec::new(); - let collected_items: Vec<_> = iterator.collect(); - - for result in collected_items.into_iter().rev() { - let value = match result { - Ok((_, value)) => value, - Err(err) => return Err(anyhow!("Error during iteration: {}", err)), - }; - - let price_ticker: PriceTicker = serde_json::from_slice(&value)?; - pt.push(price_ticker); - if pt.len() as i32 >= limit { - break; - } - } - - match sort_order { - SortOrder::Ascending => pt.sort_by(|a, b| a.id.cmp(&b.id)), - SortOrder::Descending => pt.sort_by(|a, b| b.id.cmp(&a.id)), - } - - Ok(pt) - } - pub async fn get(&self, id: String) -> Result { - match self.db.get("price_ticker", id.as_bytes()) { - Ok(Some(value)) => { - let pool_swap: PriceTicker = - serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; - Ok(pool_swap) - } - Ok(None) => Err(anyhow!("No data found for the given ID")), - Err(e) => Err(anyhow!(e)), - } - } - pub async fn put(&self, price: PriceTicker) -> Result<()> { - match serde_json::to_string(&price) { - Ok(value) => { - let key = price.id.clone(); - self.db - .put("price_ticker", key.as_bytes(), value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, id: String) -> Result<()> { - match self.db.delete("price_ticker", id.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/raw_block.rs b/lib/ain-ocean/src/data_acces/raw_block.rs deleted file mode 100644 index 024222dcba4..00000000000 --- a/lib/ain-ocean/src/data_acces/raw_block.rs +++ /dev/null @@ -1,41 +0,0 @@ -use anyhow::{anyhow, Result}; - -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, - model::raw_block::RawBlock, -}; - -#[derive(Debug)] -pub struct RawBlockDb { - pub db: RocksDB, -} - -impl RawBlockDb { - pub async fn get(&self, hash: String) -> Result> { - match self.db.get("raw_block", hash.as_bytes()) { - Ok(Some(value)) => { - let trx: RawBlock = serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; - Ok(Some(trx)) - } - Ok(None) => Ok(None), - Err(e) => Err(anyhow!(e)), - } - } - - pub async fn store(&self, block: RawBlock) -> Result<()> { - match serde_json::to_string(&block) { - Ok(value) => { - let key = block.id.clone(); - self.db.put("raw_block", key.as_bytes(), value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, hash: String) -> Result<()> { - match self.db.delete("raw_block", hash.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/script_activity.rs b/lib/ain-ocean/src/data_acces/script_activity.rs deleted file mode 100644 index feeaa12abc9..00000000000 --- a/lib/ain-ocean/src/data_acces/script_activity.rs +++ /dev/null @@ -1,67 +0,0 @@ -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::script_activity::ScriptActivity, -}; -use anyhow::{anyhow, Result}; -use rocksdb::{Direction, IteratorMode}; -use serde_json; - -pub struct ScriptUnspentDB { - pub db: RocksDB, -} - -impl ScriptUnspentDB { - pub async fn query( - &self, - hid: String, - limit: i32, - lt: Option, - ) -> Result> { - let prefix = format!("script_activity_hid_sort:{}:", lt.unwrap_or_default()); - let iterator_result = self.db.iterator( - "script_activity", - IteratorMode::From(prefix.as_bytes(), Direction::Forward), - )?; - let mut results = Vec::new(); - for item in iterator_result { - match item { - Ok((key, value)) => { - let key_str = String::from_utf8_lossy(&key); - if !key_str.starts_with(&prefix) { - break; - } - - let script_unspent: ScriptActivity = serde_json::from_slice(&value)?; - - results.push(script_unspent); - - if results.len() >= limit as usize { - break; - } - } - Err(err) => { - eprintln!("Error iterating over the database: {:?}", err); - return Err(err.into()); - } - } - } - Ok(results) - } - pub async fn store(&self, unspent: ScriptActivity) -> Result<()> { - match serde_json::to_string(&unspent) { - Ok(value) => { - let key = unspent.hid.clone(); - self.db - .put("script_activity", key.as_bytes(), value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, hid: String) -> Result<()> { - match self.db.delete("script_activity", hid.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/script_aggregation.rs b/lib/ain-ocean/src/data_acces/script_aggregation.rs deleted file mode 100644 index 2f2788aaf5d..00000000000 --- a/lib/ain-ocean/src/data_acces/script_aggregation.rs +++ /dev/null @@ -1,93 +0,0 @@ -use anyhow::{anyhow, Result}; -use rocksdb::{Direction, IteratorMode}; -use serde_json; - -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::script_aggregation::ScriptAggregation, -}; - -pub struct ScriptAggretionDB { - pub db: RocksDB, -} - -impl ScriptAggretionDB { - pub async fn query( - &self, - hid: String, - limit: i32, - lt: String, - sort_order: SortOrder, - ) -> Result> { - let iterator = self.db.iterator( - "script_aggregation", - IteratorMode::From(lt.as_bytes(), Direction::Reverse), - )?; - - let mut script_aggre: Vec = Vec::new(); - - for item in iterator { - match item { - Ok((key, value)) => { - let key_str = String::from_utf8_lossy(&key); - - if !key_str.starts_with(&hid) { - break; - } - - let vout: ScriptAggregation = serde_json::from_slice(&value)?; - script_aggre.push(vout); - - if script_aggre.len() >= limit as usize { - break; - } - } - Err(err) => { - eprintln!("Error iterating over the database: {:?}", err); - return Err(err.into()); - } - } - } - - // Sorting based on the SortOrder - match sort_order { - SortOrder::Ascending => script_aggre.sort_by(|a, b| a.id.cmp(&b.id)), - SortOrder::Descending => script_aggre.sort_by(|a, b| b.id.cmp(&a.id)), - } - - Ok(script_aggre) - } - pub async fn store(&self, aggregation: ScriptAggregation) -> Result<()> { - match serde_json::to_string(&aggregation) { - Ok(value) => { - let key = aggregation.hid.clone(); - self.db - .put("script_aggregation", key.as_bytes(), value.as_bytes())?; - - let h = aggregation.block.height.clone(); - let height: &[u8] = &h.to_be_bytes(); - self.db - .put("script_aggregation_mapper", height, key.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn get(&self, hid: String) -> Result> { - match self.db.get("script_aggregation", hid.as_bytes()) { - Ok(Some(value)) => { - let oracle: ScriptAggregation = - serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; - Ok(Some(oracle)) - } - Ok(None) => Ok(None), - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, hid: String) -> Result<()> { - match self.db.delete("script_aggregation", hid.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/script_unspent.rs b/lib/ain-ocean/src/data_acces/script_unspent.rs deleted file mode 100644 index 5db7c88e066..00000000000 --- a/lib/ain-ocean/src/data_acces/script_unspent.rs +++ /dev/null @@ -1,68 +0,0 @@ -use anyhow::{anyhow, Error, Result}; -use rocksdb::{Direction, IteratorMode}; -use serde_json; - -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, - model::script_unspent::ScriptUnspent, -}; - -pub struct ScriptUnspentDB { - pub db: RocksDB, -} - -impl ScriptUnspentDB { - pub async fn query( - &self, - hid: String, - limit: i32, - gt: Option, - ) -> Result> { - let prefix = format!("script_unspent_hid_sort:{}:", gt.unwrap_or_default()); - let iterator_result = self.db.iterator( - "script_unspent", - IteratorMode::From(prefix.as_bytes(), Direction::Forward), - )?; - let mut results = Vec::new(); - for item in iterator_result { - match item { - Ok((key, value)) => { - let key_str = String::from_utf8_lossy(&key); - if !key_str.starts_with(&prefix) { - break; - } - - let script_unspent: ScriptUnspent = serde_json::from_slice(&value)?; - - results.push(script_unspent); - - if results.len() >= limit as usize { - break; - } - } - Err(err) => { - eprintln!("Error iterating over the database: {:?}", err); - return Err(err.into()); - } - } - } - Ok(results) - } - pub async fn store(&self, unspent: ScriptUnspent) -> Result<()> { - match serde_json::to_string(&unspent) { - Ok(value) => { - let key = unspent.hid.clone(); - self.db - .put("script_unspent", key.as_bytes(), value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, hid: String) -> Result<()> { - match self.db.delete("script_unspent", hid.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/data_acces/transaction.rs b/lib/ain-ocean/src/data_acces/transaction.rs deleted file mode 100644 index 487a954c4a6..00000000000 --- a/lib/ain-ocean/src/data_acces/transaction.rs +++ /dev/null @@ -1,91 +0,0 @@ -use anyhow::{anyhow, Result}; -use serde::{Deserialize, Serialize}; - -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, - model::transaction::Transaction, -}; - -#[derive(Debug)] -pub struct TransactionVinDb { - pub db: RocksDB, -} - -impl TransactionVinDb { - pub async fn get(&self, txid: String) -> Result> { - match self.db.get("transaction", txid.as_bytes()) { - Ok(Some(value)) => { - let trx: Transaction = serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; - Ok(Some(trx)) - } - Ok(None) => Ok(None), - Err(e) => Err(anyhow!(e)), - } - } - pub async fn store(&self, txn: Transaction) -> Result<()> { - let value = serde_json::to_string(&txn)?; - let txid_key = txn.txid.clone(); - self.db - .put("transaction", txid_key.as_bytes(), value.as_bytes())?; - - // Retrieve existing transaction IDs for the block hash, if any - let mut txn_ids = match self - .db - .get("transaction_mapper", txn.block.hash.as_bytes())? - { - Some(bytes) => serde_json::from_slice::>(&bytes)?, - None => vec![], - }; - - // Add the new transaction ID to the list - txn_ids.push(txn.txid); - let txn_ids_value = serde_json::to_string(&txn_ids)?; - self.db.put( - "transaction_mapper", - txn.block.hash.as_bytes(), - txn_ids_value.as_bytes(), - )?; - Ok(()) - } - pub async fn delete(&self, txid: String) -> Result<()> { - match self.db.delete("transaction", txid.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } - pub async fn query_by_block_hash( - &self, - hash: String, - limit: i32, - lt: i32, - ) -> Result> { - let mut transactions = Vec::new(); - - // Retrieve the transaction ID(s) associated with the block hash - match self.db.get("transaction_mapper", hash.as_bytes()) { - Ok(Some(txn_id_bytes)) => { - // Assuming one block hash maps to multiple transaction IDs - println!("the value in trx{:?}", txn_id_bytes); - let txn_ids: Vec = serde_json::from_slice::>(&txn_id_bytes)?; - - for txn_id in txn_ids.iter().take(limit as usize) { - // Retrieve the transaction details for each transaction ID - match self.db.get("transaction", txn_id.as_bytes()) { - Ok(Some(txn_bytes)) => { - let txn: Transaction = serde_json::from_slice(&txn_bytes)?; - transactions.push(txn); - } - Ok(None) => { - return Err(anyhow!("Transaction not found for ID: {}", txn_id)) - } - Err(e) => return Err(anyhow!("Database error: {}", e)), - } - } - } - Ok(None) => return Err(anyhow!("No transactions found for block hash: {}", hash)), - Err(e) => return Err(anyhow!("Database error: {}", e)), - } - - Ok(transactions) - } -} diff --git a/lib/ain-ocean/src/data_acces/transaction_vin.rs b/lib/ain-ocean/src/data_acces/transaction_vin.rs deleted file mode 100644 index 20b80f81093..00000000000 --- a/lib/ain-ocean/src/data_acces/transaction_vin.rs +++ /dev/null @@ -1,71 +0,0 @@ -use anyhow::{anyhow, Result}; -use rocksdb::IteratorMode; - -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::transaction_vin::TransactionVin, -}; - -#[derive(Debug)] -pub struct TransactionVinDb { - pub db: RocksDB, -} - -impl TransactionVinDb { - pub async fn store(&self, trx_vin: TransactionVin) -> Result<()> { - match serde_json::to_string(&trx_vin) { - Ok(value) => { - let key = trx_vin.id.clone(); - self.db - .put("transaction_vin", key.as_bytes(), value.as_bytes())?; - self.db.put( - "transaction_vin_mapper", - trx_vin.txid.as_bytes(), - trx_vin.id.as_bytes(), - )?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, id: String) -> Result<()> { - match self.db.delete("transaction_vin", id.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } - pub async fn query( - &self, - tx_id: String, - limit: i32, - lt: i32, - sort_order: SortOrder, - ) -> Result> { - let iterator = self.db.iterator("transaction_vin", IteratorMode::End)?; - let mut trx_vin: Vec = Vec::new(); - let collected_blocks: Vec<_> = iterator.collect(); - - for result in collected_blocks.into_iter().rev() { - let (key, value) = match result { - Ok((key, value)) => (key, value), - Err(err) => return Err(anyhow!("Error during iteration: {}", err)), - }; - - let vin: TransactionVin = serde_json::from_slice(&value)?; - if vin.txid == tx_id { - trx_vin.push(vin); - if trx_vin.len() as i32 >= limit { - break; - } - } - } - - // Sort blocks based on the specified sort order - match sort_order { - SortOrder::Ascending => trx_vin.sort_by(|a, b| a.txid.cmp(&b.txid)), - SortOrder::Descending => trx_vin.sort_by(|a, b| b.txid.cmp(&a.txid)), - } - - Ok(trx_vin) - } -} diff --git a/lib/ain-ocean/src/data_acces/transaction_vout.rs b/lib/ain-ocean/src/data_acces/transaction_vout.rs deleted file mode 100644 index aab89713d08..00000000000 --- a/lib/ain-ocean/src/data_acces/transaction_vout.rs +++ /dev/null @@ -1,82 +0,0 @@ -use anyhow::{anyhow, Result}; -use rocksdb::IteratorMode; - -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::transaction_vout::TransactionVout, -}; - -#[derive(Debug)] -pub struct TransactionVoutDb { - pub db: RocksDB, -} - -impl TransactionVoutDb { - pub async fn get(&self, tx_id: String, n: i64) -> Result> { - match self.db.get("transaction_vout", tx_id.as_bytes()) { - Ok(Some(value)) => { - let master_node: TransactionVout = - serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; - Ok(Some(master_node)) - } - Ok(None) => Ok(None), - Err(e) => Err(anyhow!(e)), - } - } - pub async fn store(&self, trx_out: TransactionVout) -> Result<()> { - let value = serde_json::to_string(&trx_out)?; - let key = trx_out.id.clone(); - self.db - .put("transaction_vout", key.as_bytes(), value.as_bytes())?; - - // Accumulate transaction vout IDs for each txid - let mut vout_ids = match self - .db - .get("transaction_vout_mapper", trx_out.txid.as_bytes())? - { - Some(bytes) => serde_json::from_slice::>(&bytes)?, - None => vec![], - }; - vout_ids.push(trx_out.id); - let vout_ids_value = serde_json::to_string(&vout_ids)?; - self.db.put( - "transaction_vout_mapper", - trx_out.txid.as_bytes(), - vout_ids_value.as_bytes(), - )?; - - Ok(()) - } - pub async fn delete(&self, trx_id: String) -> Result<()> { - match self.db.delete("transaction_vout", trx_id.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } - pub async fn query( - &self, - tx_id: String, - limit: i32, - lt: i32, - sort_order: SortOrder, - ) -> Result> { - let iterator = self.db.iterator("transaction_vout", IteratorMode::End)?; - let mut trx_vout: Vec = Vec::new(); - if let Some(bytes) = self.db.get("transaction_vout_mapper", tx_id.as_bytes())? { - let vout_ids: Vec = serde_json::from_slice(&bytes)?; - for vout_id in vout_ids.iter().take(limit as usize) { - if let Some(vout_bytes) = self.db.get("transaction_vout", vout_id.as_bytes())? { - let vout: TransactionVout = serde_json::from_slice(&vout_bytes)?; - trx_vout.push(vout); - } - } - } - - match sort_order { - SortOrder::Ascending => trx_vout.sort_by(|a, b| a.n.cmp(&b.n)), - SortOrder::Descending => trx_vout.sort_by(|a, b| b.n.cmp(&a.n)), - } - - Ok(trx_vout) - } -} diff --git a/lib/ain-ocean/src/data_acces/vault_auction_batch_history.rs b/lib/ain-ocean/src/data_acces/vault_auction_batch_history.rs deleted file mode 100644 index 1f91c9c20a4..00000000000 --- a/lib/ain-ocean/src/data_acces/vault_auction_batch_history.rs +++ /dev/null @@ -1,42 +0,0 @@ -use anyhow::{anyhow, Result}; -use serde_json; - -use crate::{ - database::db_manager::{ColumnFamilyOperations, RocksDB}, - model::vault_auction_batch_history::VaultAuctionBatchHistory, -}; - -pub struct VaultAuctionDB { - pub db: RocksDB, -} - -impl VaultAuctionDB { - pub async fn store(&self, auction: VaultAuctionBatchHistory) -> Result<()> { - match serde_json::to_string(&auction) { - Ok(value) => { - let key = auction.id.clone(); - self.db - .put("vault_auction_history", key.as_bytes(), value.as_bytes())?; - Ok(()) - } - Err(e) => Err(anyhow!(e)), - } - } - pub async fn get(&self, id: String) -> Result> { - match self.db.get("vault_auction_history", id.as_bytes()) { - Ok(Some(value)) => { - let oracle: VaultAuctionBatchHistory = - serde_json::from_slice(&value).map_err(|e| anyhow!(e))?; - Ok(Some(oracle)) - } - Ok(None) => Ok(None), - Err(e) => Err(anyhow!(e)), - } - } - pub async fn delete(&self, id: String) -> Result<()> { - match self.db.delete("vault_auction_history", id.as_bytes()) { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!(e)), - } - } -} diff --git a/lib/ain-ocean/src/database/config.rs b/lib/ain-ocean/src/database/config.rs deleted file mode 100644 index bcb21665287..00000000000 --- a/lib/ain-ocean/src/database/config.rs +++ /dev/null @@ -1,36 +0,0 @@ -use std::{env, fs, path::PathBuf}; - -use serde::{Deserialize, Serialize}; -use structopt::StructOpt; - -#[derive(Debug, Clone, Serialize, Deserialize, StructOpt)] -pub struct Config { - /// Path to the RocksDB database on the local file system. - #[structopt( - long = "rocksdb-path", - env = "ROCKSDB_PATH", - default_value = "rocksdb/data" - )] - pub rocksdb_path: String, -} -impl Default for Config { - fn default() -> Self { - let mut path = match env::var("HOME") { - Ok(val) => PathBuf::from(val), - Err(_) => panic!("Couldn't find a home directory"), - }; - path.push("rocksdb/data"); - if let Err(e) = fs::create_dir_all(&path) { - panic!("Failed to create default RocksDB path: {}", e); - } - - let path_str = match path.to_str() { - Some(p) => p, - None => panic!("Failed to convert path to string"), - }; - - Self { - rocksdb_path: path_str.to_string(), - } - } -} diff --git a/lib/ain-ocean/src/database/db_manager.rs b/lib/ain-ocean/src/database/db_manager.rs deleted file mode 100644 index 1c06b1901c8..00000000000 --- a/lib/ain-ocean/src/database/db_manager.rs +++ /dev/null @@ -1,298 +0,0 @@ -use std::{collections::HashSet, sync::Arc}; - -use anyhow::{anyhow, Result}; -use bitcoin::{ - blockdata::block::{Block, Header}, - consensus::encode::serialize, -}; -use rocksdb::{ColumnFamilyDescriptor, DBIterator, Direction, IteratorMode, Options, DB}; -use serde::{Deserialize, Serialize}; - -use crate::model::oracle::Oracle; - -#[derive(Debug)] -pub struct RocksDB { - db: Arc, - cfs: HashSet, -} - -#[derive(Debug, PartialEq, Clone)] -pub enum SortOrder { - Ascending, - Descending, -} - -pub trait ColumnFamilyOperations { - fn get(&self, cf_name: &str, key: &[u8]) -> Result>>; - fn put(&self, cf_name: &str, key: &[u8], value: &[u8]) -> Result<()>; - fn delete(&self, cf_name: &str, key: &[u8]) -> Result<()>; - fn get_total_row(&self) -> Result<()>; - fn iterator(&self, cf_name: &str, mode: IteratorMode) -> Result<(DBIterator)>; -} - -impl RocksDB { - pub fn new(db_path: &str) -> anyhow::Result { - let mut opts = Options::default(); - opts.create_if_missing(true); - opts.create_missing_column_families(true); - - let cf_names = [ - "default", - "block", - "masternode_stats", - "masternode", - "oracle_history", - "oracle_price_active", - "oracle_price_aggregated_interval", - "oracle_price_aggregated", - "oracle_price_feed", - "oracle_token_currency", - "oracle", - "pool_swap_aggregated", - "pool_swap", - "price_ticker", - "raw_block", - "script_activity", - "script_aggregation", - "script_unspent", - "transaction", - "transaction_vin", - "transaction_vout", - "vault_auction_history", - "pool_swap", - ]; - let mut cf_descriptors = vec![]; - - for cf_name in &cf_names { - let mut cf_opts = Options::default(); - cf_opts.set_max_write_buffer_number(16); - cf_descriptors.push(ColumnFamilyDescriptor::new(cf_name.to_string(), cf_opts)); - } - - let db = Arc::new(DB::open_cf_descriptors(&opts, db_path, cf_descriptors)?); - - // Keep names of the column families so you can look them up later - let cfs = cf_names - .iter() - .cloned() - .map(String::from) - .collect::>(); - - Ok(Self { db, cfs }) - } - - pub fn put_block(&self, block: &Block) -> anyhow::Result<()> { - // Serialize the header to a byte vector - let serialized_header = serialize(block); - // Convert the block hash to string (Assume it's a suitable key) - let key = block.block_hash().to_string(); - // Store the block header - self.put("block", key.as_bytes(), &serialized_header)?; - Ok(()) - } - - pub fn get_block(&self, key: &[u8]) -> anyhow::Result>> { - self.get("block", key) - } - - pub fn put_block_header(&self, header: &Header) -> anyhow::Result<()> { - // Serialize the header to a byte vector - let serialized_header = serialize(header); - // Convert the block hash to string (Assume it's a suitable key) - let key = header.block_hash().to_string(); - // Store the block header - self.put("block_header", key.as_bytes(), &serialized_header)?; - // Update the latest block hash - let latest_block_hash = header.block_hash().to_string(); - self.put_latest_block_hash( - "latest_block_hash", - b"latest_block_hash", - latest_block_hash.as_bytes(), - )?; - - Ok(()) - } - - pub fn get_block_header(&self, key: &[u8]) -> anyhow::Result>> { - self.get("block_header", key) - } - - pub fn put_latest_block_hash( - &self, - cf_name: &str, - key: &[u8], - value: &[u8], - ) -> anyhow::Result<()> { - if let Some(cf) = self.cfs.get(cf_name) { - let cf_handle = self - .db - .cf_handle(cf) - .ok_or_else(|| anyhow::anyhow!("Failed to get column family handle"))?; - // Key does not exist, proceed to store the new value - self.db - .put_cf(cf_handle, key, value) - .map_err(|_| anyhow::anyhow!("Failed to put key-value pair")) - } else { - // Log some diagnostic info here. - Err(anyhow::anyhow!("Invalid column family name")) - } - } - - pub fn count_entries_in_cf(&self, cf_name: &str) -> anyhow::Result { - if let Some(cf_name) = self.cfs.get(cf_name) { - let cf = self - .db - .cf_handle(cf_name) - .ok_or_else(|| anyhow::anyhow!("Could not get column family handle"))?; - let iter = self.db.iterator_cf(cf, IteratorMode::Start); - - let mut count: u64 = 0; - for _ in iter { - count += 1; - } - - Ok(count) - } else { - Err(anyhow::anyhow!("Invalid column family name")) - } - } - - pub fn get_latest_block_hash(&self) -> anyhow::Result> { - let _db_path = self.db.path(); - let cf_name = "latest_block_hash"; - let key = b"latest_block_hash"; - if let Some(cf_name) = self.cfs.get(cf_name) { - let cf = self - .db - .cf_handle(cf_name) - .ok_or_else(|| anyhow::anyhow!("Failed to get column family handle"))?; - - match self.db.get_cf(cf, key)? { - Some(value) => { - let value_str = String::from_utf8(value) - .map_err(|e| anyhow::anyhow!("Failed to convert to UTF-8: {}", e))?; - Ok(Some(value_str)) - } - None => Ok(None), - } - } else { - Err(anyhow::anyhow!("Invalid column family name")) - } - } - - //block_hash in block table - pub async fn block_hash_exists(&self, block_hash: &str) -> anyhow::Result { - let cf_name = "block"; - if let Some(cf_name) = self.cfs.get(cf_name) { - let cf = self - .db - .cf_handle(cf_name) - .ok_or_else(|| anyhow::anyhow!("Failed to get column family handle"))?; - - let key = block_hash.as_bytes(); - match self.db.get_cf(cf, key)? { - Some(_) => Ok(true), // Block hash exists in the "block" column family - None => Ok(false), // Block hash does not exist - } - } else { - Err(anyhow::anyhow!("Invalid column family name")) - } - } -} - -impl ColumnFamilyOperations for RocksDB { - fn get(&self, cf_name: &str, key: &[u8]) -> Result>> { - if let Some(cf_name) = self.cfs.get(cf_name) { - let cf = self - .db - .cf_handle(cf_name) - .expect("Should never fail if column family name is valid"); - let result = self.db.get_cf(cf, key)?; - Ok(result) - } else { - Err(anyhow!("Invalid column family name")) - } - } - - fn put(&self, cf_name: &str, key: &[u8], value: &[u8]) -> Result<()> { - if let Some(cf) = self.cfs.get(cf_name) { - let cf_handle = self - .db - .cf_handle(cf) - .ok_or_else(|| anyhow!("Failed to get column family handle"))?; - - // Check if the key already exists - if self.db.get_cf(cf_handle, key)?.is_none() { - self.db - .put_cf(cf_handle, key, value) - .map_err(|_| anyhow!("Failed to put key-value pair")) - } else { - Ok(()) - } - } else { - // Log some diagnostic info here. - Err(anyhow!("Invalid column family name")) - } - } - - fn delete(&self, cf_name: &str, key: &[u8]) -> Result<()> { - if let Some(cf_name) = self.cfs.get(cf_name) { - let cf = self - .db - .cf_handle(cf_name) - .expect("Should never fail if column family name is valid"); - self.db.delete_cf(cf, key)?; - Ok(()) - } else { - Err(anyhow!("Invalid column family name")) - } - } - - fn get_total_row(&self) -> anyhow::Result<()> { - let db_path = self.db.path(); - println!("{:?}", db_path); - - let block_header_cf = self - .db - .cf_handle("block_header") - .ok_or(anyhow::anyhow!("Column family 'block_header' not found"))?; - - let block_cf = self - .db - .cf_handle("block") - .ok_or(anyhow::anyhow!("Column family 'block' not found"))?; - - let mut block_header_count = 0; - let mut block_count = 0; - - for _ in self.db.iterator_cf(block_header_cf, IteratorMode::Start) { - block_header_count += 1; - } - - // Count rows in "block" column family - for _ in self.db.iterator_cf(block_cf, IteratorMode::Start) { - block_count += 1; - } - - println!("Total rows in 'block_header': {}", block_header_count); - println!("Total rows in 'block': {}", block_count); - Ok(()) - } - - fn iterator(&self, cf_name: &str, mode: IteratorMode) -> Result { - if let Some(cf_handle) = self.db.cf_handle(cf_name) { - Ok(self.db.iterator_cf(cf_handle, mode)) - } else { - Err(anyhow!("Column family not found")) - } - } -} - -impl<'a> From for IteratorMode<'a> { - fn from(sort_order: SortOrder) -> Self { - match sort_order { - SortOrder::Ascending => IteratorMode::Start, - SortOrder::Descending => IteratorMode::From(b"", Direction::Reverse), - } - } -} diff --git a/lib/ain-ocean/src/database/db_test.rs b/lib/ain-ocean/src/database/db_test.rs deleted file mode 100644 index 8131a626ed1..00000000000 --- a/lib/ain-ocean/src/database/db_test.rs +++ /dev/null @@ -1,180 +0,0 @@ -// // In your src/lib.rs or a dedicated module for RocksDB interaction - -// extern crate rocksdb; -// extern crate tempdir; -// use crate::database::db_manger::RocksDB; -// use bitcoin::blockdata::block::Header; -// use bitcoin::blockdata::block::Version; -// use bitcoin::blockdata::script::ScriptBuf; -// use bitcoin::blockdata::transaction::OutPoint; -// use bitcoin::blockdata::transaction::Transaction; -// use bitcoin::blockdata::transaction::TxIn; -// use bitcoin::blockdata::transaction::TxOut; -// use bitcoin::blockdata::witness::Witness; -// use bitcoin::consensus::deserialize; -// use bitcoin::hash_types::TxMerkleNode; -// use bitcoin::hash_types::Txid; -// use bitcoin::pow::CompactTarget; -// use bitcoin::Block; -// use bitcoin::BlockHash; -// use bitcoin_hashes::sha256d; -// use bitcoin_hashes::Hash; -// use hex; -// use rocksdb::{Options, DB}; - -// // Function to initialize a RocksDB instance -// pub fn init_db(path: &str) -> DB { -// let mut opts = Options::default(); -// opts.create_if_missing(true); -// DB::open(&opts, path).expect("failed to open database") -// } - -// pub fn create_mock_header() -> Header { -// // Convert hex string to a byte array - -// let hash: BlockHash = BlockHash::from_slice(&[0u8; 32]).unwrap(); -// let merkle_root_bytes = -// hex::decode("c9a4892e8ab7704e5078797f74c4d684ff493e22750a528cec21bf30ef73a3b7") -// .expect("Invalid hex string for merkle root"); - -// // Convert the byte array to a Hash type -// let merkle_root_hash = -// sha256d::Hash::from_slice(&merkle_root_bytes).expect("Invalid bytes for merkle root hash"); - -// Header { -// version: Version::from_consensus(1527281788), -// prev_blockhash: hash, // Mock previous block hash -// merkle_root: TxMerkleNode::from_raw_hash(merkle_root_hash), -// time: 2236946890, -// bits: CompactTarget::from_consensus(3633759788), -// nonce: 491612868, -// } -// } - -// pub fn create_mock_block() -> Block { -// // Convert hex string to a byte array - -// let hash: BlockHash = BlockHash::from_slice(&[0u8; 32]).unwrap(); -// let merkle_root_bytes = -// hex::decode("c9a4892e8ab7704e5078797f74c4d684ff493e22750a528cec21bf30ef73a3b7") -// .expect("Invalid hex string for merkle root"); - -// // Convert the byte array to a Hash type -// let merkle_root_hash = -// sha256d::Hash::from_slice(&merkle_root_bytes).expect("Invalid bytes for merkle root hash"); - -// let tx_bytes = hex::decode("c9a4892e8ab7704e5078797f74c4d684ff493e22750a528cec21bf30ef73a3b7") -// .expect("Invalid hex string for merkle root"); -// let tx_id = sha256d::Hash::from_slice(&tx_bytes).expect("Invalid bytes for merkle root hash"); - -// let header = Header { -// version: Version::from_consensus(1527281788), -// prev_blockhash: hash, // Mock previous block hash -// merkle_root: TxMerkleNode::from_raw_hash(merkle_root_hash), -// time: 2236946890, -// bits: CompactTarget::from_consensus(3633759788), -// nonce: 491612868, -// }; - -// let input = TxIn { -// previous_output: OutPoint { -// txid: Txid::from_raw_hash(tx_id), - -// vout: 4294967295, -// }, -// script_sig: ScriptBuf::new(), -// sequence: bitcoin::Sequence(4294967295), -// witness: Witness::default(), -// }; - -// let output1 = TxOut { -// value: 5000000000, -// script_pubkey: ScriptBuf::new(), -// }; - -// let output2 = TxOut { -// value: 0, -// script_pubkey: ScriptBuf::new(), -// }; - -// // Construct the transaction -// let transaction = Transaction { -// version: 2, -// lock_time: bitcoin::absolute::LockTime::from_height(0).unwrap(), -// input: vec![input], -// output: vec![output1, output2], -// }; - -// Block { -// header, -// txdata: vec![transaction], -// } -// } - -// #[cfg(test)] -// mod tests { -// use super::*; -// use tempdir::TempDir; - -// #[test] -// fn test_db_headers_store_retrieve() { -// let temp_dir = TempDir::new("rocksdb_test").unwrap(); -// let rocks_db = RocksDB::new(temp_dir.path().to_str().unwrap()).unwrap(); -// // Create a mock header -// let header = create_mock_header(); -// rocks_db.put_block_header(&header).unwrap(); -// let bh = header.block_hash().to_string(); - -// let retrieved_data = rocks_db.get_block_header(bh.as_bytes()).unwrap(); - -// assert!( -// retrieved_data.is_some(), -// "No data was retrieved for the header" -// ); -// let retrieved_header: Header = deserialize(&retrieved_data.unwrap()).unwrap(); -// assert_eq!( -// header, retrieved_header, -// "Retrieved header should match the original header" -// ); -// } - -// #[test] -// fn test_db_block_store_retrieve() { -// let temp_dir = TempDir::new("rocksdb_test").unwrap(); -// let rocks_db = RocksDB::new(temp_dir.path().to_str().unwrap()).unwrap(); -// // Create a mock header -// let new_block = create_mock_block(); -// rocks_db.put_block(&new_block).unwrap(); -// let bh = new_block.block_hash().to_string(); -// let retrieved_data = rocks_db.get_block(bh.as_bytes()).unwrap(); -// assert!( -// retrieved_data.is_some(), -// "No data was retrieved for the header" -// ); -// let retrieved_block: Block = deserialize(&retrieved_data.unwrap()).unwrap(); -// assert_eq!( -// new_block, retrieved_block, -// "Retrieved header should match the original header" -// ); -// } - -// #[test] -// fn test_db_latest_block_hash_store_retrieve() { -// let temp_dir = TempDir::new("rocksdb_test").unwrap(); -// let rocks_db = RocksDB::new(temp_dir.path().to_str().unwrap()).unwrap(); - -// // Create and store a test block header -// let header = create_mock_header(); -// rocks_db.put_block_header(&header).unwrap(); - -// // Retrieve the latest block hash from the database -// let stored_latest_block_hash = rocks_db.get_latest_block_hash().unwrap(); - -// // Check that the retrieved hash matches the test header's block hash -// assert_eq!( -// Some(header.block_hash().to_string()), -// stored_latest_block_hash, -// "The retrieved latest block hash does not match the expected value." -// ); -// } -// } diff --git a/lib/ain-ocean/src/database/mod.rs b/lib/ain-ocean/src/database/mod.rs deleted file mode 100644 index 3509674f499..00000000000 --- a/lib/ain-ocean/src/database/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod config; -pub mod db_manager; -pub mod db_test; diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index e0be55ee79c..e894520fb90 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -1,12 +1,23 @@ +use std::num::ParseIntError; + use axum::{ http::StatusCode, response::{IntoResponse, Response}, }; - +use bitcoin::hex::HexToArrayError; +use thiserror::Error; pub type OceanResult = Result; +use anyhow::format_err; -#[derive(thiserror::Error, Debug)] -pub enum OceanError {} +#[derive(Error, Debug)] +pub enum OceanError { + #[error("Ocean: HexToArrayError error: {0:?}")] + HexToArrayError(#[from] HexToArrayError), + #[error("Ocean: ParseIntError error: {0:?}")] + ParseIntError(#[from] ParseIntError), + #[error(transparent)] + Other(#[from] anyhow::Error), +} impl IntoResponse for OceanError { fn into_response(self) -> Response { @@ -18,3 +29,15 @@ impl IntoResponse for OceanError { (code, reason).into_response() } } + +impl From> for OceanError { + fn from(err: Box) -> OceanError { + OceanError::Other(format_err!("{err}")) + } +} + +impl From<&str> for OceanError { + fn from(s: &str) -> Self { + OceanError::Other(format_err!("{s}")) + } +} diff --git a/lib/ain-ocean/src/indexer/auction.rs b/lib/ain-ocean/src/indexer/auction.rs index 190373e576a..0a7466c7157 100644 --- a/lib/ain-ocean/src/indexer/auction.rs +++ b/lib/ain-ocean/src/indexer/auction.rs @@ -4,11 +4,11 @@ use super::BlockContext; use crate::indexer::{Index, Result}; impl Index for PlaceAuctionBid { - fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } - fn invalidate(&self) { + fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } } diff --git a/lib/ain-ocean/src/indexer/masternode.rs b/lib/ain-ocean/src/indexer/masternode.rs index 92edb99c7af..41299670c75 100644 --- a/lib/ain-ocean/src/indexer/masternode.rs +++ b/lib/ain-ocean/src/indexer/masternode.rs @@ -1,20 +1,23 @@ -use std::io::Write; - use dftx_rs::{masternode::*, Transaction}; use log::debug; use super::BlockContext; use crate::{ indexer::{Index, Result}, - model::masternode::{Masternode, MasternodeBlock}, + model::{Masternode, MasternodeBlock}, + repository::RepositoryOps, + SERVICES, }; impl Index for CreateMasternode { - fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { debug!("[CreateMasternode] Indexing..."); + let txid = tx.txid(); + debug!("[CreateMasternode] Indexing {txid:?}"); let masternode = Masternode { - id: tx.txid().to_string(), + id: txid.to_string(), + sort: format!("{}-{}", context.height, idx), owner_address: tx.output[1].script_pubkey.to_hex_string(), operator_address: tx.output[1].script_pubkey.to_hex_string(), creation_height: context.height, @@ -29,20 +32,26 @@ impl Index for CreateMasternode { median_time: context.median_time, }, collateral: tx.output[1].value.to_string(), - sort: None, history: None, }; - Ok(()) + SERVICES.masternode.by_id.put(&txid, &masternode)?; + SERVICES + .masternode + .by_height + .put(&(context.height, idx), &txid.to_string()) } - fn invalidate(&self) { - todo!() + fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + debug!("[CreateMasternode] Invalidating..."); + let txid = tx.txid(); + SERVICES.masternode.by_id.delete(&txid)?; + SERVICES.masternode.by_height.delete(&(context.height, idx)) } } impl Index for UpdateMasternode { - fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { debug!("[UpdateMasternode] Indexing..."); // TODO // Get mn @@ -50,15 +59,16 @@ impl Index for UpdateMasternode { Ok(()) } - fn invalidate(&self) { + fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { // TODO // Get mn // Restore from history + Ok(()) } } impl Index for ResignMasternode { - fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { debug!("[ResignMasternode] Indexing..."); // TODO // Get mn @@ -66,9 +76,10 @@ impl Index for ResignMasternode { Ok(()) } - fn invalidate(&self) { + fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { // TODO // Get mn // Set resign height to -1 + Ok(()) } } diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index dba852636aa..057cfb88550 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -5,17 +5,17 @@ mod pool; use dftx_rs::Transaction; -pub(crate) type Result = std::result::Result>; - pub(crate) trait Index { - fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()>; - fn invalidate(&self); + fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()>; + fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()>; } use bitcoin::BlockHash; use dftx_rs::{deserialize, Block, DfTx}; use log::debug; +use crate::Result; + pub(crate) struct BlockContext { height: u32, hash: BlockHash, @@ -36,7 +36,7 @@ pub fn index_block(block: String, block_height: u32) -> Result<()> { median_time: 0, // TODO }; - for tx in block.txdata { + for (idx, tx) in block.txdata.into_iter().enumerate() { let bytes = tx.output[0].script_pubkey.as_bytes(); if bytes.len() > 2 && bytes[0] == 0x6a && bytes[1] <= 0x4e { let offset = 1 + match bytes[1] { @@ -51,16 +51,16 @@ pub fn index_block(block: String, block_height: u32) -> Result<()> { let dftx = deserialize::(raw_tx)?; match dftx { - DfTx::CreateMasternode(data) => data.index(&context, tx)?, - // DfTx::UpdateMasternode(data) => data.index(&context, tx)?, - // DfTx::ResignMasternode(data) => data.index(&context, tx)?, - // DfTx::AppointOracle(data) => data.index(&context, tx)?, - // DfTx::RemoveOracle(data) => data.index(&context, tx)?, - // DfTx::UpdateOracle(data) => data.index(&context, tx)?, - // DfTx::SetOracleData(data) => data.index(&context, tx)?, - // DfTx::PoolSwap(data) => data.index(&context, tx)?, - // DfTx::CompositeSwap(data) => data.index(&context, tx)?, - // DfTx::PlaceAuctionBid(data) => data.index(&context, tx)?, + DfTx::CreateMasternode(data) => data.index(&context, tx, idx)?, + // DfTx::UpdateMasternode(data) => data.index(&context, tx, idx)?, + // DfTx::ResignMasternode(data) => data.index(&context, tx, idx)?, + // DfTx::AppointOracle(data) => data.index(&context, tx, idx)?, + // DfTx::RemoveOracle(data) => data.index(&context, tx, idx)?, + // DfTx::UpdateOracle(data) => data.index(&context, tx, idx)?, + // DfTx::SetOracleData(data) => data.index(&context, tx, idx)?, + // DfTx::PoolSwap(data) => data.index(&context, tx, idx)?, + // DfTx::CompositeSwap(data) => data.index(&context, tx, idx)?, + // DfTx::PlaceAuctionBid(data) => data.index(&context, tx, idx)?, _ => (), } } diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index 950bda90352..c68a2008f2a 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -4,41 +4,41 @@ use super::BlockContext; use crate::indexer::{Index, Result}; impl Index for AppointOracle { - fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } - fn invalidate(&self) { + fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } } impl Index for RemoveOracle { - fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } - fn invalidate(&self) { + fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } } impl Index for UpdateOracle { - fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } - fn invalidate(&self) { + fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } } impl Index for SetOracleData { - fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } - fn invalidate(&self) { + fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } } diff --git a/lib/ain-ocean/src/indexer/pool.rs b/lib/ain-ocean/src/indexer/pool.rs index 86916590516..ed0ae92b275 100644 --- a/lib/ain-ocean/src/indexer/pool.rs +++ b/lib/ain-ocean/src/indexer/pool.rs @@ -4,21 +4,21 @@ use super::BlockContext; use crate::indexer::{Index, Result}; impl Index for PoolSwap { - fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } - fn invalidate(&self) { + fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } } impl Index for CompositeSwap { - fn index(&self, context: &BlockContext, tx: Transaction) -> Result<()> { + fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } - fn invalidate(&self) { + fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } } diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 15af10216db..e3fe9ff7002 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -3,9 +3,48 @@ pub mod api_query; pub mod error; mod indexer; +use std::{path::PathBuf, sync::Arc}; + pub use api::ocean_router; pub use indexer::{index_block, invalidate_block}; +use repository::{MasternodeByHeightRepository, MasternodeRepository, MasternodeStatsRepository}; pub mod api; -mod data_acces; -pub mod database; mod model; +mod repository; +pub mod storage; +use crate::storage::ocean_store::OceanStore; + +pub(crate) type Result = std::result::Result>; + +lazy_static::lazy_static! { + // Global services exposed by the library + pub static ref SERVICES: Services = { + let datadir = ain_cpp_imports::get_datadir(); + let store = OceanStore::new(&PathBuf::from(datadir)).expect("Error initialization Ocean storage"); + Services::new( + Arc::new(store) + ) + }; +} + +pub struct MasternodeService { + by_id: MasternodeRepository, + by_height: MasternodeByHeightRepository, + stats: MasternodeStatsRepository, +} + +pub struct Services { + masternode: MasternodeService, +} + +impl Services { + fn new(store: Arc) -> Self { + Self { + masternode: MasternodeService { + by_id: MasternodeRepository::new(Arc::clone(&store)), + by_height: MasternodeByHeightRepository::new(Arc::clone(&store)), + stats: MasternodeStatsRepository::new(Arc::clone(&store)), + }, + } + } +} diff --git a/lib/ain-ocean/src/model/masternode.rs b/lib/ain-ocean/src/model/masternode.rs index f180ca7aa22..92516758d59 100644 --- a/lib/ain-ocean/src/model/masternode.rs +++ b/lib/ain-ocean/src/model/masternode.rs @@ -2,8 +2,8 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] pub struct Masternode { - pub id: String, - pub sort: Option, + pub id: String, // Keep for backward compatibility + pub sort: String, // Keep for backward compatibility pub owner_address: String, pub operator_address: String, pub creation_height: u32, @@ -16,6 +16,14 @@ pub struct Masternode { pub history: Option>, } +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct HistoryItem { + pub txid: String, + pub owner_address: String, + pub operator_address: String, +} + #[derive(Serialize, Deserialize, Debug, Default)] #[serde(rename_all = "camelCase")] pub struct MasternodeBlock { @@ -24,91 +32,3 @@ pub struct MasternodeBlock { pub time: u64, pub median_time: u64, } - -#[derive(Serialize, Deserialize, Debug, Default, Clone)] -pub enum MasternodeState { - PreEnabled, - Enabled, - PreResigned, - Resigned, - PreBanned, - Banned, - #[default] - Unknown, -} - -impl std::fmt::Display for MasternodeState { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - MasternodeState::PreEnabled => write!(f, "PRE_ENABLED"), - MasternodeState::Enabled => write!(f, "ENABLED"), - MasternodeState::PreResigned => write!(f, "PRE_RESIGNED"), - MasternodeState::Resigned => write!(f, "RESIGNED"), - MasternodeState::PreBanned => write!(f, "PRE_BANNED"), - MasternodeState::Banned => write!(f, "BANNED"), - MasternodeState::Unknown => write!(f, "UNKNOWN"), - } - } -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone)] -pub struct MasternodeOwner { - pub address: String, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone)] -pub struct MasternodeOperator { - pub address: String, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone)] -pub struct MasternodeCreation { - pub height: i32, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone)] -pub struct MasternodeResign { - pub tx: String, - pub height: i32, -} - -#[derive(Serialize, Deserialize, Debug, Default, Clone)] -#[serde(rename_all = "camelCase")] -pub struct MasternodeData { - pub id: String, - pub sort: String, - pub state: MasternodeState, - pub minted_blocks: i32, - pub owner: MasternodeOwner, - pub operator: MasternodeOperator, - pub creation: MasternodeCreation, - pub resign: Option, - pub timelock: i32, -} -impl MasternodeData { - pub fn new(id: &str) -> Self { - Self { - id: id.repeat(64), - sort: id.repeat(72), - state: MasternodeState::Enabled, - minted_blocks: 2, - owner: MasternodeOwner { - address: id.repeat(34), - }, - operator: MasternodeOperator { - address: id.repeat(34), - }, - creation: MasternodeCreation { height: 0 }, - resign: None, - timelock: 0, - } - } -} - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] -pub struct HistoryItem { - pub txid: String, - pub owner_address: String, - pub operator_address: String, -} diff --git a/lib/ain-ocean/src/model/mod.rs b/lib/ain-ocean/src/model/mod.rs index 5d77166b54f..d23d80a0b86 100644 --- a/lib/ain-ocean/src/model/mod.rs +++ b/lib/ain-ocean/src/model/mod.rs @@ -1,21 +1,43 @@ -pub mod block; -pub mod masternode; -pub mod masternode_stats; -pub mod oracle; -pub mod oracle_history; -pub mod oracle_price_active; -pub mod oracle_price_aggregated; -pub mod oracle_price_aggregated_interval; -pub mod oracle_price_feed; -pub mod oracle_token_currency; -pub mod poolswap; -pub mod poolswap_aggregated; -pub mod price_ticker; -pub mod raw_block; -pub mod script_activity; -pub mod script_aggregation; -pub mod script_unspent; -pub mod transaction; -pub mod transaction_vin; -pub mod transaction_vout; -pub mod vault_auction_batch_history; +mod block; +mod masternode; +mod masternode_stats; +mod oracle; +mod oracle_history; +mod oracle_price_active; +mod oracle_price_aggregated; +mod oracle_price_aggregated_interval; +mod oracle_price_feed; +mod oracle_token_currency; +mod poolswap; +mod poolswap_aggregated; +mod price_ticker; +mod raw_block; +mod script_activity; +mod script_aggregation; +mod script_unspent; +mod transaction; +mod transaction_vin; +mod transaction_vout; +mod vault_auction_batch_history; + +pub use block::*; +pub use masternode::*; +pub use masternode_stats::*; +pub use oracle::*; +pub use oracle_history::*; +pub use oracle_price_active::*; +pub use oracle_price_aggregated::*; +pub use oracle_price_aggregated_interval::*; +pub use oracle_price_feed::*; +pub use oracle_token_currency::*; +pub use poolswap::*; +pub use poolswap_aggregated::*; +pub use price_ticker::*; +pub use raw_block::*; +pub use script_activity::*; +pub use script_aggregation::*; +pub use script_unspent::*; +pub use transaction::*; +pub use transaction_vin::*; +pub use transaction_vout::*; +pub use vault_auction_batch_history::*; diff --git a/lib/ain-ocean/src/repository/block.rs b/lib/ain-ocean/src/repository/block.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/block.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/repository/masternode.rs b/lib/ain-ocean/src/repository/masternode.rs new file mode 100644 index 00000000000..c553b7ad91e --- /dev/null +++ b/lib/ain-ocean/src/repository/masternode.rs @@ -0,0 +1,41 @@ +use std::sync::Arc; + +use ain_macros::Repository; +use bitcoin::Txid; + +use super::RepositoryOps; +use crate::{ + model::Masternode, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "Txid", V = "Masternode", Column = "Masternode")] +pub struct MasternodeRepository { + pub store: Arc, +} + +impl MasternodeRepository { + pub fn new(store: Arc) -> Self { + Self { store } + } +} + +type MasternodeByHeightKey = (u32, usize); + +#[derive(Repository)] +#[repository( + K = "MasternodeByHeightKey", + V = "String", + Column = "MasternodeByHeight" +)] +pub struct MasternodeByHeightRepository { + pub store: Arc, +} + +impl MasternodeByHeightRepository { + pub fn new(store: Arc) -> Self { + Self { store } + } +} diff --git a/lib/ain-ocean/src/repository/masternode_stats.rs b/lib/ain-ocean/src/repository/masternode_stats.rs new file mode 100644 index 00000000000..6ba06bf6a13 --- /dev/null +++ b/lib/ain-ocean/src/repository/masternode_stats.rs @@ -0,0 +1,23 @@ +use std::sync::Arc; + +use ain_macros::Repository; +use bitcoin::Txid; + +use super::RepositoryOps; +use crate::{ + model::MasternodeStats, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "Txid", V = "MasternodeStats", Column = "MasternodeStats")] +pub struct MasternodeStatsRepository { + pub store: Arc, +} + +impl MasternodeStatsRepository { + pub fn new(store: Arc) -> Self { + Self { store } + } +} diff --git a/lib/ain-ocean/src/repository/mod.rs b/lib/ain-ocean/src/repository/mod.rs new file mode 100644 index 00000000000..3ee848f9148 --- /dev/null +++ b/lib/ain-ocean/src/repository/mod.rs @@ -0,0 +1,50 @@ +use crate::Result; + +mod block; +mod masternode; +mod masternode_stats; +mod oracle_price_active; +mod oracle_price_aggregated; +mod oracle_price_aggregated_interval; +mod oracle_price_feed; +mod oracle_token_currency; +mod pool_swap; +mod pool_swap_aggregated; +mod price_ticker; +mod raw_block; +mod script_activity; +mod script_aggregation; +mod script_unspent; +mod test; +mod transaction; +mod transaction_vin; +mod transaction_vout; +mod vault_auction_batch_history; + +pub use block::*; +pub use masternode::*; +pub use masternode_stats::*; +pub use oracle_price_active::*; +pub use oracle_price_aggregated::*; +pub use oracle_price_aggregated_interval::*; +pub use oracle_price_feed::*; +pub use oracle_token_currency::*; +pub use pool_swap::*; +pub use pool_swap_aggregated::*; +pub use price_ticker::*; +pub use raw_block::*; +pub use script_activity::*; +pub use script_aggregation::*; +pub use script_unspent::*; +pub use test::*; +pub use transaction::*; +pub use transaction_vin::*; +pub use transaction_vout::*; +pub use vault_auction_batch_history::*; + +pub trait RepositoryOps { + fn get(&self, key: K) -> Result>; + fn put(&self, key: &K, masternode: &V) -> Result<()>; + fn delete(&self, key: &K) -> Result<()>; + fn list(&self, from: Option, limit: usize) -> Result>; +} diff --git a/lib/ain-ocean/src/repository/oracle_price_active.rs b/lib/ain-ocean/src/repository/oracle_price_active.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/oracle_price_active.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/repository/oracle_price_aggregated.rs b/lib/ain-ocean/src/repository/oracle_price_aggregated.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/oracle_price_aggregated.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/repository/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/repository/oracle_price_aggregated_interval.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/oracle_price_aggregated_interval.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/repository/oracle_price_feed.rs b/lib/ain-ocean/src/repository/oracle_price_feed.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/oracle_price_feed.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/repository/oracle_token_currency.rs b/lib/ain-ocean/src/repository/oracle_token_currency.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/oracle_token_currency.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/repository/pool_swap.rs b/lib/ain-ocean/src/repository/pool_swap.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/pool_swap.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/repository/pool_swap_aggregated.rs b/lib/ain-ocean/src/repository/pool_swap_aggregated.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/pool_swap_aggregated.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/repository/price_ticker.rs b/lib/ain-ocean/src/repository/price_ticker.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/price_ticker.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/repository/raw_block.rs b/lib/ain-ocean/src/repository/raw_block.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/raw_block.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/repository/script_activity.rs b/lib/ain-ocean/src/repository/script_activity.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/script_activity.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/repository/script_aggregation.rs b/lib/ain-ocean/src/repository/script_aggregation.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/script_aggregation.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/repository/script_unspent.rs b/lib/ain-ocean/src/repository/script_unspent.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/script_unspent.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/data_acces/test/block_test.rs b/lib/ain-ocean/src/repository/test/block_test.rs similarity index 99% rename from lib/ain-ocean/src/data_acces/test/block_test.rs rename to lib/ain-ocean/src/repository/test/block_test.rs index 4fa1d2d5cb2..7b377e18efc 100644 --- a/lib/ain-ocean/src/data_acces/test/block_test.rs +++ b/lib/ain-ocean/src/repository/test/block_test.rs @@ -1,4 +1,4 @@ -#[cfg(test)] +#[cfg(test_off)] mod tests { use super::*; use crate::data_acces::block::BlockDb; diff --git a/lib/ain-ocean/src/data_acces/test/masternode_test.rs b/lib/ain-ocean/src/repository/test/masternode_test.rs similarity index 99% rename from lib/ain-ocean/src/data_acces/test/masternode_test.rs rename to lib/ain-ocean/src/repository/test/masternode_test.rs index 7ad29de0228..7e815933422 100644 --- a/lib/ain-ocean/src/data_acces/test/masternode_test.rs +++ b/lib/ain-ocean/src/repository/test/masternode_test.rs @@ -1,4 +1,4 @@ -#[cfg(test)] +#[cfg(test_off)] mod tests { use super::*; use crate::data_acces::masternode::MasterNodeDB; diff --git a/lib/ain-ocean/src/data_acces/test/mod.rs b/lib/ain-ocean/src/repository/test/mod.rs similarity index 100% rename from lib/ain-ocean/src/data_acces/test/mod.rs rename to lib/ain-ocean/src/repository/test/mod.rs diff --git a/lib/ain-ocean/src/data_acces/test/oracle_test.rs b/lib/ain-ocean/src/repository/test/oracle_test.rs similarity index 99% rename from lib/ain-ocean/src/data_acces/test/oracle_test.rs rename to lib/ain-ocean/src/repository/test/oracle_test.rs index acaeed659cb..b6930c9e904 100644 --- a/lib/ain-ocean/src/data_acces/test/oracle_test.rs +++ b/lib/ain-ocean/src/repository/test/oracle_test.rs @@ -1,4 +1,4 @@ -#[cfg(test)] +#[cfg(test_off)] mod tests { use tempfile::tempdir; use tokio::task; diff --git a/lib/ain-ocean/src/data_acces/test/transaction_test.rs b/lib/ain-ocean/src/repository/test/transaction_test.rs similarity index 99% rename from lib/ain-ocean/src/data_acces/test/transaction_test.rs rename to lib/ain-ocean/src/repository/test/transaction_test.rs index e87196a35a2..00459f4f34f 100644 --- a/lib/ain-ocean/src/data_acces/test/transaction_test.rs +++ b/lib/ain-ocean/src/repository/test/transaction_test.rs @@ -1,4 +1,4 @@ -#[cfg(test)] +#[cfg(test_off)] mod tests { use tempfile::tempdir; use tokio::task; diff --git a/lib/ain-ocean/src/repository/transaction.rs b/lib/ain-ocean/src/repository/transaction.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/transaction.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/repository/transaction_vin.rs b/lib/ain-ocean/src/repository/transaction_vin.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/transaction_vin.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/repository/transaction_vout.rs b/lib/ain-ocean/src/repository/transaction_vout.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/transaction_vout.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/repository/vault_auction_batch_history.rs b/lib/ain-ocean/src/repository/vault_auction_batch_history.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/lib/ain-ocean/src/repository/vault_auction_batch_history.rs @@ -0,0 +1 @@ + diff --git a/lib/ain-ocean/src/storage/columns/block.rs b/lib/ain-ocean/src/storage/columns/block.rs new file mode 100644 index 00000000000..3e74dde2c51 --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/block.rs @@ -0,0 +1,24 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; + +#[derive(Debug)] +pub struct Block; + +impl ColumnName for Block { + const NAME: &'static str = "block"; +} + +impl Column for Block { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for Block { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/masternode.rs b/lib/ain-ocean/src/storage/columns/masternode.rs new file mode 100644 index 00000000000..9e74561e270 --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/masternode.rs @@ -0,0 +1,71 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct Masternode; + +impl ColumnName for Masternode { + const NAME: &'static str = "masternode"; +} + +impl Column for Masternode { + type Index = Txid; + + fn key(index: &Self::Index) -> Vec { + index.as_byte_array().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + Self::Index::from_slice(&raw_key) + .map_err(|_| DBError::Custom(format_err!("Error parsing key"))) + } +} + +impl TypedColumn for Masternode { + type Type = model::Masternode; +} + +// Secondary index by block height and txno +#[derive(Debug)] +pub struct MasternodeByHeight; + +impl ColumnName for MasternodeByHeight { + const NAME: &'static str = "masternode_by_height"; +} + +impl Column for MasternodeByHeight { + type Index = (u32, usize); + + fn key(index: &Self::Index) -> Vec { + let height_bytes = index.0.to_be_bytes(); + let txno_bytes = index.1.to_be_bytes(); + + let height_slice: &[u8] = AsRef::<[u8]>::as_ref(&height_bytes); + let txno_slice: &[u8] = AsRef::<[u8]>::as_ref(&txno_bytes); + + [height_slice, txno_slice].concat() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + if raw_key.len() != 12 { + return Err(DBError::Custom(format_err!("Wrong key length"))); + } + + let height_bytes = <[u8; 4]>::try_from(&raw_key[..4]) + .map_err(|_| DBError::Custom(format_err!("Invalid height bytes")))?; + let txno_bytes = <[u8; 8]>::try_from(&raw_key[4..]) + .map_err(|_| DBError::Custom(format_err!("Invalid txno bytes")))?; + + let height = u32::from_be_bytes(height_bytes); + let txno = usize::from_be_bytes(txno_bytes); + + Ok((height, txno)) + } +} + +impl TypedColumn for MasternodeByHeight { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/masternode_stats.rs b/lib/ain-ocean/src/storage/columns/masternode_stats.rs new file mode 100644 index 00000000000..5c08d62c7de --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/masternode_stats.rs @@ -0,0 +1,29 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct MasternodeStats; + +impl ColumnName for MasternodeStats { + const NAME: &'static str = "masternode_stats"; +} + +impl Column for MasternodeStats { + type Index = Txid; + + fn key(index: &Self::Index) -> Vec { + index.as_byte_array().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + Self::Index::from_slice(&raw_key) + .map_err(|_| DBError::Custom(format_err!("Error parsing key"))) + } +} + +impl TypedColumn for MasternodeStats { + type Type = model::MasternodeStats; +} diff --git a/lib/ain-ocean/src/storage/columns/mod.rs b/lib/ain-ocean/src/storage/columns/mod.rs new file mode 100644 index 00000000000..0d5dbdfddb3 --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/mod.rs @@ -0,0 +1,66 @@ +mod block; +mod masternode; +mod masternode_stats; +mod oracle_history; +mod oracle_price_active; +mod oracle_price_aggregated; +mod oracle_price_aggregated_interval; +mod oracle_price_feed; +mod oracle_token_currency; +mod pool_swap; +mod pool_swap_aggregated; +mod price_ticker; +mod raw_block; +mod script_activity; +mod script_aggregation; +mod script_unspent; +mod transaction; +mod transaction_vin; +mod transaction_vout; +mod vault_auction_history; + +use ain_db::ColumnName; +pub use block::*; +pub use masternode::*; +pub use masternode_stats::*; +pub use oracle_history::*; +pub use oracle_price_active::*; +pub use oracle_price_aggregated::*; +pub use oracle_price_aggregated_interval::*; +pub use oracle_price_feed::*; +pub use oracle_token_currency::*; +pub use pool_swap::*; +pub use pool_swap_aggregated::*; +pub use price_ticker::*; +pub use raw_block::*; +pub use script_activity::*; +pub use script_aggregation::*; +pub use script_unspent::*; +pub use transaction::*; +pub use transaction_vin::*; +pub use transaction_vout::*; +pub use vault_auction_history::*; + +pub const COLUMN_NAMES: [&'static str; 21] = [ + block::Block::NAME, + masternode_stats::MasternodeStats::NAME, + masternode::Masternode::NAME, + masternode::MasternodeByHeight::NAME, + oracle_history::OracleHistory::NAME, + oracle_price_active::OraclePriceActive::NAME, + oracle_price_aggregated::OraclePriceAggregated::NAME, + oracle_price_aggregated_interval::OraclePriceAggregatedInterval::NAME, + oracle_price_feed::OraclePriceFeed::NAME, + oracle_token_currency::OracleTokenCurrency::NAME, + pool_swap_aggregated::PoolSwapAggregated::NAME, + pool_swap::PoolSwap::NAME, + price_ticker::PriceTicker::NAME, + raw_block::RawBlock::NAME, + script_activity::ScriptActivity::NAME, + script_aggregation::ScriptAggregation::NAME, + script_unspent::ScriptUnspent::NAME, + transaction::Transaction::NAME, + transaction_vin::TransactionVin::NAME, + transaction_vout::TransactionVout::NAME, + vault_auction_history::VaultAuctionHistory::NAME, +]; diff --git a/lib/ain-ocean/src/storage/columns/oracle_history.rs b/lib/ain-ocean/src/storage/columns/oracle_history.rs new file mode 100644 index 00000000000..29a21d36eed --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/oracle_history.rs @@ -0,0 +1,28 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct OracleHistory; + +impl ColumnName for OracleHistory { + const NAME: &'static str = "oracle_history"; +} + +impl Column for OracleHistory { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for OracleHistory { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/oracle_price_active.rs b/lib/ain-ocean/src/storage/columns/oracle_price_active.rs new file mode 100644 index 00000000000..3a5d8da071e --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/oracle_price_active.rs @@ -0,0 +1,28 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model::{self, Oracle}; + +#[derive(Debug)] +pub struct OraclePriceActive; + +impl ColumnName for OraclePriceActive { + const NAME: &'static str = "oracle_price_active"; +} + +impl Column for OraclePriceActive { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for OraclePriceActive { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/oracle_price_aggregated.rs b/lib/ain-ocean/src/storage/columns/oracle_price_aggregated.rs new file mode 100644 index 00000000000..7635952aabe --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/oracle_price_aggregated.rs @@ -0,0 +1,28 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct OraclePriceAggregated; + +impl ColumnName for OraclePriceAggregated { + const NAME: &'static str = "oracle_price_aggregated"; +} + +impl Column for OraclePriceAggregated { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for OraclePriceAggregated { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/storage/columns/oracle_price_aggregated_interval.rs new file mode 100644 index 00000000000..538f7b9d0fa --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/oracle_price_aggregated_interval.rs @@ -0,0 +1,28 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct OraclePriceAggregatedInterval; + +impl ColumnName for OraclePriceAggregatedInterval { + const NAME: &'static str = "oracle_price_aggregated_interval"; +} + +impl Column for OraclePriceAggregatedInterval { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for OraclePriceAggregatedInterval { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/oracle_price_feed.rs b/lib/ain-ocean/src/storage/columns/oracle_price_feed.rs new file mode 100644 index 00000000000..efc07db85fa --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/oracle_price_feed.rs @@ -0,0 +1,28 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct OraclePriceFeed; + +impl ColumnName for OraclePriceFeed { + const NAME: &'static str = "oracle_price_feed"; +} + +impl Column for OraclePriceFeed { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for OraclePriceFeed { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/oracle_token_currency.rs b/lib/ain-ocean/src/storage/columns/oracle_token_currency.rs new file mode 100644 index 00000000000..57c7b348f6b --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/oracle_token_currency.rs @@ -0,0 +1,28 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct OracleTokenCurrency; + +impl ColumnName for OracleTokenCurrency { + const NAME: &'static str = "oracle_token_currency"; +} + +impl Column for OracleTokenCurrency { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for OracleTokenCurrency { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/pool_swap.rs b/lib/ain-ocean/src/storage/columns/pool_swap.rs new file mode 100644 index 00000000000..15d3d3efcf7 --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/pool_swap.rs @@ -0,0 +1,28 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct PoolSwap; + +impl ColumnName for PoolSwap { + const NAME: &'static str = "pool_swap"; +} + +impl Column for PoolSwap { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for PoolSwap { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs b/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs new file mode 100644 index 00000000000..b14503804b3 --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs @@ -0,0 +1,27 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; + +use crate::model; + +#[derive(Debug)] +pub struct PoolSwapAggregated; + +impl ColumnName for PoolSwapAggregated { + const NAME: &'static str = "pool_swap_aggregated"; +} + +impl Column for PoolSwapAggregated { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for PoolSwapAggregated { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/price_ticker.rs b/lib/ain-ocean/src/storage/columns/price_ticker.rs new file mode 100644 index 00000000000..2a377aec72a --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/price_ticker.rs @@ -0,0 +1,28 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct PriceTicker; + +impl ColumnName for PriceTicker { + const NAME: &'static str = "price_tiker"; +} + +impl Column for PriceTicker { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for PriceTicker { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/raw_block.rs b/lib/ain-ocean/src/storage/columns/raw_block.rs new file mode 100644 index 00000000000..85cd7906d7e --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/raw_block.rs @@ -0,0 +1,28 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct RawBlock; + +impl ColumnName for RawBlock { + const NAME: &'static str = "raw_block"; +} + +impl Column for RawBlock { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for RawBlock { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/script_activity.rs b/lib/ain-ocean/src/storage/columns/script_activity.rs new file mode 100644 index 00000000000..a6e14b815e7 --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/script_activity.rs @@ -0,0 +1,28 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct ScriptActivity; + +impl ColumnName for ScriptActivity { + const NAME: &'static str = "raw_block"; +} + +impl Column for ScriptActivity { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for ScriptActivity { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/script_aggregation.rs b/lib/ain-ocean/src/storage/columns/script_aggregation.rs new file mode 100644 index 00000000000..c3ba805e4fa --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/script_aggregation.rs @@ -0,0 +1,28 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct ScriptAggregation; + +impl ColumnName for ScriptAggregation { + const NAME: &'static str = "script_aggregation"; +} + +impl Column for ScriptAggregation { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for ScriptAggregation { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/script_unspent.rs b/lib/ain-ocean/src/storage/columns/script_unspent.rs new file mode 100644 index 00000000000..f07e5ed6a10 --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/script_unspent.rs @@ -0,0 +1,28 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct ScriptUnspent; + +impl ColumnName for ScriptUnspent { + const NAME: &'static str = "script_unspent"; +} + +impl Column for ScriptUnspent { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for ScriptUnspent { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/transaction.rs b/lib/ain-ocean/src/storage/columns/transaction.rs new file mode 100644 index 00000000000..0cb76ed4eab --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/transaction.rs @@ -0,0 +1,28 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct Transaction; + +impl ColumnName for Transaction { + const NAME: &'static str = "transaction"; +} + +impl Column for Transaction { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for Transaction { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/transaction_vin.rs b/lib/ain-ocean/src/storage/columns/transaction_vin.rs new file mode 100644 index 00000000000..2cd118ca826 --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/transaction_vin.rs @@ -0,0 +1,28 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct TransactionVin; + +impl ColumnName for TransactionVin { + const NAME: &'static str = "transaction_vin"; +} + +impl Column for TransactionVin { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for TransactionVin { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/transaction_vout.rs b/lib/ain-ocean/src/storage/columns/transaction_vout.rs new file mode 100644 index 00000000000..206841073e3 --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/transaction_vout.rs @@ -0,0 +1,28 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct TransactionVout; + +impl ColumnName for TransactionVout { + const NAME: &'static str = "transaction_vout"; +} + +impl Column for TransactionVout { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for TransactionVout { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/columns/vault_auction_history.rs b/lib/ain-ocean/src/storage/columns/vault_auction_history.rs new file mode 100644 index 00000000000..5087a2f0925 --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/vault_auction_history.rs @@ -0,0 +1,28 @@ +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; + +use crate::model; + +#[derive(Debug)] +pub struct VaultAuctionHistory; + +impl ColumnName for VaultAuctionHistory { + const NAME: &'static str = "vault_auction_history"; +} + +impl Column for VaultAuctionHistory { + type Index = String; + + fn key(index: &Self::Index) -> Vec { + index.as_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + } +} + +impl TypedColumn for VaultAuctionHistory { + type Type = String; +} diff --git a/lib/ain-ocean/src/storage/mod.rs b/lib/ain-ocean/src/storage/mod.rs new file mode 100644 index 00000000000..c73816d91fb --- /dev/null +++ b/lib/ain-ocean/src/storage/mod.rs @@ -0,0 +1,19 @@ +use rocksdb::IteratorMode; + +pub mod columns; +pub mod ocean_store; + +#[derive(Debug, PartialEq, Clone)] +pub enum SortOrder { + Ascending, + Descending, +} + +impl<'a> From for IteratorMode<'a> { + fn from(sort_order: SortOrder) -> Self { + match sort_order { + SortOrder::Ascending => IteratorMode::Start, + SortOrder::Descending => IteratorMode::End, + } + } +} diff --git a/lib/ain-ocean/src/storage/ocean_store.rs b/lib/ain-ocean/src/storage/ocean_store.rs new file mode 100644 index 00000000000..32a118e2633 --- /dev/null +++ b/lib/ain-ocean/src/storage/ocean_store.rs @@ -0,0 +1,63 @@ +use std::{fs, marker::PhantomData, path::Path, sync::Arc}; + +use ain_db::{Column, ColumnName, LedgerColumn, Rocks, TypedColumn}; + +use super::columns::COLUMN_NAMES; +use crate::Result; + +#[derive(Debug, Clone)] +pub struct OceanStore(Arc); + +impl OceanStore { + pub fn new(path: &Path) -> Result { + let path = path.join("ocean"); + fs::create_dir_all(&path)?; + let backend = Arc::new(Rocks::open(&path, &COLUMN_NAMES)?); + + Ok(Self(backend)) + } + + pub fn column(&self) -> LedgerColumn + where + C: Column + ColumnName, + { + LedgerColumn { + backend: Arc::clone(&self.0), + column: PhantomData, + } + } +} + +impl OceanStore { + pub fn get( + &self, + key: C::Index, + ) -> Result> { + let col = self.column::(); + Ok(col.get(&key)?) + } + + pub fn put( + &self, + key: &C::Index, + val: &C::Type, + ) -> Result<()> { + let col = self.column::(); + let serialized_value = bincode::serialize(val)?; + Ok(col.put_bytes(key, &serialized_value)?) + } + + pub fn delete(&self, key: &C::Index) -> Result<()> { + let col = self.column::(); + Ok(col.delete(key)?) + } + + pub fn list( + &self, + from: Option, + limit: usize, + ) -> Result> { + let col = self.column::(); + Ok(col.iter(from, limit).collect()) + } +} diff --git a/lib/ain-rs-exports/src/ocean.rs b/lib/ain-rs-exports/src/ocean.rs index fd00b0a89a6..eb2b4a0c02e 100644 --- a/lib/ain-rs-exports/src/ocean.rs +++ b/lib/ain-rs-exports/src/ocean.rs @@ -1,9 +1,21 @@ use crate::ffi::CrossBoundaryResult; -pub fn ocean_index_block(_result: &mut CrossBoundaryResult, block: String, block_height: u32) { - ain_ocean::index_block(block, block_height); +pub fn ocean_index_block(result: &mut CrossBoundaryResult, block: String, block_height: u32) { + match ain_ocean::index_block(block, block_height) { + Ok(()) => result.ok = true, + Err(e) => { + result.ok = false; + result.reason = e.to_string() + } + } } -pub fn ocean_invalidate_block(_result: &mut CrossBoundaryResult, block: String, block_height: u32) { - ain_ocean::invalidate_block(block, block_height); +pub fn ocean_invalidate_block(result: &mut CrossBoundaryResult, block: String, block_height: u32) { + match ain_ocean::invalidate_block(block, block_height) { + Ok(()) => result.ok = true, + Err(e) => { + result.ok = false; + result.reason = e.to_string() + } + } } diff --git a/src/dfi/validation.cpp b/src/dfi/validation.cpp index 0574c19b129..743f56c836a 100644 --- a/src/dfi/validation.cpp +++ b/src/dfi/validation.cpp @@ -2799,9 +2799,9 @@ Res ProcessDeFiEventFallible(const CBlock &block, CrossBoundaryResult result; ocean_index_block(result, serializedData, pindex->nHeight); - if (!result.ok) { - return Res::Err(result.reason.c_str()); - } + // if (!result.ok) { + // return Res::Err(result.reason.c_str()); + // } } return Res::Ok(); From 6937cd1c07862ad84574a094cd1bb7e77324311e Mon Sep 17 00:00:00 2001 From: canonbrother Date: Wed, 27 Dec 2023 15:08:46 +0800 Subject: [PATCH 016/185] Fix ocean ci docker not found (#2759) * target branch feature/ocean-archive * docker-build * on pr master + note --- .github/workflows/tests-ocean.yml | 33 +++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/.github/workflows/tests-ocean.yml b/.github/workflows/tests-ocean.yml index 362e42edb25..ad01b0f43e9 100644 --- a/.github/workflows/tests-ocean.yml +++ b/.github/workflows/tests-ocean.yml @@ -5,6 +5,7 @@ on: pull_request: branches: - master + - feature/ocean-archive # TODO(): remove before merge to master concurrency: group: ${{ github.workflow }}-${{ github.ref || github.run_id }} @@ -47,19 +48,35 @@ jobs: name: defi-bins path: build/src/defid - - name: Build docker - run: "docker build -t test-build-container -f ./contrib/dockerfiles/x86_64-pc-linux-gnu.dockerfile ." + docker-build: + runs-on: ubuntu-latest + needs: [build] + + steps: + - uses: actions/checkout@v4 + + - name: Populate environment + run: ./make.sh ci-export-vars + + - name: Download binaries + uses: actions/download-artifact@v3 + with: + name: defi-bins + path: ./build/ - - name: Upload docker - uses: actions/upload-artifact@v3 - with: - name: defi-docker - path: . + - name: Build docker + run: "docker build -t test-build-container -f ./contrib/dockerfiles/x86_64-pc-linux-gnu.dockerfile ." + - name: Upload docker + uses: actions/upload-artifact@v3 + with: + name: defi-docker + path: . + test: name: Jellyfish Whale Api tests runs-on: ubuntu-latest - needs: build + needs: [build, docker-build] strategy: fail-fast: false From a73860adcc610f38f45a15063ad2c615fc38cf66 Mon Sep 17 00:00:00 2001 From: jouzo Date: Wed, 27 Dec 2023 09:34:37 +0100 Subject: [PATCH 017/185] BlockService --- lib/Cargo.lock | 6 +++ lib/ain-db/src/lib.rs | 4 +- lib/ain-ocean/Cargo.toml | 2 +- lib/ain-ocean/src/lib.rs | 17 +++++++- lib/ain-ocean/src/repository/block.rs | 43 +++++++++++++++++++ lib/ain-ocean/src/repository/raw_block.rs | 21 +++++++++ lib/ain-ocean/src/storage/columns/block.rs | 43 +++++++++++++++++-- .../src/storage/columns/masternode.rs | 3 +- .../src/storage/columns/masternode_stats.rs | 3 +- .../src/storage/columns/raw_block.rs | 11 ++--- 10 files changed, 135 insertions(+), 18 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 15d68bce0a1..89865fcdddc 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -661,6 +661,7 @@ dependencies = [ "hex-conservative", "hex_lit", "secp256k1 0.28.0", + "serde", ] [[package]] @@ -668,6 +669,9 @@ name = "bitcoin-internals" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" +dependencies = [ + "serde", +] [[package]] name = "bitcoin-io" @@ -697,6 +701,7 @@ checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" dependencies = [ "bitcoin-internals", "hex-conservative", + "serde", ] [[package]] @@ -4753,6 +4758,7 @@ checksum = "2acea373acb8c21ecb5a23741452acd2593ed44ee3d343e72baaa143bc89d0d5" dependencies = [ "bitcoin_hashes 0.13.0", "secp256k1-sys 0.9.1", + "serde", ] [[package]] diff --git a/lib/ain-db/src/lib.rs b/lib/ain-db/src/lib.rs index 683bc98411a..379b11b7090 100644 --- a/lib/ain-db/src/lib.rs +++ b/lib/ain-db/src/lib.rs @@ -9,7 +9,7 @@ use std::{ use bincode; use rocksdb::{ BlockBasedOptions, Cache, ColumnFamily, ColumnFamilyDescriptor, DBIterator, IteratorMode, - Options, DB, + Options, PerfContext, DB, }; use serde::{de::DeserializeOwned, Serialize}; @@ -204,6 +204,7 @@ use rocksdb::Error as RocksDBError; pub enum DBError { RocksDBError(RocksDBError), Bincode(BincodeError), + ParseKey, Custom(anyhow::Error), } @@ -212,6 +213,7 @@ impl fmt::Display for DBError { match self { DBError::RocksDBError(e) => write!(f, "RocksDB Error: {e}"), DBError::Bincode(e) => write!(f, "Bincode Error: {e}"), + DBError::ParseKey => write!(f, "Error parsing key"), DBError::Custom(e) => write!(f, "Custom Error: {e}"), } } diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index 4d689ac674e..780f2206c96 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -20,7 +20,7 @@ serde.workspace = true thiserror.workspace = true hex.workspace = true dftx-rs.workspace = true -bitcoin.workspace = true +bitcoin = { workspace = true, features = ["serde"] } tarpc = { version = "0.33", features = ["tokio1", "serde1", "serde-transport","tcp"] } tokio = { version = "1", features = ["full"] } serde_json = "1.0" diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index e3fe9ff7002..a69b2fe0f14 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -7,7 +7,10 @@ use std::{path::PathBuf, sync::Arc}; pub use api::ocean_router; pub use indexer::{index_block, invalidate_block}; -use repository::{MasternodeByHeightRepository, MasternodeRepository, MasternodeStatsRepository}; +use repository::{ + BlockByHeightRepository, BlockRepository, MasternodeByHeightRepository, MasternodeRepository, + MasternodeStatsRepository, RawBlockRepository, +}; pub mod api; mod model; mod repository; @@ -33,8 +36,15 @@ pub struct MasternodeService { stats: MasternodeStatsRepository, } +pub struct BlockService { + raw: RawBlockRepository, + by_id: BlockRepository, + by_height: BlockByHeightRepository, +} + pub struct Services { masternode: MasternodeService, + block: BlockService, } impl Services { @@ -45,6 +55,11 @@ impl Services { by_height: MasternodeByHeightRepository::new(Arc::clone(&store)), stats: MasternodeStatsRepository::new(Arc::clone(&store)), }, + block: BlockService { + raw: RawBlockRepository::new(Arc::clone(&store)), + by_id: BlockRepository::new(Arc::clone(&store)), + by_height: BlockByHeightRepository::new(Arc::clone(&store)), + }, } } } diff --git a/lib/ain-ocean/src/repository/block.rs b/lib/ain-ocean/src/repository/block.rs index 8b137891791..75025671b6f 100644 --- a/lib/ain-ocean/src/repository/block.rs +++ b/lib/ain-ocean/src/repository/block.rs @@ -1 +1,44 @@ +use std::sync::Arc; +use ain_macros::Repository; +use bitcoin::BlockHash; + +use super::RepositoryOps; +use crate::{ + model::Block, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "BlockHash", V = "Block", Column = "Block")] +pub struct BlockRepository { + pub store: Arc, +} + +impl BlockRepository { + pub fn new(store: Arc) -> Self { + Self { store } + } +} + +#[derive(Repository)] +#[repository(K = "u32", V = "BlockHash", Column = "BlockByHeight")] +pub struct BlockByHeightRepository { + pub store: Arc, +} + +impl BlockByHeightRepository { + pub fn new(store: Arc) -> Self { + Self { store } + } +} + +impl BlockByHeightRepository { + pub fn get_highest(&self) -> Result> { + match self.store.list::(None, 1)?.first() { + None => Ok(None), + Some((_, id)) => Ok(self.store.get::(*id)?), + } + } +} diff --git a/lib/ain-ocean/src/repository/raw_block.rs b/lib/ain-ocean/src/repository/raw_block.rs index 8b137891791..426b85bb1d0 100644 --- a/lib/ain-ocean/src/repository/raw_block.rs +++ b/lib/ain-ocean/src/repository/raw_block.rs @@ -1 +1,22 @@ +use std::sync::Arc; +use ain_macros::Repository; +use bitcoin::BlockHash; + +use super::RepositoryOps; +use crate::{ + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "BlockHash", V = "String", Column = "RawBlock")] +pub struct RawBlockRepository { + pub store: Arc, +} + +impl RawBlockRepository { + pub fn new(store: Arc) -> Self { + Self { store } + } +} diff --git a/lib/ain-ocean/src/storage/columns/block.rs b/lib/ain-ocean/src/storage/columns/block.rs index 3e74dde2c51..f44085526bd 100644 --- a/lib/ain-ocean/src/storage/columns/block.rs +++ b/lib/ain-ocean/src/storage/columns/block.rs @@ -1,4 +1,8 @@ use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, BlockHash}; + +use crate::model; #[derive(Debug)] pub struct Block; @@ -8,17 +12,48 @@ impl ColumnName for Block { } impl Column for Block { - type Index = String; + type Index = BlockHash; fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() + index.as_byte_array().to_vec() } fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + Self::Index::from_slice(&raw_key).map_err(|_| DBError::ParseKey) } } impl TypedColumn for Block { - type Type = String; + type Type = model::Block; +} + +// Secondary index by block height +#[derive(Debug)] +pub struct BlockByHeight; + +impl ColumnName for BlockByHeight { + const NAME: &'static str = "block_by_height"; +} + +impl Column for BlockByHeight { + type Index = u32; + + fn key(index: &Self::Index) -> Vec { + index.to_be_bytes().to_vec() + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + if raw_key.len() != 4 { + return Err(DBError::Custom(format_err!("Wrong key length"))); + } + + let height_bytes = <[u8; 4]>::try_from(&raw_key[..]) + .map_err(|_| DBError::Custom(format_err!("Invalid height bytes")))?; + + Ok(u32::from_be_bytes(height_bytes)) + } +} + +impl TypedColumn for BlockByHeight { + type Type = BlockHash; } diff --git a/lib/ain-ocean/src/storage/columns/masternode.rs b/lib/ain-ocean/src/storage/columns/masternode.rs index 9e74561e270..98338ba0d14 100644 --- a/lib/ain-ocean/src/storage/columns/masternode.rs +++ b/lib/ain-ocean/src/storage/columns/masternode.rs @@ -19,8 +19,7 @@ impl Column for Masternode { } fn get_key(raw_key: Box<[u8]>) -> Result { - Self::Index::from_slice(&raw_key) - .map_err(|_| DBError::Custom(format_err!("Error parsing key"))) + Self::Index::from_slice(&raw_key).map_err(|_| DBError::ParseKey) } } diff --git a/lib/ain-ocean/src/storage/columns/masternode_stats.rs b/lib/ain-ocean/src/storage/columns/masternode_stats.rs index 5c08d62c7de..217195912af 100644 --- a/lib/ain-ocean/src/storage/columns/masternode_stats.rs +++ b/lib/ain-ocean/src/storage/columns/masternode_stats.rs @@ -19,8 +19,7 @@ impl Column for MasternodeStats { } fn get_key(raw_key: Box<[u8]>) -> Result { - Self::Index::from_slice(&raw_key) - .map_err(|_| DBError::Custom(format_err!("Error parsing key"))) + Self::Index::from_slice(&raw_key).map_err(|_| DBError::ParseKey) } } diff --git a/lib/ain-ocean/src/storage/columns/raw_block.rs b/lib/ain-ocean/src/storage/columns/raw_block.rs index 85cd7906d7e..ddbaee2ee5d 100644 --- a/lib/ain-ocean/src/storage/columns/raw_block.rs +++ b/lib/ain-ocean/src/storage/columns/raw_block.rs @@ -1,8 +1,5 @@ use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; - -use crate::model; +use bitcoin::{hashes::Hash, BlockHash}; #[derive(Debug)] pub struct RawBlock; @@ -12,14 +9,14 @@ impl ColumnName for RawBlock { } impl Column for RawBlock { - type Index = String; + type Index = BlockHash; fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() + index.as_byte_array().to_vec() } fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } + Self::Index::from_slice(&raw_key).map_err(|_| DBError::ParseKey) } } From 9a7b0780550f72b52789669d0b16a2e34b69a386 Mon Sep 17 00:00:00 2001 From: jouzo Date: Fri, 29 Dec 2023 09:11:09 +0100 Subject: [PATCH 018/185] Finish Masternode indexing impl --- lib/Cargo.lock | 327 ++++++++---------- lib/ain-ocean/src/api/masternode.rs | 40 ++- lib/ain-ocean/src/indexer/auction.rs | 2 +- lib/ain-ocean/src/indexer/masternode.rs | 117 +++++-- lib/ain-ocean/src/indexer/mod.rs | 30 +- lib/ain-ocean/src/indexer/oracle.rs | 8 +- lib/ain-ocean/src/indexer/pool.rs | 4 +- lib/ain-ocean/src/model/masternode.rs | 24 +- lib/ain-ocean/src/repository/masternode.rs | 6 +- .../src/storage/columns/masternode.rs | 2 +- 10 files changed, 292 insertions(+), 268 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 89865fcdddc..eef3890a310 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -183,7 +183,7 @@ dependencies = [ "evm", "heck 0.4.1", "hex", - "hyper 0.14.27", + "hyper 0.14.28", "jsonrpsee 0.16.3", "jsonrpsee-server 0.16.3", "lazy_static", @@ -204,7 +204,7 @@ dependencies = [ "serde_json", "serde_with", "sha3", - "syn 2.0.41", + "syn 2.0.43", "tokio", "tonic", "tonic-build", @@ -218,7 +218,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -239,7 +239,7 @@ dependencies = [ "dftx-rs", "futures", "hex", - "hyper 0.14.27", + "hyper 0.14.28", "json", "jsonrpsee 0.20.3", "keccak-hash", @@ -327,9 +327,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "c9d19de80eff169429ac1e9f48fffb163916b448a44e8e046186232046d9e1f9" [[package]] name = "approx" @@ -391,13 +391,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -442,7 +442,7 @@ dependencies = [ "futures-util", "http 0.2.11", "http-body 0.4.6", - "hyper 0.14.27", + "hyper 0.14.28", "itoa", "matchit", "memchr", @@ -471,7 +471,7 @@ dependencies = [ "http 1.0.0", "http-body 1.0.0", "http-body-util", - "hyper 1.0.1", + "hyper 1.1.0", "hyper-util", "itoa", "matchit", @@ -537,7 +537,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -551,7 +551,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object 0.32.1", + "object 0.32.2", "rustc-demangle", ] @@ -631,7 +631,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -828,9 +828,9 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bstr" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c" +checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" dependencies = [ "memchr", "serde", @@ -1030,9 +1030,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "constant_time_eq" @@ -1100,9 +1100,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2" dependencies = [ "cfg-if", "crossbeam-utils", @@ -1110,9 +1110,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -1121,22 +1121,20 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset 0.9.0", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" dependencies = [ "cfg-if", ] @@ -1191,12 +1189,12 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" +checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b" dependencies = [ "nix", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1227,9 +1225,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.110" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7129e341034ecb940c9072817cd9007974ea696844fc4dd582dc1653a7fbe2e8" +checksum = "e9fc0c733f71e58dedf4f034cd2a266f80b94cc9ed512729e1798651b68c2cba" dependencies = [ "cc", "cxxbridge-flags", @@ -1239,9 +1237,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.110" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a24f3f5f8eed71936f21e570436f024f5c2e25628f7496aa7ccd03b90109d5" +checksum = "51bc81d2664db24cf1d35405f66e18a85cffd4d49ab930c71a5c6342a410f38c" dependencies = [ "cc", "codespan-reporting", @@ -1249,36 +1247,36 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] name = "cxx-gen" -version = "0.7.110" +version = "0.7.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e0fc77e9f8d61724be90deb42a7e50ba3bf37c7c16dc91cdba821f69a5e0e9" +checksum = "6fff9b9f62092944662d561f5d2202e64490094faa0b96b09102cf6eabdb55cb" dependencies = [ "codespan-reporting", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] name = "cxxbridge-flags" -version = "1.0.110" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06fdd177fc61050d63f67f5bd6351fac6ab5526694ea8e359cd9cd3b75857f44" +checksum = "8511afbe34ea242697784da5cb2c5d4a0afb224ca8b136bdf93bfe180cbe5884" [[package]] name = "cxxbridge-macro" -version = "1.0.110" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "587663dd5fb3d10932c8aecfe7c844db1bcf0aee93eeab08fac13dc1212c2e7f" +checksum = "5c6888cd161769d65134846d4d4981d5a6654307cc46ec83fb917e530aea5f84" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -1326,7 +1324,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -1348,7 +1346,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core 0.20.3", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -1391,17 +1389,17 @@ checksum = "3ae2a35373c5c74340b79ae6780b498b2b183915ec5dacf263aac5a099bf485a" [[package]] name = "dftx-macro" version = "0.1.0" -source = "git+https://github.com/Jouzo/dftx-rs.git#7973f1ad240d5f7724e51c6b090bcd3daafc495c" +source = "git+https://github.com/Jouzo/dftx-rs.git#97fd965134968e19f8990ed27ef9b2a279e45089" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] name = "dftx-rs" version = "0.1.0" -source = "git+https://github.com/Jouzo/dftx-rs.git#7973f1ad240d5f7724e51c6b090bcd3daafc495c" +source = "git+https://github.com/Jouzo/dftx-rs.git#97fd965134968e19f8990ed27ef9b2a279e45089" dependencies = [ "anyhow", "bitcoin", @@ -1843,9 +1841,9 @@ dependencies = [ [[package]] name = "fake" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26221445034074d46b276e13eb97a265ebdb8ed8da705c4dddd3dd20b66b45d2" +checksum = "1c25829bde82205da46e1823b2259db6273379f626fc211f126f65654a2669be" dependencies = [ "deunicode", "rand 0.8.5", @@ -1956,9 +1954,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -1971,9 +1969,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -1981,15 +1979,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -1999,38 +1997,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -2325,11 +2323,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.5" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2414,9 +2412,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -2429,7 +2427,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2", "tokio", "tower-service", "tracing", @@ -2438,9 +2436,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f9214f3e703236b221f1a9cd88ec8b4adfa5296de01ab96216361f4692f56" +checksum = "fb5aa53871fc917b1a9ed87b683a5d86db645e23acb32c2e0785a353e522fb75" dependencies = [ "bytes", "futures-channel", @@ -2463,7 +2461,7 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.11", - "hyper 0.14.27", + "hyper 0.14.28", "log", "rustls", "rustls-native-certs", @@ -2478,7 +2476,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper 0.14.27", + "hyper 0.14.28", "pin-project-lite", "tokio", "tokio-io-timeout", @@ -2486,21 +2484,19 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca339002caeb0d159cc6e023dff48e199f081e42fa039895c7c6f38b37f2e9d" +checksum = "bdea9aac0dbe5a9240d68cfd9501e2db94222c6dc06843e06640b9e07f0fdc67" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.0.0", "http-body 1.0.0", - "hyper 1.0.1", + "hyper 1.1.0", "pin-project-lite", - "socket2 0.5.5", + "socket2", "tokio", - "tower", - "tower-service", "tracing", ] @@ -2650,13 +2646,13 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" dependencies = [ "hermit-abi 0.3.3", "rustix 0.38.28", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2760,7 +2756,7 @@ dependencies = [ "futures-channel", "futures-util", "globset", - "hyper 0.14.27", + "hyper 0.14.28", "jsonrpsee-types 0.16.3", "parking_lot", "rand 0.8.5", @@ -2783,7 +2779,7 @@ dependencies = [ "async-trait", "beef", "futures-util", - "hyper 0.14.27", + "hyper 0.14.28", "jsonrpsee-types 0.18.2", "serde", "serde_json", @@ -2802,7 +2798,7 @@ dependencies = [ "async-trait", "beef", "futures-util", - "hyper 0.14.27", + "hyper 0.14.28", "jsonrpsee-types 0.20.3", "parking_lot", "rand 0.8.5", @@ -2822,7 +2818,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e5f9fabdd5d79344728521bb65e3106b49ec405a78b66fbff073b72b389fa43" dependencies = [ "async-trait", - "hyper 0.14.27", + "hyper 0.14.28", "hyper-rustls", "jsonrpsee-core 0.16.3", "jsonrpsee-types 0.16.3", @@ -2841,7 +2837,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1705c65069729e3dccff6fd91ee431d5d31cabcf00ce68a62a2c6435ac713af9" dependencies = [ "async-trait", - "hyper 0.14.27", + "hyper 0.14.28", "hyper-rustls", "jsonrpsee-core 0.18.2", "jsonrpsee-types 0.18.2", @@ -2860,7 +2856,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f80c17f62c7653ce767e3d7288b793dfec920f97067ceb189ebdd3570f2bc20" dependencies = [ "async-trait", - "hyper 0.14.27", + "hyper 0.14.28", "hyper-rustls", "jsonrpsee-core 0.20.3", "jsonrpsee-types 0.20.3", @@ -2908,7 +2904,7 @@ dependencies = [ "futures-channel", "futures-util", "http 0.2.11", - "hyper 0.14.27", + "hyper 0.14.28", "jsonrpsee-core 0.16.3", "jsonrpsee-types 0.16.3", "serde", @@ -2929,7 +2925,7 @@ checksum = "82c39a00449c9ef3f50b84fc00fc4acba20ef8f559f07902244abf4c15c5ab9c" dependencies = [ "futures-util", "http 0.2.11", - "hyper 0.14.27", + "hyper 0.14.28", "jsonrpsee-core 0.20.3", "jsonrpsee-types 0.20.3", "route-recognizer", @@ -3303,9 +3299,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "memfd" @@ -3325,15 +3321,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] - [[package]] name = "memory-db" version = "0.32.0" @@ -3595,7 +3582,7 @@ dependencies = [ "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -3612,9 +3599,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] @@ -3863,7 +3850,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -3901,7 +3888,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -3928,9 +3915,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" [[package]] name = "powerfmt" @@ -3967,7 +3954,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -4030,9 +4017,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" dependencies = [ "unicode-ident", ] @@ -4306,22 +4293,22 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acde58d073e9c79da00f2b5b84eed919c8326832648a5b109b3fce1bb1175280" +checksum = "53313ec9f12686aeeffb43462c3ac77aa25f590a5f630eb2cde0de59417b29c7" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" +checksum = "2566c4bf6845f2c2e83b27043c3f5dfcd5ba8f2937d6c00dc009bfb51a079dc4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -4385,9 +4372,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.22" +version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ "base64 0.21.5", "bytes", @@ -4397,7 +4384,7 @@ dependencies = [ "h2 0.3.22", "http 0.2.11", "http-body 0.4.6", - "hyper 0.14.27", + "hyper 0.14.28", "hyper-rustls", "ipnet", "js-sys", @@ -4669,11 +4656,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -4852,7 +4839,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -4914,7 +4901,7 @@ dependencies = [ "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -5061,16 +5048,6 @@ version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.5" @@ -5179,7 +5156,7 @@ checksum = "f12dae7cf6c1e825d13ffd4ce16bd9309db7c539929d0302b4443ed451a9f4e5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -5273,7 +5250,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -5502,7 +5479,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -5570,9 +5547,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.41" +version = "2.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" +checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" dependencies = [ "proc-macro2", "quote", @@ -5665,15 +5642,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.8.1" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if", "fastrand", "redox_syscall", "rustix 0.38.28", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -5707,22 +5684,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "83a48fd946b02c0a526b2e9481c8e2a17755e47039164a86c4070446e3a4614d" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "e7fbe9b594d6568a6a1443250a7e67d80b74e1e96f6d1715e1e21cc1888291d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -5746,9 +5723,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" dependencies = [ "deranged", "itoa", @@ -5766,9 +5743,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" dependencies = [ "time-core", ] @@ -5818,9 +5795,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.0" +version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ "backtrace", "bytes", @@ -5830,7 +5807,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.5", + "socket2", "tokio-macros", "windows-sys 0.48.0", ] @@ -5853,7 +5830,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -5948,7 +5925,7 @@ dependencies = [ "h2 0.3.22", "http 0.2.11", "http-body 0.4.6", - "hyper 0.14.27", + "hyper 0.14.28", "hyper-timeout", "percent-encoding", "pin-project", @@ -6056,7 +6033,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -6431,7 +6408,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", "wasm-bindgen-shared", ] @@ -6465,7 +6442,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6596,7 +6573,7 @@ dependencies = [ "log", "mach", "memfd", - "memoffset 0.8.0", + "memoffset", "paste", "rand 0.8.5", "rustix 0.36.17", @@ -6896,9 +6873,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.28" +version = "0.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2" +checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c" dependencies = [ "memchr", ] @@ -6930,22 +6907,22 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "zerocopy" -version = "0.7.30" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306dca4455518f1f31635ec308b6b3e4eb1b11758cefafc782827d0aa7acb5c7" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.30" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -6965,7 +6942,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] diff --git a/lib/ain-ocean/src/api/masternode.rs b/lib/ain-ocean/src/api/masternode.rs index 737f0b2d5b8..0fe0d38b59b 100644 --- a/lib/ain-ocean/src/api/masternode.rs +++ b/lib/ain-ocean/src/api/masternode.rs @@ -3,6 +3,7 @@ use axum::{ routing::get, Json, Router, }; +use bitcoin::Txid; use serde::{Deserialize, Serialize}; use crate::{ @@ -23,28 +24,28 @@ pub enum MasternodeState { Unknown, } -#[derive(Serialize, Deserialize, Debug, Default, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct MasternodeOwner { pub address: String, } -#[derive(Serialize, Deserialize, Debug, Default, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct MasternodeOperator { pub address: String, } -#[derive(Serialize, Deserialize, Debug, Default, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct MasternodeCreation { pub height: u32, } -#[derive(Serialize, Deserialize, Debug, Default, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct MasternodeResign { - pub tx: String, - pub height: i32, + pub tx: Txid, + pub height: i64, } -#[derive(Serialize, Deserialize, Debug, Default, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct MasternodeData { pub id: String, @@ -61,22 +62,25 @@ pub struct MasternodeData { impl From for MasternodeData { fn from(v: Masternode) -> Self { MasternodeData { - id: v.id, + id: v.id.to_string(), sort: v.sort, state: MasternodeState::default(), // TODO Handle mn state minted_blocks: v.minted_blocks, owner: MasternodeOwner { - address: v.owner_address, + address: v.owner_address.to_hex_string(), }, operator: MasternodeOperator { - address: v.operator_address, + address: v.operator_address.to_hex_string(), }, creation: MasternodeCreation { height: v.creation_height, }, resign: v.resign_tx.map(|tx| MasternodeResign { tx, - height: v.resign_height, + height: match v.resign_height { + None => -1, + Some(v) => v as i64, + }, }), timelock: v.timelock, } @@ -106,12 +110,11 @@ async fn list_masternodes( .by_height .list(next, query.size)? .iter() - .map(|(_, mn_id)| { - let id: bitcoin::Txid = mn_id.parse()?; + .map(|(_, id)| { let mn = SERVICES .masternode .by_id - .get(id)? + .get(*id)? .ok_or("Missing masternode index")?; Ok(mn.into()) @@ -126,10 +129,13 @@ async fn list_masternodes( } async fn get_masternode( - Path(masternode_id): Path, + Path(masternode_id): Path, ) -> OceanResult>> { - let id: bitcoin::Txid = masternode_id.parse()?; - let mn = SERVICES.masternode.by_id.get(id)?.map(Into::into); + let mn = SERVICES + .masternode + .by_id + .get(masternode_id)? + .map(Into::into); Ok(Json(mn)) } diff --git a/lib/ain-ocean/src/indexer/auction.rs b/lib/ain-ocean/src/indexer/auction.rs index 0a7466c7157..2d2ca0d0e88 100644 --- a/lib/ain-ocean/src/indexer/auction.rs +++ b/lib/ain-ocean/src/indexer/auction.rs @@ -4,7 +4,7 @@ use super::BlockContext; use crate::indexer::{Index, Result}; impl Index for PlaceAuctionBid { - fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } diff --git a/lib/ain-ocean/src/indexer/masternode.rs b/lib/ain-ocean/src/indexer/masternode.rs index 41299670c75..2b60f84c6ca 100644 --- a/lib/ain-ocean/src/indexer/masternode.rs +++ b/lib/ain-ocean/src/indexer/masternode.rs @@ -1,85 +1,130 @@ +use bitcoin::{hashes::Hash, PubkeyHash, ScriptBuf, WPubkeyHash}; use dftx_rs::{masternode::*, Transaction}; use log::debug; use super::BlockContext; use crate::{ indexer::{Index, Result}, - model::{Masternode, MasternodeBlock}, + model::{HistoryItem, Masternode, MasternodeBlock}, repository::RepositoryOps, SERVICES, }; +fn get_operator_script(hash: &PubkeyHash, r#type: u8) -> Result { + match r#type { + 0x1 => Ok(ScriptBuf::new_p2pkh(hash)), + 0x4 => Ok(ScriptBuf::new_p2wpkh(&WPubkeyHash::hash( + hash.as_byte_array(), + ))), + _ => Err("Unsupported type".into()), + } +} + impl Index for CreateMasternode { - fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { debug!("[CreateMasternode] Indexing..."); let txid = tx.txid(); - debug!("[CreateMasternode] Indexing {txid:?}"); let masternode = Masternode { - id: txid.to_string(), - sort: format!("{}-{}", context.height, idx), - owner_address: tx.output[1].script_pubkey.to_hex_string(), - operator_address: tx.output[1].script_pubkey.to_hex_string(), - creation_height: context.height, - resign_height: -1, + id: txid, + sort: format!("{}-{}", ctx.height, idx), + owner_address: tx.output[1].script_pubkey.clone(), + operator_address: get_operator_script(&self.operator_pub_key_hash, self.operator_type)?, + creation_height: ctx.height, + resign_height: None, resign_tx: None, minted_blocks: 0, timelock: self.timelock.0.unwrap_or_default(), block: MasternodeBlock { - hash: context.hash.to_string(), - height: context.height, - time: context.time, - median_time: context.median_time, + hash: ctx.hash, + height: ctx.height, + time: ctx.time, + median_time: ctx.median_time, }, collateral: tx.output[1].value.to_string(), - history: None, + history: Vec::new(), }; SERVICES.masternode.by_id.put(&txid, &masternode)?; - SERVICES - .masternode - .by_height - .put(&(context.height, idx), &txid.to_string()) + SERVICES.masternode.by_height.put(&(ctx.height, idx), &txid) } - fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn invalidate(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { debug!("[CreateMasternode] Invalidating..."); let txid = tx.txid(); SERVICES.masternode.by_id.delete(&txid)?; - SERVICES.masternode.by_height.delete(&(context.height, idx)) + SERVICES.masternode.by_height.delete(&(ctx.height, idx)) } } impl Index for UpdateMasternode { - fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, _ctx: &BlockContext, tx: Transaction, _idx: usize) -> Result<()> { debug!("[UpdateMasternode] Indexing..."); - // TODO - // Get mn - // Update fields + if let Some(mut mn) = SERVICES.masternode.by_id.get(self.node_id)? { + mn.history.push(HistoryItem { + owner_address: mn.owner_address.clone(), + operator_address: mn.operator_address.clone(), + }); + + for update in self.updates.as_ref() { + debug!("update : {:?}", update); + match update.r#type { + 0x1 => mn.owner_address = tx.output[1].script_pubkey.clone(), + 0x2 => { + if let Some(hash) = update.address.address_pub_key_hash { + mn.operator_address = get_operator_script(&hash, update.address.r#type)? + } + } + _ => (), + } + } + + SERVICES.masternode.by_id.put(&self.node_id, &mn)?; + } Ok(()) } - fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { - // TODO - // Get mn - // Restore from history + fn invalidate(&self, _ctx: &BlockContext, _tx: Transaction, _idx: usize) -> Result<()> { + debug!("[UpdateMasternode] Invalidating..."); + if let Some(mut mn) = SERVICES.masternode.by_id.get(self.node_id)? { + if let Some(history_item) = mn.history.pop() { + mn.owner_address = history_item.owner_address; + mn.operator_address = history_item.operator_address; + } + + SERVICES.masternode.by_id.put(&self.node_id, &mn)?; + } Ok(()) } } impl Index for ResignMasternode { - fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, ctx: &BlockContext, tx: Transaction, _idx: usize) -> Result<()> { debug!("[ResignMasternode] Indexing..."); - // TODO - // Get mn - // Set resign tx and resign height + if let Some(mn) = SERVICES.masternode.by_id.get(self.node_id)? { + SERVICES.masternode.by_id.put( + &self.node_id, + &Masternode { + resign_height: Some(ctx.height), + resign_tx: Some(tx.txid()), + ..mn + }, + )?; + } Ok(()) } - fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { - // TODO - // Get mn - // Set resign height to -1 + fn invalidate(&self, _ctx: &BlockContext, _tx: Transaction, _idx: usize) -> Result<()> { + debug!("[ResignMasternode] Invalidating..."); + if let Some(mn) = SERVICES.masternode.by_id.get(self.node_id)? { + SERVICES.masternode.by_id.put( + &self.node_id, + &Masternode { + resign_height: None, + ..mn + }, + )?; + } Ok(()) } } diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 057cfb88550..1696b931fda 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -6,7 +6,7 @@ mod pool; use dftx_rs::Transaction; pub(crate) trait Index { - fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()>; + fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()>; fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()>; } @@ -27,9 +27,10 @@ pub fn index_block(block: String, block_height: u32) -> Result<()> { debug!("[index_block] Indexing block..."); let hex = hex::decode(block)?; + debug!("got hex"); let block = deserialize::(&hex)?; - - let context = BlockContext { + debug!("got block"); + let ctx = BlockContext { height: block_height, hash: block.block_hash(), time: 0, // TODO @@ -47,24 +48,23 @@ pub fn index_block(block: String, block_height: u32) -> Result<()> { }; let raw_tx = &bytes[offset..]; - let dftx = deserialize::(raw_tx)?; - match dftx { - DfTx::CreateMasternode(data) => data.index(&context, tx, idx)?, - // DfTx::UpdateMasternode(data) => data.index(&context, tx, idx)?, - // DfTx::ResignMasternode(data) => data.index(&context, tx, idx)?, - // DfTx::AppointOracle(data) => data.index(&context, tx, idx)?, - // DfTx::RemoveOracle(data) => data.index(&context, tx, idx)?, - // DfTx::UpdateOracle(data) => data.index(&context, tx, idx)?, - // DfTx::SetOracleData(data) => data.index(&context, tx, idx)?, - // DfTx::PoolSwap(data) => data.index(&context, tx, idx)?, - // DfTx::CompositeSwap(data) => data.index(&context, tx, idx)?, - // DfTx::PlaceAuctionBid(data) => data.index(&context, tx, idx)?, + DfTx::CreateMasternode(data) => data.index(&ctx, tx, idx)?, + DfTx::UpdateMasternode(data) => data.index(&ctx, tx, idx)?, + DfTx::ResignMasternode(data) => data.index(&ctx, tx, idx)?, + // DfTx::AppointOracle(data) => data.index(&ctx, tx, idx)?, + // DfTx::RemoveOracle(data) => data.index(&ctx, tx, idx)?, + // DfTx::UpdateOracle(data) => data.index(&ctx, tx, idx)?, + // DfTx::SetOracleData(data) => data.index(&ctx, tx, idx)?, + // DfTx::PoolSwap(data) => data.index(&ctx, tx, idx)?, + // DfTx::CompositeSwap(data) => data.index(&ctx, tx, idx)?, + // DfTx::PlaceAuctionBid(data) => data.index(&ctx, tx, idx)?, _ => (), } } } + Ok(()) } diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index c68a2008f2a..32f2465e157 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -4,7 +4,7 @@ use super::BlockContext; use crate::indexer::{Index, Result}; impl Index for AppointOracle { - fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } @@ -14,7 +14,7 @@ impl Index for AppointOracle { } impl Index for RemoveOracle { - fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } @@ -24,7 +24,7 @@ impl Index for RemoveOracle { } impl Index for UpdateOracle { - fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } @@ -34,7 +34,7 @@ impl Index for UpdateOracle { } impl Index for SetOracleData { - fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } diff --git a/lib/ain-ocean/src/indexer/pool.rs b/lib/ain-ocean/src/indexer/pool.rs index ed0ae92b275..4a23319e7ae 100644 --- a/lib/ain-ocean/src/indexer/pool.rs +++ b/lib/ain-ocean/src/indexer/pool.rs @@ -4,7 +4,7 @@ use super::BlockContext; use crate::indexer::{Index, Result}; impl Index for PoolSwap { - fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } @@ -14,7 +14,7 @@ impl Index for PoolSwap { } impl Index for CompositeSwap { - fn index(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { todo!() } diff --git a/lib/ain-ocean/src/model/masternode.rs b/lib/ain-ocean/src/model/masternode.rs index 92516758d59..126885d7570 100644 --- a/lib/ain-ocean/src/model/masternode.rs +++ b/lib/ain-ocean/src/model/masternode.rs @@ -1,33 +1,33 @@ +use bitcoin::{BlockHash, ScriptBuf, Txid}; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] pub struct Masternode { - pub id: String, // Keep for backward compatibility + pub id: Txid, // Keep for backward compatibility pub sort: String, // Keep for backward compatibility - pub owner_address: String, - pub operator_address: String, + pub owner_address: ScriptBuf, + pub operator_address: ScriptBuf, pub creation_height: u32, - pub resign_height: i32, - pub resign_tx: Option, + pub resign_height: Option, + pub resign_tx: Option, pub minted_blocks: i32, pub timelock: u16, pub collateral: String, pub block: MasternodeBlock, - pub history: Option>, + pub history: Vec, } -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct HistoryItem { - pub txid: String, - pub owner_address: String, - pub operator_address: String, + pub owner_address: ScriptBuf, + pub operator_address: ScriptBuf, } -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct MasternodeBlock { - pub hash: String, + pub hash: BlockHash, pub height: u32, pub time: u64, pub median_time: u64, diff --git a/lib/ain-ocean/src/repository/masternode.rs b/lib/ain-ocean/src/repository/masternode.rs index c553b7ad91e..489f91c7040 100644 --- a/lib/ain-ocean/src/repository/masternode.rs +++ b/lib/ain-ocean/src/repository/masternode.rs @@ -25,11 +25,7 @@ impl MasternodeRepository { type MasternodeByHeightKey = (u32, usize); #[derive(Repository)] -#[repository( - K = "MasternodeByHeightKey", - V = "String", - Column = "MasternodeByHeight" -)] +#[repository(K = "MasternodeByHeightKey", V = "Txid", Column = "MasternodeByHeight")] pub struct MasternodeByHeightRepository { pub store: Arc, } diff --git a/lib/ain-ocean/src/storage/columns/masternode.rs b/lib/ain-ocean/src/storage/columns/masternode.rs index 98338ba0d14..c99fbe0ac61 100644 --- a/lib/ain-ocean/src/storage/columns/masternode.rs +++ b/lib/ain-ocean/src/storage/columns/masternode.rs @@ -66,5 +66,5 @@ impl Column for MasternodeByHeight { } impl TypedColumn for MasternodeByHeight { - type Type = String; + type Type = Txid; } From 0acc887add3214f501dd4559036fe0b9fe497cc2 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Tue, 2 Jan 2024 15:32:27 +0100 Subject: [PATCH 019/185] Use serde as default Column trait implementation (#2765) --- lib/ain-db/src/lib.rs | 41 +++++---- lib/ain-evm/src/storage/block_store.rs | 14 +-- lib/ain-evm/src/storage/db.rs | 85 +------------------ lib/ain-ocean/src/storage/columns/block.rs | 23 ----- .../src/storage/columns/masternode.rs | 34 -------- .../src/storage/columns/masternode_stats.rs | 8 -- lib/ain-ocean/src/storage/columns/mod.rs | 3 +- .../src/storage/columns/oracle_history.rs | 14 +-- .../storage/columns/oracle_price_active.rs | 14 +-- .../columns/oracle_price_aggregated.rs | 14 +-- .../oracle_price_aggregated_interval.rs | 14 +-- .../src/storage/columns/oracle_price_feed.rs | 14 +-- .../storage/columns/oracle_token_currency.rs | 14 +-- .../src/storage/columns/pool_swap.rs | 14 +-- .../storage/columns/pool_swap_aggregated.rs | 13 +-- .../src/storage/columns/price_ticker.rs | 14 +-- .../src/storage/columns/raw_block.rs | 12 +-- .../src/storage/columns/script_activity.rs | 14 +-- .../src/storage/columns/script_aggregation.rs | 14 +-- .../src/storage/columns/script_unspent.rs | 14 +-- .../src/storage/columns/transaction.rs | 14 +-- .../src/storage/columns/transaction_vin.rs | 14 +-- .../src/storage/columns/transaction_vout.rs | 15 +--- .../storage/columns/vault_auction_history.rs | 26 ++++-- 24 files changed, 74 insertions(+), 382 deletions(-) diff --git a/lib/ain-db/src/lib.rs b/lib/ain-db/src/lib.rs index 379b11b7090..fa4b424ced7 100644 --- a/lib/ain-db/src/lib.rs +++ b/lib/ain-db/src/lib.rs @@ -6,10 +6,11 @@ use std::{ sync::Arc, }; +use anyhow::format_err; use bincode; use rocksdb::{ BlockBasedOptions, Cache, ColumnFamily, ColumnFamilyDescriptor, DBIterator, IteratorMode, - Options, PerfContext, DB, + Options, DB, }; use serde::{de::DeserializeOwned, Serialize}; @@ -66,10 +67,10 @@ impl Rocks { Ok(()) } - pub fn cf_handle(&self, cf: &str) -> &ColumnFamily { + pub fn cf_handle(&self, cf: &str) -> Result<&ColumnFamily> { self.0 .cf_handle(cf) - .expect("should never get an unknown column") + .ok_or_else(|| DBError::Custom(format_err!("Unknown column: {}", cf))) } fn get_cf(&self, cf: &ColumnFamily, key: &[u8]) -> Result>> { @@ -111,11 +112,15 @@ pub trait ColumnName { // Column trait. Define associated index type // pub trait Column { - type Index: Debug; + type Index: Debug + Serialize + DeserializeOwned; - fn key(index: &Self::Index) -> Vec; + fn key(index: &Self::Index) -> Result> { + bincode::serialize(index).map_err(DBError::Bincode) + } - fn get_key(raw_key: Box<[u8]>) -> Result; + fn get_key(raw_key: Box<[u8]>) -> Result { + bincode::deserialize(&raw_key).map_err(DBError::Bincode) + } } // @@ -139,14 +144,14 @@ where C: Column + ColumnName, { pub fn get_bytes(&self, key: &C::Index) -> Result>> { - self.backend.get_cf(self.handle(), &C::key(key)) + self.backend.get_cf(self.handle()?, &C::key(key)?) } pub fn put_bytes(&self, key: &C::Index, value: &[u8]) -> Result<()> { - self.backend.put_cf(self.handle(), &C::key(key), value) + self.backend.put_cf(self.handle()?, &C::key(key)?, value) } - pub fn handle(&self) -> &ColumnFamily { + pub fn handle(&self) -> Result<&ColumnFamily> { self.backend.cf_handle(C::NAME) } } @@ -170,20 +175,25 @@ where } pub fn delete(&self, key: &C::Index) -> Result<()> { - self.backend.delete_cf(self.handle(), &C::key(key)) + self.backend.delete_cf(self.handle()?, &C::key(key)?) } pub fn iter( &self, from: Option, limit: usize, - ) -> impl Iterator + '_ { - let index = from.as_ref().map(|i| C::key(i)).unwrap_or_default(); + ) -> Result + '_> { + let index = from + .as_ref() + .map(|i| C::key(i)) + .transpose()? + .unwrap_or_default(); let iterator_mode = from.map_or(IteratorMode::Start, |_| { IteratorMode::From(&index, rocksdb::Direction::Forward) }); - self.backend - .iterator_cf::(self.handle(), iterator_mode) + let it = self + .backend + .iterator_cf::(self.handle()?, iterator_mode) .filter_map(|k| { k.ok().and_then(|(k, v)| { let value = bincode::deserialize(&v).ok()?; @@ -191,7 +201,8 @@ where Some((key, value)) }) }) - .take(limit) + .take(limit); + Ok(it) } } diff --git a/lib/ain-evm/src/storage/block_store.rs b/lib/ain-evm/src/storage/block_store.rs index b3f1be5ae52..51a52018d5b 100644 --- a/lib/ain-evm/src/storage/block_store.rs +++ b/lib/ain-evm/src/storage/block_store.rs @@ -128,7 +128,7 @@ impl BlockStorage for BlockStore { fn get_latest_block(&self) -> Result> { let latest_block_cf = self.column::(); - match latest_block_cf.get(&"")? { + match latest_block_cf.get(&String::new())? { Some(block_number) => self.get_block_by_number(&block_number), None => Ok(None), } @@ -138,7 +138,8 @@ impl BlockStorage for BlockStore { if let Some(block) = block { let latest_block_cf = self.column::(); let block_number = block.header.number; - latest_block_cf.put(&"", &block_number)?; + // latest_block_cf.put(&"", &block_number)?; + latest_block_cf.put(&String::new(), &block_number)?; } Ok(()) } @@ -226,15 +227,16 @@ impl Rollback for BlockStore { if let Some(block) = self.get_block_by_hash(&block.header.parent_hash)? { let latest_block_cf = self.column::(); - latest_block_cf.put(&"", &block.header.number)?; + // latest_block_cf.put(&"", &block.header.number)?; + latest_block_cf.put(&String::new(), &block.header.number)?; } let logs_cf = self.column::(); logs_cf.delete(&block.header.number)?; let block_deployed_codes_cf = self.column::(); - let mut iter = - block_deployed_codes_cf.iter(Some((block.header.number, H160::zero())), usize::MAX); + let mut iter = block_deployed_codes_cf + .iter(Some((block.header.number, H160::zero())), usize::MAX)?; let address_codes_cf = self.column::(); for ((block_number, address), hash) in &mut iter { @@ -323,7 +325,7 @@ impl BlockStore { let response_max_size = usize::try_from(ain_cpp_imports::get_max_response_byte_size()) .map_err(|_| format_err!("failed to convert response size limit to usize"))?; - for (k, v) in self.column::().iter(from, limit) { + for (k, v) in self.column::().iter(from, limit)? { if out.len() > response_max_size { return Err(format_err!("exceed response max size limit").into()); } diff --git a/lib/ain-evm/src/storage/db.rs b/lib/ain-evm/src/storage/db.rs index fbe168359c7..f475ecf3a2f 100644 --- a/lib/ain-evm/src/storage/db.rs +++ b/lib/ain-evm/src/storage/db.rs @@ -115,119 +115,42 @@ pub const COLUMN_NAMES: [&'static str; 8] = [ impl Column for columns::Transactions { type Index = H256; - - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - Ok(Self::Index::from_slice(&raw_key)) - } } impl Column for columns::Blocks { type Index = U256; - - fn key(index: &Self::Index) -> Vec { - let mut bytes = [0_u8; 32]; - index.to_big_endian(&mut bytes); - bytes.to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - Ok(Self::Index::from(&*raw_key)) - } } impl Column for columns::Receipts { type Index = H256; - - fn key(index: &Self::Index) -> Vec { - index.to_fixed_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - Ok(Self::Index::from_slice(&raw_key)) - } } impl Column for columns::BlockMap { type Index = H256; - - fn key(index: &Self::Index) -> Vec { - index.to_fixed_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - Ok(Self::Index::from_slice(&raw_key)) - } } impl Column for columns::LatestBlockNumber { - type Index = &'static str; + type Index = String; - fn key(_index: &Self::Index) -> Vec { - b"latest".to_vec() + fn key(_index: &Self::Index) -> Result, DBError> { + Ok(b"latest".to_vec()) } fn get_key(_raw_key: Box<[u8]>) -> Result { - Ok("latest") + Ok(String::from("latest")) } } impl Column for columns::AddressLogsMap { type Index = U256; - - fn key(index: &Self::Index) -> Vec { - let mut bytes = [0_u8; 32]; - index.to_big_endian(&mut bytes); - bytes.to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - Ok(Self::Index::from(&*raw_key)) - } } impl Column for columns::AddressCodeMap { type Index = (H160, H256); - - fn key(index: &Self::Index) -> Vec { - let mut bytes = Vec::with_capacity(20 + 32); - bytes.extend_from_slice(&index.0.to_fixed_bytes()); - bytes.extend_from_slice(&index.1.to_fixed_bytes()); - bytes - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - let address = H160::from_slice(&raw_key[..20]); - let code_hash = H256::from_slice(&raw_key[20..]); - Ok((address, code_hash)) - } } impl Column for columns::BlockDeployedCodeHashes { type Index = (U256, H160); - - fn key(index: &Self::Index) -> Vec { - let mut u256_bytes = [0_u8; 32]; - index.0.to_big_endian(&mut u256_bytes); - - let mut bytes = Vec::with_capacity(32 + 20); - bytes.extend_from_slice(&u256_bytes); - bytes.extend_from_slice(&index.1.to_fixed_bytes()); - bytes - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - let u256_bytes = &raw_key[0..32]; - let h160_bytes = &raw_key[32..52]; - - let u256 = U256::from_big_endian(u256_bytes); - let h160 = H160::from_slice(h160_bytes); - - Ok((u256, h160)) - } } // diff --git a/lib/ain-ocean/src/storage/columns/block.rs b/lib/ain-ocean/src/storage/columns/block.rs index f44085526bd..e1398f353c5 100644 --- a/lib/ain-ocean/src/storage/columns/block.rs +++ b/lib/ain-ocean/src/storage/columns/block.rs @@ -13,14 +13,6 @@ impl ColumnName for Block { impl Column for Block { type Index = BlockHash; - - fn key(index: &Self::Index) -> Vec { - index.as_byte_array().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - Self::Index::from_slice(&raw_key).map_err(|_| DBError::ParseKey) - } } impl TypedColumn for Block { @@ -37,21 +29,6 @@ impl ColumnName for BlockByHeight { impl Column for BlockByHeight { type Index = u32; - - fn key(index: &Self::Index) -> Vec { - index.to_be_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - if raw_key.len() != 4 { - return Err(DBError::Custom(format_err!("Wrong key length"))); - } - - let height_bytes = <[u8; 4]>::try_from(&raw_key[..]) - .map_err(|_| DBError::Custom(format_err!("Invalid height bytes")))?; - - Ok(u32::from_be_bytes(height_bytes)) - } } impl TypedColumn for BlockByHeight { diff --git a/lib/ain-ocean/src/storage/columns/masternode.rs b/lib/ain-ocean/src/storage/columns/masternode.rs index c99fbe0ac61..8b66e520b9f 100644 --- a/lib/ain-ocean/src/storage/columns/masternode.rs +++ b/lib/ain-ocean/src/storage/columns/masternode.rs @@ -13,14 +13,6 @@ impl ColumnName for Masternode { impl Column for Masternode { type Index = Txid; - - fn key(index: &Self::Index) -> Vec { - index.as_byte_array().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - Self::Index::from_slice(&raw_key).map_err(|_| DBError::ParseKey) - } } impl TypedColumn for Masternode { @@ -37,32 +29,6 @@ impl ColumnName for MasternodeByHeight { impl Column for MasternodeByHeight { type Index = (u32, usize); - - fn key(index: &Self::Index) -> Vec { - let height_bytes = index.0.to_be_bytes(); - let txno_bytes = index.1.to_be_bytes(); - - let height_slice: &[u8] = AsRef::<[u8]>::as_ref(&height_bytes); - let txno_slice: &[u8] = AsRef::<[u8]>::as_ref(&txno_bytes); - - [height_slice, txno_slice].concat() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - if raw_key.len() != 12 { - return Err(DBError::Custom(format_err!("Wrong key length"))); - } - - let height_bytes = <[u8; 4]>::try_from(&raw_key[..4]) - .map_err(|_| DBError::Custom(format_err!("Invalid height bytes")))?; - let txno_bytes = <[u8; 8]>::try_from(&raw_key[4..]) - .map_err(|_| DBError::Custom(format_err!("Invalid txno bytes")))?; - - let height = u32::from_be_bytes(height_bytes); - let txno = usize::from_be_bytes(txno_bytes); - - Ok((height, txno)) - } } impl TypedColumn for MasternodeByHeight { diff --git a/lib/ain-ocean/src/storage/columns/masternode_stats.rs b/lib/ain-ocean/src/storage/columns/masternode_stats.rs index 217195912af..3382de7df46 100644 --- a/lib/ain-ocean/src/storage/columns/masternode_stats.rs +++ b/lib/ain-ocean/src/storage/columns/masternode_stats.rs @@ -13,14 +13,6 @@ impl ColumnName for MasternodeStats { impl Column for MasternodeStats { type Index = Txid; - - fn key(index: &Self::Index) -> Vec { - index.as_byte_array().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - Self::Index::from_slice(&raw_key).map_err(|_| DBError::ParseKey) - } } impl TypedColumn for MasternodeStats { diff --git a/lib/ain-ocean/src/storage/columns/mod.rs b/lib/ain-ocean/src/storage/columns/mod.rs index 0d5dbdfddb3..1da163fbadf 100644 --- a/lib/ain-ocean/src/storage/columns/mod.rs +++ b/lib/ain-ocean/src/storage/columns/mod.rs @@ -41,7 +41,7 @@ pub use transaction_vin::*; pub use transaction_vout::*; pub use vault_auction_history::*; -pub const COLUMN_NAMES: [&'static str; 21] = [ +pub const COLUMN_NAMES: [&'static str; 22] = [ block::Block::NAME, masternode_stats::MasternodeStats::NAME, masternode::Masternode::NAME, @@ -63,4 +63,5 @@ pub const COLUMN_NAMES: [&'static str; 21] = [ transaction_vin::TransactionVin::NAME, transaction_vout::TransactionVout::NAME, vault_auction_history::VaultAuctionHistory::NAME, + vault_auction_history::VaultAuctionHistoryByHeight::NAME, ]; diff --git a/lib/ain-ocean/src/storage/columns/oracle_history.rs b/lib/ain-ocean/src/storage/columns/oracle_history.rs index 29a21d36eed..f42cf36713a 100644 --- a/lib/ain-ocean/src/storage/columns/oracle_history.rs +++ b/lib/ain-ocean/src/storage/columns/oracle_history.rs @@ -1,8 +1,4 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; - -use crate::model; +use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] pub struct OracleHistory; @@ -13,14 +9,6 @@ impl ColumnName for OracleHistory { impl Column for OracleHistory { type Index = String; - - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } - } } impl TypedColumn for OracleHistory { diff --git a/lib/ain-ocean/src/storage/columns/oracle_price_active.rs b/lib/ain-ocean/src/storage/columns/oracle_price_active.rs index 3a5d8da071e..47222c6d961 100644 --- a/lib/ain-ocean/src/storage/columns/oracle_price_active.rs +++ b/lib/ain-ocean/src/storage/columns/oracle_price_active.rs @@ -1,8 +1,4 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; - -use crate::model::{self, Oracle}; +use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] pub struct OraclePriceActive; @@ -13,14 +9,6 @@ impl ColumnName for OraclePriceActive { impl Column for OraclePriceActive { type Index = String; - - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } - } } impl TypedColumn for OraclePriceActive { diff --git a/lib/ain-ocean/src/storage/columns/oracle_price_aggregated.rs b/lib/ain-ocean/src/storage/columns/oracle_price_aggregated.rs index 7635952aabe..ff4b0a32627 100644 --- a/lib/ain-ocean/src/storage/columns/oracle_price_aggregated.rs +++ b/lib/ain-ocean/src/storage/columns/oracle_price_aggregated.rs @@ -1,8 +1,4 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; - -use crate::model; +use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] pub struct OraclePriceAggregated; @@ -13,14 +9,6 @@ impl ColumnName for OraclePriceAggregated { impl Column for OraclePriceAggregated { type Index = String; - - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } - } } impl TypedColumn for OraclePriceAggregated { diff --git a/lib/ain-ocean/src/storage/columns/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/storage/columns/oracle_price_aggregated_interval.rs index 538f7b9d0fa..f4d925cc410 100644 --- a/lib/ain-ocean/src/storage/columns/oracle_price_aggregated_interval.rs +++ b/lib/ain-ocean/src/storage/columns/oracle_price_aggregated_interval.rs @@ -1,8 +1,4 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; - -use crate::model; +use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] pub struct OraclePriceAggregatedInterval; @@ -13,14 +9,6 @@ impl ColumnName for OraclePriceAggregatedInterval { impl Column for OraclePriceAggregatedInterval { type Index = String; - - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } - } } impl TypedColumn for OraclePriceAggregatedInterval { diff --git a/lib/ain-ocean/src/storage/columns/oracle_price_feed.rs b/lib/ain-ocean/src/storage/columns/oracle_price_feed.rs index efc07db85fa..4a546eadc94 100644 --- a/lib/ain-ocean/src/storage/columns/oracle_price_feed.rs +++ b/lib/ain-ocean/src/storage/columns/oracle_price_feed.rs @@ -1,8 +1,4 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; - -use crate::model; +use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] pub struct OraclePriceFeed; @@ -13,14 +9,6 @@ impl ColumnName for OraclePriceFeed { impl Column for OraclePriceFeed { type Index = String; - - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } - } } impl TypedColumn for OraclePriceFeed { diff --git a/lib/ain-ocean/src/storage/columns/oracle_token_currency.rs b/lib/ain-ocean/src/storage/columns/oracle_token_currency.rs index 57c7b348f6b..b315cd259f8 100644 --- a/lib/ain-ocean/src/storage/columns/oracle_token_currency.rs +++ b/lib/ain-ocean/src/storage/columns/oracle_token_currency.rs @@ -1,8 +1,4 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; - -use crate::model; +use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] pub struct OracleTokenCurrency; @@ -13,14 +9,6 @@ impl ColumnName for OracleTokenCurrency { impl Column for OracleTokenCurrency { type Index = String; - - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } - } } impl TypedColumn for OracleTokenCurrency { diff --git a/lib/ain-ocean/src/storage/columns/pool_swap.rs b/lib/ain-ocean/src/storage/columns/pool_swap.rs index 15d3d3efcf7..1b79dda32a1 100644 --- a/lib/ain-ocean/src/storage/columns/pool_swap.rs +++ b/lib/ain-ocean/src/storage/columns/pool_swap.rs @@ -1,8 +1,4 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; - -use crate::model; +use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] pub struct PoolSwap; @@ -13,14 +9,6 @@ impl ColumnName for PoolSwap { impl Column for PoolSwap { type Index = String; - - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } - } } impl TypedColumn for PoolSwap { diff --git a/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs b/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs index b14503804b3..090fcec8277 100644 --- a/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs +++ b/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs @@ -1,7 +1,4 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; - -use crate::model; +use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] pub struct PoolSwapAggregated; @@ -12,14 +9,6 @@ impl ColumnName for PoolSwapAggregated { impl Column for PoolSwapAggregated { type Index = String; - - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } - } } impl TypedColumn for PoolSwapAggregated { diff --git a/lib/ain-ocean/src/storage/columns/price_ticker.rs b/lib/ain-ocean/src/storage/columns/price_ticker.rs index 2a377aec72a..a92c44cdac9 100644 --- a/lib/ain-ocean/src/storage/columns/price_ticker.rs +++ b/lib/ain-ocean/src/storage/columns/price_ticker.rs @@ -1,8 +1,4 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; - -use crate::model; +use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] pub struct PriceTicker; @@ -13,14 +9,6 @@ impl ColumnName for PriceTicker { impl Column for PriceTicker { type Index = String; - - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } - } } impl TypedColumn for PriceTicker { diff --git a/lib/ain-ocean/src/storage/columns/raw_block.rs b/lib/ain-ocean/src/storage/columns/raw_block.rs index ddbaee2ee5d..aa9ae79d1a7 100644 --- a/lib/ain-ocean/src/storage/columns/raw_block.rs +++ b/lib/ain-ocean/src/storage/columns/raw_block.rs @@ -1,5 +1,5 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use bitcoin::{hashes::Hash, BlockHash}; +use ain_db::{Column, ColumnName, TypedColumn}; +use bitcoin::BlockHash; #[derive(Debug)] pub struct RawBlock; @@ -10,14 +10,6 @@ impl ColumnName for RawBlock { impl Column for RawBlock { type Index = BlockHash; - - fn key(index: &Self::Index) -> Vec { - index.as_byte_array().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - Self::Index::from_slice(&raw_key).map_err(|_| DBError::ParseKey) - } } impl TypedColumn for RawBlock { diff --git a/lib/ain-ocean/src/storage/columns/script_activity.rs b/lib/ain-ocean/src/storage/columns/script_activity.rs index a6e14b815e7..c47c692b5bd 100644 --- a/lib/ain-ocean/src/storage/columns/script_activity.rs +++ b/lib/ain-ocean/src/storage/columns/script_activity.rs @@ -1,8 +1,4 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; - -use crate::model; +use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] pub struct ScriptActivity; @@ -13,14 +9,6 @@ impl ColumnName for ScriptActivity { impl Column for ScriptActivity { type Index = String; - - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } - } } impl TypedColumn for ScriptActivity { diff --git a/lib/ain-ocean/src/storage/columns/script_aggregation.rs b/lib/ain-ocean/src/storage/columns/script_aggregation.rs index c3ba805e4fa..494911aa3fb 100644 --- a/lib/ain-ocean/src/storage/columns/script_aggregation.rs +++ b/lib/ain-ocean/src/storage/columns/script_aggregation.rs @@ -1,8 +1,4 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; - -use crate::model; +use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] pub struct ScriptAggregation; @@ -13,14 +9,6 @@ impl ColumnName for ScriptAggregation { impl Column for ScriptAggregation { type Index = String; - - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } - } } impl TypedColumn for ScriptAggregation { diff --git a/lib/ain-ocean/src/storage/columns/script_unspent.rs b/lib/ain-ocean/src/storage/columns/script_unspent.rs index f07e5ed6a10..2862184bfe0 100644 --- a/lib/ain-ocean/src/storage/columns/script_unspent.rs +++ b/lib/ain-ocean/src/storage/columns/script_unspent.rs @@ -1,8 +1,4 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; - -use crate::model; +use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] pub struct ScriptUnspent; @@ -13,14 +9,6 @@ impl ColumnName for ScriptUnspent { impl Column for ScriptUnspent { type Index = String; - - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } - } } impl TypedColumn for ScriptUnspent { diff --git a/lib/ain-ocean/src/storage/columns/transaction.rs b/lib/ain-ocean/src/storage/columns/transaction.rs index 0cb76ed4eab..8c2052f21a4 100644 --- a/lib/ain-ocean/src/storage/columns/transaction.rs +++ b/lib/ain-ocean/src/storage/columns/transaction.rs @@ -1,8 +1,4 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; - -use crate::model; +use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] pub struct Transaction; @@ -13,14 +9,6 @@ impl ColumnName for Transaction { impl Column for Transaction { type Index = String; - - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } - } } impl TypedColumn for Transaction { diff --git a/lib/ain-ocean/src/storage/columns/transaction_vin.rs b/lib/ain-ocean/src/storage/columns/transaction_vin.rs index 2cd118ca826..a8149b1e5b4 100644 --- a/lib/ain-ocean/src/storage/columns/transaction_vin.rs +++ b/lib/ain-ocean/src/storage/columns/transaction_vin.rs @@ -1,8 +1,4 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; - -use crate::model; +use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] pub struct TransactionVin; @@ -13,14 +9,6 @@ impl ColumnName for TransactionVin { impl Column for TransactionVin { type Index = String; - - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } - } } impl TypedColumn for TransactionVin { diff --git a/lib/ain-ocean/src/storage/columns/transaction_vout.rs b/lib/ain-ocean/src/storage/columns/transaction_vout.rs index 206841073e3..7de7b41c183 100644 --- a/lib/ain-ocean/src/storage/columns/transaction_vout.rs +++ b/lib/ain-ocean/src/storage/columns/transaction_vout.rs @@ -1,9 +1,4 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; - -use crate::model; - +use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] pub struct TransactionVout; @@ -13,14 +8,6 @@ impl ColumnName for TransactionVout { impl Column for TransactionVout { type Index = String; - - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } - } } impl TypedColumn for TransactionVout { diff --git a/lib/ain-ocean/src/storage/columns/vault_auction_history.rs b/lib/ain-ocean/src/storage/columns/vault_auction_history.rs index 5087a2f0925..d9a78e4e9d3 100644 --- a/lib/ain-ocean/src/storage/columns/vault_auction_history.rs +++ b/lib/ain-ocean/src/storage/columns/vault_auction_history.rs @@ -12,17 +12,25 @@ impl ColumnName for VaultAuctionHistory { } impl Column for VaultAuctionHistory { - type Index = String; + type Index = model::AuctionHistoryKey; +} + +impl TypedColumn for VaultAuctionHistory { + type Type = model::VaultAuctionBatchHistory; +} - fn key(index: &Self::Index) -> Vec { - index.as_bytes().to_vec() - } +// Secondary index by block height and txno +#[derive(Debug)] +pub struct VaultAuctionHistoryByHeight; - fn get_key(raw_key: Box<[u8]>) -> Result { - unsafe { Ok(Self::Index::from_utf8_unchecked(raw_key.to_vec())) } - } +impl ColumnName for VaultAuctionHistoryByHeight { + const NAME: &'static str = "vault_auction_history_by_height"; } -impl TypedColumn for VaultAuctionHistory { - type Type = String; +impl Column for VaultAuctionHistoryByHeight { + type Index = model::AuctionHistoryByHeightKey; +} + +impl TypedColumn for VaultAuctionHistoryByHeight { + type Type = model::AuctionHistoryKey; } From 1d56342ba5f541f65619f1a41847ecbcc1639e4b Mon Sep 17 00:00:00 2001 From: jouzo Date: Thu, 4 Jan 2024 10:57:48 +0100 Subject: [PATCH 020/185] Fix build --- .../src/model/vault_auction_batch_history.rs | 26 +++++++++++-------- lib/ain-ocean/src/storage/ocean_store.rs | 3 ++- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/lib/ain-ocean/src/model/vault_auction_batch_history.rs b/lib/ain-ocean/src/model/vault_auction_batch_history.rs index 614e96a41ca..d4885ed7297 100644 --- a/lib/ain-ocean/src/model/vault_auction_batch_history.rs +++ b/lib/ain-ocean/src/model/vault_auction_batch_history.rs @@ -1,24 +1,28 @@ +use bitcoin::{Amount, BlockHash, ScriptBuf, Txid}; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Default)] +pub type AuctionHistoryKey = (Txid, u32, Txid); +pub type AuctionHistoryByHeightKey = (Txid, u32, u32, usize); + +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct VaultAuctionBatchHistory { pub id: String, pub key: String, pub sort: String, - pub vault_id: String, - pub index: i32, - pub from: String, - pub amount: String, - pub token_id: i32, + pub vault_id: Txid, + pub index: usize, + pub from: ScriptBuf, + pub amount: i64, + pub token_id: u64, pub block: VaultAuctionBatchHistoryBlock, } -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct VaultAuctionBatchHistoryBlock { - pub hash: String, - pub height: i32, - pub time: i32, - pub median_time: i32, + pub hash: BlockHash, + pub height: u32, + pub time: u64, + pub median_time: u64, } diff --git a/lib/ain-ocean/src/storage/ocean_store.rs b/lib/ain-ocean/src/storage/ocean_store.rs index 32a118e2633..20375235890 100644 --- a/lib/ain-ocean/src/storage/ocean_store.rs +++ b/lib/ain-ocean/src/storage/ocean_store.rs @@ -58,6 +58,7 @@ impl OceanStore { limit: usize, ) -> Result> { let col = self.column::(); - Ok(col.iter(from, limit).collect()) + let list = col.iter(from, limit)?.collect(); + Ok(list) } } From 274beca5d8739b409f00fa65a1e9736fc3c52ebc Mon Sep 17 00:00:00 2001 From: jouzo Date: Fri, 5 Jan 2024 10:43:50 +0100 Subject: [PATCH 021/185] Add 404 handler --- lib/ain-ocean/src/api/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index a81ea84f9ec..b294179f7e7 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -19,6 +19,10 @@ async fn ocean_not_activated() -> impl IntoResponse { (StatusCode::FORBIDDEN, "Ocean is not activated") } +async fn not_found() -> impl IntoResponse { + (StatusCode::NOT_FOUND, "Not found") +} + pub fn ocean_router() -> Router { if !ain_cpp_imports::is_ocean_rest_enabled() { return Router::new().route("/*path", get(ocean_not_activated)); @@ -38,4 +42,5 @@ pub fn ocean_router() -> Router { .nest("/tokens", tokens::router()) .nest("/transactions", transactions::router()) .nest("/blocks", block::router()) + .fallback(not_found) } From 9f27d776714525314f12b9aabb8c9b0203959a69 Mon Sep 17 00:00:00 2001 From: jouzo Date: Fri, 5 Jan 2024 12:00:33 +0100 Subject: [PATCH 022/185] Cleanup db iter method --- lib/ain-db/src/lib.rs | 20 ++++------ lib/ain-evm/src/storage/block_store.rs | 12 +++--- lib/ain-evm/src/storage/db.rs | 19 ++-------- lib/ain-grpc/src/lib.rs | 1 - lib/ain-macros/src/lib.rs | 29 +++++---------- lib/ain-ocean/src/api/masternode.rs | 13 ++++--- lib/ain-ocean/src/error.rs | 3 ++ lib/ain-ocean/src/indexer/masternode.rs | 11 +++--- lib/ain-ocean/src/lib.rs | 2 + lib/ain-ocean/src/repository/block.rs | 25 ++++++++++--- lib/ain-ocean/src/repository/masternode.rs | 17 +++++++-- .../src/repository/masternode_stats.rs | 9 ++++- lib/ain-ocean/src/repository/mod.rs | 7 +++- lib/ain-ocean/src/repository/raw_block.rs | 9 ++++- lib/ain-ocean/src/storage/columns/block.rs | 5 +-- .../src/storage/columns/masternode.rs | 5 +-- .../src/storage/columns/masternode_stats.rs | 5 +-- .../storage/columns/vault_auction_history.rs | 4 +- lib/ain-ocean/src/storage/ocean_store.rs | 37 +------------------ 19 files changed, 104 insertions(+), 129 deletions(-) diff --git a/lib/ain-db/src/lib.rs b/lib/ain-db/src/lib.rs index fa4b424ced7..45fffbd2bce 100644 --- a/lib/ain-db/src/lib.rs +++ b/lib/ain-db/src/lib.rs @@ -181,8 +181,7 @@ where pub fn iter( &self, from: Option, - limit: usize, - ) -> Result + '_> { + ) -> Result> + '_> { let index = from .as_ref() .map(|i| C::key(i)) @@ -191,18 +190,15 @@ where let iterator_mode = from.map_or(IteratorMode::Start, |_| { IteratorMode::From(&index, rocksdb::Direction::Forward) }); - let it = self + Ok(self .backend .iterator_cf::(self.handle()?, iterator_mode) - .filter_map(|k| { - k.ok().and_then(|(k, v)| { - let value = bincode::deserialize(&v).ok()?; - let key = C::get_key(k).ok()?; - Some((key, value)) - }) - }) - .take(limit); - Ok(it) + .map(|k| { + let (key, value) = k?; + let value = bincode::deserialize(&value)?; + let key = C::get_key(key)?; + Ok((key, value)) + })) } } diff --git a/lib/ain-evm/src/storage/block_store.rs b/lib/ain-evm/src/storage/block_store.rs index 51a52018d5b..dee2042b5df 100644 --- a/lib/ain-evm/src/storage/block_store.rs +++ b/lib/ain-evm/src/storage/block_store.rs @@ -235,11 +235,11 @@ impl Rollback for BlockStore { logs_cf.delete(&block.header.number)?; let block_deployed_codes_cf = self.column::(); - let mut iter = block_deployed_codes_cf - .iter(Some((block.header.number, H160::zero())), usize::MAX)?; - let address_codes_cf = self.column::(); - for ((block_number, address), hash) in &mut iter { + + for item in block_deployed_codes_cf.iter(Some((block.header.number, H160::zero())))? { + let ((block_number, address), hash) = item?; + if block_number == block.header.number { address_codes_cf.delete(&(address, hash))?; block_deployed_codes_cf.delete(&(block.header.number, address))?; @@ -325,7 +325,9 @@ impl BlockStore { let response_max_size = usize::try_from(ain_cpp_imports::get_max_response_byte_size()) .map_err(|_| format_err!("failed to convert response size limit to usize"))?; - for (k, v) in self.column::().iter(from, limit)? { + for item in self.column::().iter(from)?.take(limit) { + let (k, v) = item?; + if out.len() > response_max_size { return Err(format_err!("exceed response max size limit").into()); } diff --git a/lib/ain-evm/src/storage/db.rs b/lib/ain-evm/src/storage/db.rs index f475ecf3a2f..c4176b471b4 100644 --- a/lib/ain-evm/src/storage/db.rs +++ b/lib/ain-evm/src/storage/db.rs @@ -1,21 +1,8 @@ -use std::{ - collections::HashMap, - fmt::Debug, - iter::Iterator, - marker::PhantomData, - path::{Path, PathBuf}, - sync::Arc, -}; - -use ain_db::{Column, ColumnName, DBError, LedgerColumn, TypedColumn}; -use bincode; +use std::collections::HashMap; + +use ain_db::{Column, ColumnName, DBError, TypedColumn}; use ethereum::{BlockAny, TransactionV2}; use ethereum_types::{H160, H256, U256}; -use rocksdb::{ - BlockBasedOptions, Cache, ColumnFamily, ColumnFamilyDescriptor, DBIterator, IteratorMode, - Options, DB, -}; -use serde::{de::DeserializeOwned, Serialize}; use crate::{log::LogIndex, receipt::Receipt}; diff --git a/lib/ain-grpc/src/lib.rs b/lib/ain-grpc/src/lib.rs index de5c7ca7a09..763dcfcb146 100644 --- a/lib/ain-grpc/src/lib.rs +++ b/lib/ain-grpc/src/lib.rs @@ -127,7 +127,6 @@ pub fn init_network_rest_ocean(addr: String) -> Result<()> { let addr = addr.as_str().parse::()?; let runtime = &SERVICES; - let handle = runtime.tokio_runtime.clone(); let listener = runtime .tokio_runtime .block_on(tokio::net::TcpListener::bind(addr))?; diff --git a/lib/ain-macros/src/lib.rs b/lib/ain-macros/src/lib.rs index a219dd81217..02ee4917ea3 100644 --- a/lib/ain-macros/src/lib.rs +++ b/lib/ain-macros/src/lib.rs @@ -54,10 +54,9 @@ pub fn ffi_fallible(_attr: TokenStream, item: TokenStream) -> TokenStream { TokenStream::from(expanded) } -fn parse_repository_attr(attr: &Attribute) -> syn::Result<(String, String, String)> { +fn parse_repository_attr(attr: &Attribute) -> syn::Result<(String, String)> { let mut key_type = None; let mut value_type = None; - let mut column_type = None; attr.parse_nested_meta(|meta| { if meta.path.is_ident("K") { @@ -70,18 +69,12 @@ fn parse_repository_attr(attr: &Attribute) -> syn::Result<(String, String, Strin let s: LitStr = val.parse()?; value_type = Some(s); } - if meta.path.is_ident("Column") { - let val = meta.value()?; - let s: LitStr = val.parse()?; - column_type = Some(s); - } Ok(()) })?; Ok(( key_type.expect("Missing attribute 'K'").value(), value_type.expect("Missing attribute 'V'").value(), - column_type.expect("Missing attribute 'column'").value(), )) } @@ -92,39 +85,37 @@ pub fn repository_derive(input: TokenStream) -> TokenStream { let mut key_type_str = String::new(); let mut value_type_str = String::new(); - let mut column_type_str = String::new(); for attr in &input.attrs { if attr.path().is_ident("repository") { - let (key, value, column) = + let (key, value) = parse_repository_attr(attr).expect("Error parsing 'repository' attribute"); key_type_str = key; value_type_str = value; - column_type_str = column; } } let key_type_ident = syn::Ident::new(&key_type_str, proc_macro2::Span::call_site()); let value_type_ident = syn::Ident::new(&value_type_str, proc_macro2::Span::call_site()); - let column_type_ident = syn::Ident::new(&column_type_str, proc_macro2::Span::call_site()); - println!("column_type_ident : {:?}", column_type_ident); + // Generate the implementation let expanded = quote! { impl RepositoryOps<#key_type_ident, #value_type_ident> for #name { - fn get(&self, id: #key_type_ident) -> Result> { - Ok(self.store.get::(id)?) + fn get(&self, id: &#key_type_ident) -> Result> { + Ok(self.col.get(id)?) } fn put(&self, id: &#key_type_ident, item: &#value_type_ident) -> Result<()> { - Ok(self.store.put::(id, item)?) + Ok(self.col.put(id, item)?) } fn delete(&self, id: &#key_type_ident) -> Result<()> { - Ok(self.store.delete::(id)?) + Ok(self.col.delete(id)?) } - fn list(&self, from: Option<#key_type_ident>, limit: usize) -> Result> { - Ok(self.store.list::(from, limit)?) + fn list(&self, from: Option<#key_type_ident>) -> Result>> + { + Ok(self.col.iter(from)?) } } }; diff --git a/lib/ain-ocean/src/api/masternode.rs b/lib/ain-ocean/src/api/masternode.rs index 0fe0d38b59b..e2872415c57 100644 --- a/lib/ain-ocean/src/api/masternode.rs +++ b/lib/ain-ocean/src/api/masternode.rs @@ -108,13 +108,14 @@ async fn list_masternodes( let masternodes = SERVICES .masternode .by_height - .list(next, query.size)? - .iter() - .map(|(_, id)| { + .list(next)? + .take(query.size) + .map(|item| { + let (_, id) = item?; let mn = SERVICES .masternode .by_id - .get(*id)? + .get(&id)? .ok_or("Missing masternode index")?; Ok(mn.into()) @@ -124,7 +125,7 @@ async fn list_masternodes( Ok(Json(ApiPagedResponse::of( masternodes, query.size, - |masternode| masternode.clone().id, + |masternode| masternode.clone().sort, ))) } @@ -134,7 +135,7 @@ async fn get_masternode( let mn = SERVICES .masternode .by_id - .get(masternode_id)? + .get(&masternode_id)? .map(Into::into); Ok(Json(mn)) diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index e894520fb90..1f08d709a28 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -1,5 +1,6 @@ use std::num::ParseIntError; +use ain_db::DBError; use axum::{ http::StatusCode, response::{IntoResponse, Response}, @@ -15,6 +16,8 @@ pub enum OceanError { HexToArrayError(#[from] HexToArrayError), #[error("Ocean: ParseIntError error: {0:?}")] ParseIntError(#[from] ParseIntError), + #[error("Ocean: DBError error: {0:?}")] + DBError(#[from] DBError), #[error(transparent)] Other(#[from] anyhow::Error), } diff --git a/lib/ain-ocean/src/indexer/masternode.rs b/lib/ain-ocean/src/indexer/masternode.rs index 2b60f84c6ca..0ca2e6d0ff9 100644 --- a/lib/ain-ocean/src/indexer/masternode.rs +++ b/lib/ain-ocean/src/indexer/masternode.rs @@ -51,8 +51,7 @@ impl Index for CreateMasternode { fn invalidate(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { debug!("[CreateMasternode] Invalidating..."); - let txid = tx.txid(); - SERVICES.masternode.by_id.delete(&txid)?; + SERVICES.masternode.by_id.delete(&tx.txid())?; SERVICES.masternode.by_height.delete(&(ctx.height, idx)) } } @@ -60,7 +59,7 @@ impl Index for CreateMasternode { impl Index for UpdateMasternode { fn index(&self, _ctx: &BlockContext, tx: Transaction, _idx: usize) -> Result<()> { debug!("[UpdateMasternode] Indexing..."); - if let Some(mut mn) = SERVICES.masternode.by_id.get(self.node_id)? { + if let Some(mut mn) = SERVICES.masternode.by_id.get(&self.node_id)? { mn.history.push(HistoryItem { owner_address: mn.owner_address.clone(), operator_address: mn.operator_address.clone(), @@ -86,7 +85,7 @@ impl Index for UpdateMasternode { fn invalidate(&self, _ctx: &BlockContext, _tx: Transaction, _idx: usize) -> Result<()> { debug!("[UpdateMasternode] Invalidating..."); - if let Some(mut mn) = SERVICES.masternode.by_id.get(self.node_id)? { + if let Some(mut mn) = SERVICES.masternode.by_id.get(&self.node_id)? { if let Some(history_item) = mn.history.pop() { mn.owner_address = history_item.owner_address; mn.operator_address = history_item.operator_address; @@ -101,7 +100,7 @@ impl Index for UpdateMasternode { impl Index for ResignMasternode { fn index(&self, ctx: &BlockContext, tx: Transaction, _idx: usize) -> Result<()> { debug!("[ResignMasternode] Indexing..."); - if let Some(mn) = SERVICES.masternode.by_id.get(self.node_id)? { + if let Some(mn) = SERVICES.masternode.by_id.get(&self.node_id)? { SERVICES.masternode.by_id.put( &self.node_id, &Masternode { @@ -116,7 +115,7 @@ impl Index for ResignMasternode { fn invalidate(&self, _ctx: &BlockContext, _tx: Transaction, _idx: usize) -> Result<()> { debug!("[ResignMasternode] Invalidating..."); - if let Some(mn) = SERVICES.masternode.by_id.get(self.node_id)? { + if let Some(mn) = SERVICES.masternode.by_id.get(&self.node_id)? { SERVICES.masternode.by_id.put( &self.node_id, &Masternode { diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index a69b2fe0f14..27aa684de76 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(return_position_impl_trait_in_trait)] + pub mod api_paged_response; pub mod api_query; pub mod error; diff --git a/lib/ain-ocean/src/repository/block.rs b/lib/ain-ocean/src/repository/block.rs index 75025671b6f..21eea96c683 100644 --- a/lib/ain-ocean/src/repository/block.rs +++ b/lib/ain-ocean/src/repository/block.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use ain_db::LedgerColumn; use ain_macros::Repository; use bitcoin::BlockHash; @@ -11,34 +12,46 @@ use crate::{ }; #[derive(Repository)] -#[repository(K = "BlockHash", V = "Block", Column = "Block")] +#[repository(K = "BlockHash", V = "Block")] pub struct BlockRepository { pub store: Arc, + col: LedgerColumn, } impl BlockRepository { pub fn new(store: Arc) -> Self { - Self { store } + Self { + col: store.column(), + store, + } } } #[derive(Repository)] -#[repository(K = "u32", V = "BlockHash", Column = "BlockByHeight")] +#[repository(K = "u32", V = "BlockHash")] pub struct BlockByHeightRepository { pub store: Arc, + col: LedgerColumn, } impl BlockByHeightRepository { pub fn new(store: Arc) -> Self { - Self { store } + Self { + col: store.column(), + store, + } } } impl BlockByHeightRepository { pub fn get_highest(&self) -> Result> { - match self.store.list::(None, 1)?.first() { + match self.col.iter(None)?.next() { None => Ok(None), - Some((_, id)) => Ok(self.store.get::(*id)?), + Some(Ok((_, id))) => { + let col = self.store.column::(); + Ok(col.get(&id)?) + } + Some(Err(e)) => Err(e.into()), } } } diff --git a/lib/ain-ocean/src/repository/masternode.rs b/lib/ain-ocean/src/repository/masternode.rs index 489f91c7040..5a64a0112fd 100644 --- a/lib/ain-ocean/src/repository/masternode.rs +++ b/lib/ain-ocean/src/repository/masternode.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use ain_db::LedgerColumn; use ain_macros::Repository; use bitcoin::Txid; @@ -11,27 +12,35 @@ use crate::{ }; #[derive(Repository)] -#[repository(K = "Txid", V = "Masternode", Column = "Masternode")] +#[repository(K = "Txid", V = "Masternode")] pub struct MasternodeRepository { pub store: Arc, + col: LedgerColumn, } impl MasternodeRepository { pub fn new(store: Arc) -> Self { - Self { store } + Self { + col: store.column(), + store, + } } } type MasternodeByHeightKey = (u32, usize); #[derive(Repository)] -#[repository(K = "MasternodeByHeightKey", V = "Txid", Column = "MasternodeByHeight")] +#[repository(K = "MasternodeByHeightKey", V = "Txid")] pub struct MasternodeByHeightRepository { pub store: Arc, + col: LedgerColumn, } impl MasternodeByHeightRepository { pub fn new(store: Arc) -> Self { - Self { store } + Self { + col: store.column(), + store, + } } } diff --git a/lib/ain-ocean/src/repository/masternode_stats.rs b/lib/ain-ocean/src/repository/masternode_stats.rs index 6ba06bf6a13..e6b9cdb593c 100644 --- a/lib/ain-ocean/src/repository/masternode_stats.rs +++ b/lib/ain-ocean/src/repository/masternode_stats.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use ain_db::LedgerColumn; use ain_macros::Repository; use bitcoin::Txid; @@ -11,13 +12,17 @@ use crate::{ }; #[derive(Repository)] -#[repository(K = "Txid", V = "MasternodeStats", Column = "MasternodeStats")] +#[repository(K = "Txid", V = "MasternodeStats")] pub struct MasternodeStatsRepository { pub store: Arc, + col: LedgerColumn, } impl MasternodeStatsRepository { pub fn new(store: Arc) -> Self { - Self { store } + Self { + col: store.column(), + store, + } } } diff --git a/lib/ain-ocean/src/repository/mod.rs b/lib/ain-ocean/src/repository/mod.rs index 3ee848f9148..97aa4e95774 100644 --- a/lib/ain-ocean/src/repository/mod.rs +++ b/lib/ain-ocean/src/repository/mod.rs @@ -43,8 +43,11 @@ pub use transaction_vout::*; pub use vault_auction_batch_history::*; pub trait RepositoryOps { - fn get(&self, key: K) -> Result>; + fn get(&self, key: &K) -> Result>; fn put(&self, key: &K, masternode: &V) -> Result<()>; fn delete(&self, key: &K) -> Result<()>; - fn list(&self, from: Option, limit: usize) -> Result>; + fn list( + &self, + from: Option, + ) -> Result>>; } diff --git a/lib/ain-ocean/src/repository/raw_block.rs b/lib/ain-ocean/src/repository/raw_block.rs index 426b85bb1d0..b2f04f6be23 100644 --- a/lib/ain-ocean/src/repository/raw_block.rs +++ b/lib/ain-ocean/src/repository/raw_block.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use ain_db::LedgerColumn; use ain_macros::Repository; use bitcoin::BlockHash; @@ -10,13 +11,17 @@ use crate::{ }; #[derive(Repository)] -#[repository(K = "BlockHash", V = "String", Column = "RawBlock")] +#[repository(K = "BlockHash", V = "String")] pub struct RawBlockRepository { pub store: Arc, + col: LedgerColumn, } impl RawBlockRepository { pub fn new(store: Arc) -> Self { - Self { store } + Self { + col: store.column(), + store, + } } } diff --git a/lib/ain-ocean/src/storage/columns/block.rs b/lib/ain-ocean/src/storage/columns/block.rs index e1398f353c5..488a2aad218 100644 --- a/lib/ain-ocean/src/storage/columns/block.rs +++ b/lib/ain-ocean/src/storage/columns/block.rs @@ -1,6 +1,5 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, BlockHash}; +use ain_db::{Column, ColumnName, TypedColumn}; +use bitcoin::BlockHash; use crate::model; diff --git a/lib/ain-ocean/src/storage/columns/masternode.rs b/lib/ain-ocean/src/storage/columns/masternode.rs index 8b66e520b9f..d4a3e1b1fdc 100644 --- a/lib/ain-ocean/src/storage/columns/masternode.rs +++ b/lib/ain-ocean/src/storage/columns/masternode.rs @@ -1,6 +1,5 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; +use ain_db::{Column, ColumnName, TypedColumn}; +use bitcoin::Txid; use crate::model; diff --git a/lib/ain-ocean/src/storage/columns/masternode_stats.rs b/lib/ain-ocean/src/storage/columns/masternode_stats.rs index 3382de7df46..5e77802b89a 100644 --- a/lib/ain-ocean/src/storage/columns/masternode_stats.rs +++ b/lib/ain-ocean/src/storage/columns/masternode_stats.rs @@ -1,6 +1,5 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; +use ain_db::{Column, ColumnName, TypedColumn}; +use bitcoin::Txid; use crate::model; diff --git a/lib/ain-ocean/src/storage/columns/vault_auction_history.rs b/lib/ain-ocean/src/storage/columns/vault_auction_history.rs index d9a78e4e9d3..ebfa2a0b110 100644 --- a/lib/ain-ocean/src/storage/columns/vault_auction_history.rs +++ b/lib/ain-ocean/src/storage/columns/vault_auction_history.rs @@ -1,6 +1,4 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; +use ain_db::{Column, ColumnName, TypedColumn}; use crate::model; diff --git a/lib/ain-ocean/src/storage/ocean_store.rs b/lib/ain-ocean/src/storage/ocean_store.rs index 20375235890..9caa2cd74c7 100644 --- a/lib/ain-ocean/src/storage/ocean_store.rs +++ b/lib/ain-ocean/src/storage/ocean_store.rs @@ -1,6 +1,6 @@ use std::{fs, marker::PhantomData, path::Path, sync::Arc}; -use ain_db::{Column, ColumnName, LedgerColumn, Rocks, TypedColumn}; +use ain_db::{Column, ColumnName, DBError, LedgerColumn, Rocks, TypedColumn}; use super::columns::COLUMN_NAMES; use crate::Result; @@ -27,38 +27,3 @@ impl OceanStore { } } } - -impl OceanStore { - pub fn get( - &self, - key: C::Index, - ) -> Result> { - let col = self.column::(); - Ok(col.get(&key)?) - } - - pub fn put( - &self, - key: &C::Index, - val: &C::Type, - ) -> Result<()> { - let col = self.column::(); - let serialized_value = bincode::serialize(val)?; - Ok(col.put_bytes(key, &serialized_value)?) - } - - pub fn delete(&self, key: &C::Index) -> Result<()> { - let col = self.column::(); - Ok(col.delete(key)?) - } - - pub fn list( - &self, - from: Option, - limit: usize, - ) -> Result> { - let col = self.column::(); - let list = col.iter(from, limit)?.collect(); - Ok(list) - } -} From 8cad7f908fd2fd356309c204bdcff3724e2ca576 Mon Sep 17 00:00:00 2001 From: jouzo Date: Mon, 8 Jan 2024 08:07:00 +0100 Subject: [PATCH 023/185] Remove need for nightly --- lib/ain-macros/src/lib.rs | 5 +++-- lib/ain-ocean/src/lib.rs | 2 -- lib/ain-ocean/src/repository/mod.rs | 6 +++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/ain-macros/src/lib.rs b/lib/ain-macros/src/lib.rs index 02ee4917ea3..101d68acce7 100644 --- a/lib/ain-macros/src/lib.rs +++ b/lib/ain-macros/src/lib.rs @@ -113,9 +113,10 @@ pub fn repository_derive(input: TokenStream) -> TokenStream { Ok(self.col.delete(id)?) } - fn list(&self, from: Option<#key_type_ident>) -> Result>> + fn list<'a>(&'a self, from: Option<#key_type_ident>) -> Result> + 'a>> { - Ok(self.col.iter(from)?) + let it = self.col.iter(from)?; + Ok(Box::new(it)) } } }; diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 27aa684de76..a69b2fe0f14 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] - pub mod api_paged_response; pub mod api_query; pub mod error; diff --git a/lib/ain-ocean/src/repository/mod.rs b/lib/ain-ocean/src/repository/mod.rs index 97aa4e95774..75ec0cefafa 100644 --- a/lib/ain-ocean/src/repository/mod.rs +++ b/lib/ain-ocean/src/repository/mod.rs @@ -46,8 +46,8 @@ pub trait RepositoryOps { fn get(&self, key: &K) -> Result>; fn put(&self, key: &K, masternode: &V) -> Result<()>; fn delete(&self, key: &K) -> Result<()>; - fn list( - &self, + fn list<'a>( + &'a self, from: Option, - ) -> Result>>; + ) -> Result> + 'a>>; } From fd5932fd0609371bc316bb76a3fc0e762e40ccd0 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Tue, 9 Jan 2024 10:00:01 +0100 Subject: [PATCH 024/185] Index auction (#2771) --- lib/ain-ocean/src/api/loan.rs | 70 +++++++++++++++++-- lib/ain-ocean/src/indexer/auction.rs | 47 +++++++++++-- lib/ain-ocean/src/indexer/mod.rs | 2 +- lib/ain-ocean/src/lib.rs | 15 +++- .../src/model/vault_auction_batch_history.rs | 2 +- .../repository/vault_auction_batch_history.rs | 55 +++++++++++++++ lib/ain-ocean/src/storage/ocean_store.rs | 2 +- 7 files changed, 179 insertions(+), 14 deletions(-) diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index 5452df1f3d0..f76c425242d 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -1,4 +1,15 @@ -use axum::{extract::Path, routing::get, Router}; +use axum::{ + extract::{Path, Query}, + routing::get, + Json, Router, +}; +use bitcoin::Txid; +use log::debug; + +use crate::{ + api_paged_response::ApiPagedResponse, api_query::PaginationQuery, error::OceanResult, + model::VaultAuctionBatchHistory, repository::RepositoryOps, SERVICES, +}; async fn list_scheme() -> String { "List of loan schemes".to_string() @@ -33,12 +44,61 @@ async fn get_vault(Path(vault_id): Path) -> String { } async fn list_vault_auction_history( - Path((vault_id, height, batch_index)): Path<(String, i64, i64)>, -) -> String { - format!( + Path((vault_id, height, batch_index)): Path<(Txid, u32, u32)>, + Query(query): Query, +) -> OceanResult>> { + println!("listvault auction history"); + debug!( "Auction history for vault id {}, height {}, batch index {}", vault_id, height, batch_index - ) + ); + let next = query + .next + .map(|q| { + let parts: Vec<&str> = q.split('-').collect(); + if parts.len() != 2 { + return Err("Invalid query format"); + } + + let height = parts[0].parse::().map_err(|_| "Invalid height")?; + let txno = parts[1].parse::().map_err(|_| "Invalid txno")?; + + Ok((height, txno)) + }) + .transpose()? + .unwrap_or_default(); + + debug!("next : {:?}", next); + + let size = if query.size > 0 { query.size } else { 20 }; + + let auctions = SERVICES + .auction + .by_height + .list(Some((vault_id, batch_index, next.0, next.1)))? + .take(size) + .take_while(|item| match item { + Ok((k, _)) => k.0 == vault_id && k.1 == batch_index, + _ => true, + }) + .map(|item| { + let (_, id) = item?; + + let auction = SERVICES + .auction + .by_id + .get(&id)? + .ok_or("Missing auction index")?; + + Ok(auction) + }) + .collect::>>()?; + + Ok(Json(ApiPagedResponse::of( + auctions, + query.size, + |auction| auction.clone().sort, + ))) } async fn list_auction() -> String { diff --git a/lib/ain-ocean/src/indexer/auction.rs b/lib/ain-ocean/src/indexer/auction.rs index 2d2ca0d0e88..60528360cdc 100644 --- a/lib/ain-ocean/src/indexer/auction.rs +++ b/lib/ain-ocean/src/indexer/auction.rs @@ -1,14 +1,53 @@ use dftx_rs::{vault::PlaceAuctionBid, Transaction}; +use log::debug; use super::BlockContext; -use crate::indexer::{Index, Result}; +use crate::{ + indexer::{Index, Result}, + model::{VaultAuctionBatchHistory, VaultAuctionBatchHistoryBlock}, + repository::RepositoryOps, + SERVICES, +}; impl Index for PlaceAuctionBid { fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { - todo!() + debug!("[PlaceAuctionBid] Indexing..."); + + let auction = VaultAuctionBatchHistory { + id: format!("{}-{}-{}", self.vault_id, self.index, tx.txid()), + key: format!("{}-{}", self.vault_id, self.index), + sort: format!("{}-{}", ctx.height, idx), + vault_id: self.vault_id, + index: idx, + from: self.from.clone(), + amount: self.token_amount.amount, + token_id: self.token_amount.token.0, + block: VaultAuctionBatchHistoryBlock { + hash: ctx.hash, + height: ctx.height, + time: ctx.time, + median_time: ctx.median_time, + }, + }; + debug!("auction : {:?}", auction); + + let key = (self.vault_id, self.index, tx.txid()); + SERVICES.auction.by_id.put(&key, &auction)?; + SERVICES + .auction + .by_height + .put(&(self.vault_id, self.index, ctx.height, idx), &key) } - fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { - todo!() + fn invalidate(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + debug!("[PlaceAuctionBid] Invalidating..."); + SERVICES + .auction + .by_id + .delete(&(self.vault_id, self.index, tx.txid()))?; + SERVICES + .auction + .by_height + .delete(&(self.vault_id, self.index, ctx.height, idx)) } } diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 1696b931fda..865983c56b6 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -59,7 +59,7 @@ pub fn index_block(block: String, block_height: u32) -> Result<()> { // DfTx::SetOracleData(data) => data.index(&ctx, tx, idx)?, // DfTx::PoolSwap(data) => data.index(&ctx, tx, idx)?, // DfTx::CompositeSwap(data) => data.index(&ctx, tx, idx)?, - // DfTx::PlaceAuctionBid(data) => data.index(&ctx, tx, idx)?, + DfTx::PlaceAuctionBid(data) => data.index(&ctx, tx, idx)?, _ => (), } } diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index a69b2fe0f14..2b567c7d473 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -8,8 +8,9 @@ use std::{path::PathBuf, sync::Arc}; pub use api::ocean_router; pub use indexer::{index_block, invalidate_block}; use repository::{ - BlockByHeightRepository, BlockRepository, MasternodeByHeightRepository, MasternodeRepository, - MasternodeStatsRepository, RawBlockRepository, + AuctionHistoryByHeightRepository, AuctionHistoryRepository, BlockByHeightRepository, + BlockRepository, MasternodeByHeightRepository, MasternodeRepository, MasternodeStatsRepository, + RawBlockRepository, }; pub mod api; mod model; @@ -42,9 +43,15 @@ pub struct BlockService { by_height: BlockByHeightRepository, } +pub struct AuctionService { + by_id: AuctionHistoryRepository, + by_height: AuctionHistoryByHeightRepository, +} + pub struct Services { masternode: MasternodeService, block: BlockService, + auction: AuctionService, } impl Services { @@ -60,6 +67,10 @@ impl Services { by_id: BlockRepository::new(Arc::clone(&store)), by_height: BlockByHeightRepository::new(Arc::clone(&store)), }, + auction: AuctionService { + by_id: AuctionHistoryRepository::new(Arc::clone(&store)), + by_height: AuctionHistoryByHeightRepository::new(Arc::clone(&store)), + }, } } } diff --git a/lib/ain-ocean/src/model/vault_auction_batch_history.rs b/lib/ain-ocean/src/model/vault_auction_batch_history.rs index d4885ed7297..2c1dd549ede 100644 --- a/lib/ain-ocean/src/model/vault_auction_batch_history.rs +++ b/lib/ain-ocean/src/model/vault_auction_batch_history.rs @@ -1,4 +1,4 @@ -use bitcoin::{Amount, BlockHash, ScriptBuf, Txid}; +use bitcoin::{BlockHash, ScriptBuf, Txid}; use serde::{Deserialize, Serialize}; pub type AuctionHistoryKey = (Txid, u32, Txid); diff --git a/lib/ain-ocean/src/repository/vault_auction_batch_history.rs b/lib/ain-ocean/src/repository/vault_auction_batch_history.rs index 8b137891791..5e1b370e576 100644 --- a/lib/ain-ocean/src/repository/vault_auction_batch_history.rs +++ b/lib/ain-ocean/src/repository/vault_auction_batch_history.rs @@ -1 +1,56 @@ +use std::sync::Arc; +use ain_db::LedgerColumn; +use ain_macros::Repository; + +use super::RepositoryOps; +use crate::{ + model::{AuctionHistoryByHeightKey, AuctionHistoryKey, VaultAuctionBatchHistory}, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "AuctionHistoryKey", V = "VaultAuctionBatchHistory")] +pub struct AuctionHistoryRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl AuctionHistoryRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} + +#[derive(Repository)] +#[repository(K = "AuctionHistoryByHeightKey", V = "AuctionHistoryKey")] +pub struct AuctionHistoryByHeightRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl AuctionHistoryByHeightRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} + +impl AuctionHistoryByHeightRepository { + pub fn get_latest(&self) -> Result> { + match self.list(None)?.next() { + None => Ok(None), + Some(Ok((_, id))) => { + let col = self.store.column::(); + Ok(col.get(&id)?) + } + Some(Err(e)) => Err(e.into()), + } + } +} diff --git a/lib/ain-ocean/src/storage/ocean_store.rs b/lib/ain-ocean/src/storage/ocean_store.rs index 9caa2cd74c7..96eadf79516 100644 --- a/lib/ain-ocean/src/storage/ocean_store.rs +++ b/lib/ain-ocean/src/storage/ocean_store.rs @@ -1,6 +1,6 @@ use std::{fs, marker::PhantomData, path::Path, sync::Arc}; -use ain_db::{Column, ColumnName, DBError, LedgerColumn, Rocks, TypedColumn}; +use ain_db::{Column, ColumnName, LedgerColumn, Rocks}; use super::columns::COLUMN_NAMES; use crate::Result; From 0f99a2f5688c82299ddd8d4772cbabc9933c8ae5 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Tue, 9 Jan 2024 13:51:26 +0100 Subject: [PATCH 025/185] Use single block context (#2773) --- lib/ain-ocean/src/api/loan.rs | 2 +- lib/ain-ocean/src/indexer/auction.rs | 9 ++----- lib/ain-ocean/src/indexer/masternode.rs | 9 ++----- lib/ain-ocean/src/indexer/mod.rs | 10 +------ lib/ain-ocean/src/model/block.rs | 10 +++++++ lib/ain-ocean/src/model/masternode.rs | 15 +++-------- lib/ain-ocean/src/model/masternode_stats.rs | 15 +++-------- lib/ain-ocean/src/model/oracle.rs | 17 ++++-------- lib/ain-ocean/src/model/oracle_history.rs | 15 +++-------- .../src/model/oracle_price_active.rs | 23 ++++++---------- .../src/model/oracle_price_aggregated.rs | 19 +++++--------- .../model/oracle_price_aggregated_interval.rs | 19 +++++--------- lib/ain-ocean/src/model/oracle_price_feed.rs | 15 +++-------- .../src/model/oracle_token_currency.rs | 15 +++-------- lib/ain-ocean/src/model/poolswap.rs | 15 +++-------- .../src/model/poolswap_aggregated.rs | 14 ++++------ lib/ain-ocean/src/model/price_ticker.rs | 2 +- lib/ain-ocean/src/model/script_activity.rs | 26 +++++++------------ lib/ain-ocean/src/model/script_aggregation.rs | 20 +++++--------- lib/ain-ocean/src/model/script_unspent.rs | 18 +++++-------- lib/ain-ocean/src/model/transaction.rs | 15 +++-------- .../src/model/vault_auction_batch_history.rs | 17 ++++-------- 22 files changed, 102 insertions(+), 218 deletions(-) diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index f76c425242d..1b0e911463e 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -97,7 +97,7 @@ async fn list_vault_auction_history( Ok(Json(ApiPagedResponse::of( auctions, query.size, - |auction| auction.clone().sort, + |auction| auction.sort.to_string(), ))) } diff --git a/lib/ain-ocean/src/indexer/auction.rs b/lib/ain-ocean/src/indexer/auction.rs index 60528360cdc..c6d50122db7 100644 --- a/lib/ain-ocean/src/indexer/auction.rs +++ b/lib/ain-ocean/src/indexer/auction.rs @@ -4,7 +4,7 @@ use log::debug; use super::BlockContext; use crate::{ indexer::{Index, Result}, - model::{VaultAuctionBatchHistory, VaultAuctionBatchHistoryBlock}, + model::VaultAuctionBatchHistory, repository::RepositoryOps, SERVICES, }; @@ -22,12 +22,7 @@ impl Index for PlaceAuctionBid { from: self.from.clone(), amount: self.token_amount.amount, token_id: self.token_amount.token.0, - block: VaultAuctionBatchHistoryBlock { - hash: ctx.hash, - height: ctx.height, - time: ctx.time, - median_time: ctx.median_time, - }, + block: ctx.clone(), }; debug!("auction : {:?}", auction); diff --git a/lib/ain-ocean/src/indexer/masternode.rs b/lib/ain-ocean/src/indexer/masternode.rs index 0ca2e6d0ff9..23bb114df13 100644 --- a/lib/ain-ocean/src/indexer/masternode.rs +++ b/lib/ain-ocean/src/indexer/masternode.rs @@ -5,7 +5,7 @@ use log::debug; use super::BlockContext; use crate::{ indexer::{Index, Result}, - model::{HistoryItem, Masternode, MasternodeBlock}, + model::{HistoryItem, Masternode}, repository::RepositoryOps, SERVICES, }; @@ -35,12 +35,7 @@ impl Index for CreateMasternode { resign_tx: None, minted_blocks: 0, timelock: self.timelock.0.unwrap_or_default(), - block: MasternodeBlock { - hash: ctx.hash, - height: ctx.height, - time: ctx.time, - median_time: ctx.median_time, - }, + block: ctx.clone(), collateral: tx.output[1].value.to_string(), history: Vec::new(), }; diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 865983c56b6..8f31056fa63 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -10,18 +10,10 @@ pub(crate) trait Index { fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()>; } -use bitcoin::BlockHash; use dftx_rs::{deserialize, Block, DfTx}; use log::debug; -use crate::Result; - -pub(crate) struct BlockContext { - height: u32, - hash: BlockHash, - time: u64, - median_time: u64, -} +use crate::{model::BlockContext, Result}; pub fn index_block(block: String, block_height: u32) -> Result<()> { debug!("[index_block] Indexing block..."); diff --git a/lib/ain-ocean/src/model/block.rs b/lib/ain-ocean/src/model/block.rs index bf542a2c276..f302d912016 100644 --- a/lib/ain-ocean/src/model/block.rs +++ b/lib/ain-ocean/src/model/block.rs @@ -1,3 +1,4 @@ +use bitcoin::BlockHash; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] @@ -22,3 +23,12 @@ pub struct Block { pub size_stripped: i32, pub weight: i32, } + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct BlockContext { + pub hash: BlockHash, + pub height: u32, + pub time: u64, + pub median_time: u64, +} diff --git a/lib/ain-ocean/src/model/masternode.rs b/lib/ain-ocean/src/model/masternode.rs index 126885d7570..41a1715db54 100644 --- a/lib/ain-ocean/src/model/masternode.rs +++ b/lib/ain-ocean/src/model/masternode.rs @@ -1,6 +1,8 @@ -use bitcoin::{BlockHash, ScriptBuf, Txid}; +use bitcoin::{ScriptBuf, Txid}; use serde::{Deserialize, Serialize}; +use super::BlockContext; + #[derive(Debug, Serialize, Deserialize)] pub struct Masternode { pub id: Txid, // Keep for backward compatibility @@ -13,7 +15,7 @@ pub struct Masternode { pub minted_blocks: i32, pub timelock: u16, pub collateral: String, - pub block: MasternodeBlock, + pub block: BlockContext, pub history: Vec, } @@ -23,12 +25,3 @@ pub struct HistoryItem { pub owner_address: ScriptBuf, pub operator_address: ScriptBuf, } - -#[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct MasternodeBlock { - pub hash: BlockHash, - pub height: u32, - pub time: u64, - pub median_time: u64, -} diff --git a/lib/ain-ocean/src/model/masternode_stats.rs b/lib/ain-ocean/src/model/masternode_stats.rs index f037629517b..44325fbd392 100644 --- a/lib/ain-ocean/src/model/masternode_stats.rs +++ b/lib/ain-ocean/src/model/masternode_stats.rs @@ -1,10 +1,12 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Default)] +use super::BlockContext; + +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct MasternodeStats { pub id: String, - pub block: MasternodeStatsBlock, + pub block: BlockContext, pub stats: MasternodeStatsStats, } @@ -16,15 +18,6 @@ pub struct TimelockStats { pub count: i32, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] -pub struct MasternodeStatsBlock { - pub hash: String, - pub height: i32, - pub time: i32, - pub median_time: i32, -} - #[derive(Serialize, Deserialize, Debug, Default)] #[serde(rename_all = "camelCase")] pub struct MasternodeStatsStats { diff --git a/lib/ain-ocean/src/model/oracle.rs b/lib/ain-ocean/src/model/oracle.rs index 97befdd9c71..d9892b23c30 100644 --- a/lib/ain-ocean/src/model/oracle.rs +++ b/lib/ain-ocean/src/model/oracle.rs @@ -1,27 +1,20 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] +use super::BlockContext; + +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Oracle { pub id: String, pub owner_address: String, pub weightage: i32, pub price_feeds: Vec, - pub block: OracleBlock, + pub block: BlockContext, } -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct PriceFeedsItem { pub token: String, pub currency: String, } - -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] -#[serde(rename_all = "camelCase")] -pub struct OracleBlock { - pub hash: String, - pub height: i32, - pub time: i32, - pub median_time: i32, -} diff --git a/lib/ain-ocean/src/model/oracle_history.rs b/lib/ain-ocean/src/model/oracle_history.rs index 0bce2e20a6d..faa93b373cb 100644 --- a/lib/ain-ocean/src/model/oracle_history.rs +++ b/lib/ain-ocean/src/model/oracle_history.rs @@ -1,6 +1,8 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Default)] +use super::BlockContext; + +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OracleHistory { pub id: String, @@ -9,7 +11,7 @@ pub struct OracleHistory { pub owner_address: String, pub weightage: i32, pub price_feeds: Vec, - pub block: OracleHistoryBlock, + pub block: BlockContext, } #[derive(Serialize, Deserialize, Debug, Default)] @@ -18,12 +20,3 @@ pub struct PriceFeedsItem { pub token: String, pub currency: String, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] -pub struct OracleHistoryBlock { - pub hash: String, - pub height: i32, - pub time: i32, - pub median_time: i32, -} diff --git a/lib/ain-ocean/src/model/oracle_price_active.rs b/lib/ain-ocean/src/model/oracle_price_active.rs index d3d7a77641a..3f5b74a4ac8 100644 --- a/lib/ain-ocean/src/model/oracle_price_active.rs +++ b/lib/ain-ocean/src/model/oracle_price_active.rs @@ -1,6 +1,8 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Default)] +use super::BlockContext; + +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OraclePriceActive { pub id: String, @@ -9,10 +11,10 @@ pub struct OraclePriceActive { pub active: OraclePriceActiveActive, pub next: OraclePriceActiveNext, pub is_live: bool, - pub block: OraclePriceActiveBlock, + pub block: BlockContext, } -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OraclePriceActiveActive { pub amount: String, @@ -20,7 +22,7 @@ pub struct OraclePriceActiveActive { pub oracles: OraclePriceActiveActiveOracles, } -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OraclePriceActiveNext { pub amount: String, @@ -28,23 +30,14 @@ pub struct OraclePriceActiveNext { pub oracles: OraclePriceActiveNextOracles, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] -pub struct OraclePriceActiveBlock { - pub hash: String, - pub height: i32, - pub time: i32, - pub median_time: i32, -} - -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OraclePriceActiveActiveOracles { pub active: i32, pub total: i32, } -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OraclePriceActiveNextOracles { pub active: i32, diff --git a/lib/ain-ocean/src/model/oracle_price_aggregated.rs b/lib/ain-ocean/src/model/oracle_price_aggregated.rs index 57e16f7b063..df0db13821c 100644 --- a/lib/ain-ocean/src/model/oracle_price_aggregated.rs +++ b/lib/ain-ocean/src/model/oracle_price_aggregated.rs @@ -1,6 +1,8 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Default)] +use super::BlockContext; + +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregated { pub id: String, @@ -9,10 +11,10 @@ pub struct OraclePriceAggregated { pub token: String, pub currency: String, pub aggregated: OraclePriceAggregatedAggregated, - pub block: OraclePriceAggregatedBlock, + pub block: BlockContext, } -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedAggregated { pub amount: String, @@ -20,16 +22,7 @@ pub struct OraclePriceAggregatedAggregated { pub oracles: OraclePriceAggregatedAggregatedOracles, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] -pub struct OraclePriceAggregatedBlock { - pub hash: String, - pub height: i32, - pub time: i32, - pub median_time: i32, -} - -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedAggregatedOracles { pub active: i32, diff --git a/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs index 867e0030d39..8380e7faee1 100644 --- a/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs +++ b/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs @@ -1,6 +1,8 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Default)] +use super::BlockContext; + +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedInterval { pub id: String, @@ -9,10 +11,10 @@ pub struct OraclePriceAggregatedInterval { pub token: String, pub currency: String, pub aggregated: OraclePriceAggregatedIntervalAggregated, - pub block: OraclePriceAggregatedIntervalBlock, + pub block: BlockContext, } -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedIntervalAggregated { pub amount: String, @@ -21,16 +23,7 @@ pub struct OraclePriceAggregatedIntervalAggregated { pub oracles: OraclePriceAggregatedIntervalAggregatedOracles, } -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] -pub struct OraclePriceAggregatedIntervalBlock { - pub hash: String, - pub height: i32, - pub time: i32, - pub median_time: i32, -} - -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedIntervalAggregatedOracles { pub active: i32, diff --git a/lib/ain-ocean/src/model/oracle_price_feed.rs b/lib/ain-ocean/src/model/oracle_price_feed.rs index 74fd34d5764..2ff21dc1add 100644 --- a/lib/ain-ocean/src/model/oracle_price_feed.rs +++ b/lib/ain-ocean/src/model/oracle_price_feed.rs @@ -1,6 +1,8 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Default)] +use super::BlockContext; + +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OraclePriceFeed { pub id: String, @@ -12,14 +14,5 @@ pub struct OraclePriceFeed { pub txid: String, pub time: i32, pub amount: String, - pub block: OraclePriceFeedBlock, -} - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] -pub struct OraclePriceFeedBlock { - pub hash: String, - pub height: i32, - pub time: i32, - pub median_time: i32, + pub block: BlockContext, } diff --git a/lib/ain-ocean/src/model/oracle_token_currency.rs b/lib/ain-ocean/src/model/oracle_token_currency.rs index a814083e9bb..c04a83d0a94 100644 --- a/lib/ain-ocean/src/model/oracle_token_currency.rs +++ b/lib/ain-ocean/src/model/oracle_token_currency.rs @@ -1,6 +1,8 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Default)] +use super::BlockContext; + +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OracleTokenCurrency { pub id: String, @@ -9,14 +11,5 @@ pub struct OracleTokenCurrency { pub currency: String, pub oracle_id: String, pub weightage: i32, - pub block: OracleTokenCurrencyBlock, -} - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] -pub struct OracleTokenCurrencyBlock { - pub hash: String, - pub height: i32, - pub time: i32, - pub median_time: i32, + pub block: BlockContext, } diff --git a/lib/ain-ocean/src/model/poolswap.rs b/lib/ain-ocean/src/model/poolswap.rs index 16dd5d0ba58..86cb1528b6d 100644 --- a/lib/ain-ocean/src/model/poolswap.rs +++ b/lib/ain-ocean/src/model/poolswap.rs @@ -1,6 +1,8 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Default, PartialEq)] +use super::BlockContext; + +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct PoolSwap { pub id: String, @@ -10,14 +12,5 @@ pub struct PoolSwap { pub sort: String, pub from_amount: String, pub from_token_id: i32, - pub block: PoolSwapBlock, -} - -#[derive(Serialize, Deserialize, Debug, Default, PartialEq)] -#[serde(rename_all = "camelCase")] -pub struct PoolSwapBlock { - pub hash: String, - pub height: i32, - pub time: i32, - pub median_time: i32, + pub block: BlockContext, } diff --git a/lib/ain-ocean/src/model/poolswap_aggregated.rs b/lib/ain-ocean/src/model/poolswap_aggregated.rs index 3e997e33028..7b5453b9eb7 100644 --- a/lib/ain-ocean/src/model/poolswap_aggregated.rs +++ b/lib/ain-ocean/src/model/poolswap_aggregated.rs @@ -1,23 +1,19 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Default)] +use super::BlockContext; + +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct PoolSwapAggregated { pub id: String, pub key: String, pub bucket: i32, pub aggregated: PoolSwapAggregatedAggregated, - pub block: PoolSwapAggregatedBlock, + pub block: BlockContext, } -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct PoolSwapAggregatedAggregated { pub amounts: Vec, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] -pub struct PoolSwapAggregatedBlock { - pub median_time: i32, -} diff --git a/lib/ain-ocean/src/model/price_ticker.rs b/lib/ain-ocean/src/model/price_ticker.rs index 509350976e7..9767dbedc37 100644 --- a/lib/ain-ocean/src/model/price_ticker.rs +++ b/lib/ain-ocean/src/model/price_ticker.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use super::oracle_price_aggregated::OraclePriceAggregated; -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct PriceTicker { pub id: String, pub sort: String, diff --git a/lib/ain-ocean/src/model/script_activity.rs b/lib/ain-ocean/src/model/script_activity.rs index bed279a82c7..16feb1bc1df 100644 --- a/lib/ain-ocean/src/model/script_activity.rs +++ b/lib/ain-ocean/src/model/script_activity.rs @@ -1,7 +1,8 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)] + +use super::BlockContext; +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum ScriptActivityType { - #[default] Vin, Vout, } @@ -15,9 +16,8 @@ impl ScriptActivityType { } } -#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum ScriptActivityTypeHex { - #[default] Vin, Vout, } @@ -31,7 +31,7 @@ impl ScriptActivityTypeHex { } } -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ScriptActivity { pub id: String, @@ -39,7 +39,7 @@ pub struct ScriptActivity { pub r#type: ScriptActivityType, pub type_hex: ScriptActivityTypeHex, pub txid: String, - pub block: ScriptActivityBlock, + pub block: BlockContext, pub script: ScriptActivityScript, pub vin: ScriptActivityVin, pub vout: ScriptActivityVout, @@ -47,27 +47,19 @@ pub struct ScriptActivity { pub token_id: i32, } -#[derive(Debug, Default, Serialize, Deserialize)] -pub struct ScriptActivityBlock { - pub hash: String, - pub height: i32, - pub time: i32, - pub median_time: i32, -} - -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ScriptActivityScript { pub r#type: String, pub hex: String, } -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ScriptActivityVin { pub txid: String, pub n: i32, } -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ScriptActivityVout { pub txid: String, pub n: i32, diff --git a/lib/ain-ocean/src/model/script_aggregation.rs b/lib/ain-ocean/src/model/script_aggregation.rs index 1345920cc52..3d8bd49deed 100644 --- a/lib/ain-ocean/src/model/script_aggregation.rs +++ b/lib/ain-ocean/src/model/script_aggregation.rs @@ -1,36 +1,30 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, Serialize, Deserialize)] + +use super::BlockContext; +#[derive(Debug, Serialize, Deserialize)] pub struct ScriptAggregation { pub id: String, pub hid: String, - pub block: ScriptAggregationBlock, + pub block: BlockContext, pub script: ScriptAggregationScript, pub statistic: ScriptAggregationStatistic, pub amount: ScriptAggregationAmount, } -#[derive(Debug, Default, Serialize, Deserialize)] -pub struct ScriptAggregationBlock { - pub hash: String, - pub height: i32, - pub time: i32, - pub median_time: i32, -} - -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ScriptAggregationScript { pub r#type: String, pub hex: String, } -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ScriptAggregationStatistic { pub tx_count: i32, pub tx_in_count: i32, pub tx_out_count: i32, } -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ScriptAggregationAmount { pub tx_in: String, pub tx_out: String, diff --git a/lib/ain-ocean/src/model/script_unspent.rs b/lib/ain-ocean/src/model/script_unspent.rs index 1c7787247bf..d411f00c3c2 100644 --- a/lib/ain-ocean/src/model/script_unspent.rs +++ b/lib/ain-ocean/src/model/script_unspent.rs @@ -1,29 +1,23 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, Serialize, Deserialize)] + +use super::BlockContext; +#[derive(Debug, Serialize, Deserialize)] pub struct ScriptUnspent { pub id: String, pub hid: String, pub sort: String, - pub block: ScriptUnspentBlock, + pub block: BlockContext, pub script: ScriptUnspentScript, pub vout: ScriptUnspentVout, } -#[derive(Debug, Default, Serialize, Deserialize)] -pub struct ScriptUnspentBlock { - pub hash: String, - pub height: i32, - pub time: i32, - pub median_time: i32, -} - -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ScriptUnspentScript { pub r#type: String, pub hex: String, } -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct ScriptUnspentVout { pub txid: String, pub n: i32, diff --git a/lib/ain-ocean/src/model/transaction.rs b/lib/ain-ocean/src/model/transaction.rs index 911c2d22b83..f1573415d29 100644 --- a/lib/ain-ocean/src/model/transaction.rs +++ b/lib/ain-ocean/src/model/transaction.rs @@ -1,11 +1,13 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Clone)] +use super::BlockContext; + +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Transaction { pub id: String, pub order: i32, - pub block: TransactionBlock, + pub block: BlockContext, pub txid: String, pub hash: String, pub version: i32, @@ -17,12 +19,3 @@ pub struct Transaction { pub vin_count: i32, pub vout_count: i32, } - -#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Clone)] -#[serde(rename_all = "camelCase")] -pub struct TransactionBlock { - pub hash: String, - pub height: i32, - pub time: i32, - pub median_time: i32, -} diff --git a/lib/ain-ocean/src/model/vault_auction_batch_history.rs b/lib/ain-ocean/src/model/vault_auction_batch_history.rs index 2c1dd549ede..c502265a247 100644 --- a/lib/ain-ocean/src/model/vault_auction_batch_history.rs +++ b/lib/ain-ocean/src/model/vault_auction_batch_history.rs @@ -1,10 +1,12 @@ -use bitcoin::{BlockHash, ScriptBuf, Txid}; +use bitcoin::{ScriptBuf, Txid}; use serde::{Deserialize, Serialize}; +use super::BlockContext; + pub type AuctionHistoryKey = (Txid, u32, Txid); pub type AuctionHistoryByHeightKey = (Txid, u32, u32, usize); -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct VaultAuctionBatchHistory { pub id: String, @@ -15,14 +17,5 @@ pub struct VaultAuctionBatchHistory { pub from: ScriptBuf, pub amount: i64, pub token_id: u64, - pub block: VaultAuctionBatchHistoryBlock, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct VaultAuctionBatchHistoryBlock { - pub hash: BlockHash, - pub height: u32, - pub time: u64, - pub median_time: u64, + pub block: BlockContext, } From 915a79dc40f5841885b2fda83c11e220a4afe823 Mon Sep 17 00:00:00 2001 From: jouzo Date: Tue, 9 Jan 2024 13:59:37 +0100 Subject: [PATCH 026/185] Fix fmt --- lib/ain-ocean/src/repository/test/block_test.rs | 12 +++++++----- lib/ain-ocean/src/repository/test/masternode_test.rs | 11 +++++++---- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/ain-ocean/src/repository/test/block_test.rs b/lib/ain-ocean/src/repository/test/block_test.rs index 7b377e18efc..461ca515b39 100644 --- a/lib/ain-ocean/src/repository/test/block_test.rs +++ b/lib/ain-ocean/src/repository/test/block_test.rs @@ -1,12 +1,14 @@ #[cfg(test_off)] mod tests { - use super::*; - use crate::data_acces::block::BlockDb; - use crate::database::db_manager::SortOrder; - use crate::database::db_manager::{ColumnFamilyOperations, RocksDB}; - use crate::model::block::Block; use tempdir::TempDir; + use super::*; + use crate::{ + data_acces::block::BlockDb, + database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, + model::block::Block, + }; + pub fn create_dummy_block(height: i32) -> Block { Block { id: "1".to_string(), diff --git a/lib/ain-ocean/src/repository/test/masternode_test.rs b/lib/ain-ocean/src/repository/test/masternode_test.rs index 7e815933422..f85f1e86307 100644 --- a/lib/ain-ocean/src/repository/test/masternode_test.rs +++ b/lib/ain-ocean/src/repository/test/masternode_test.rs @@ -1,12 +1,15 @@ #[cfg(test_off)] mod tests { - use super::*; - use crate::data_acces::masternode::MasterNodeDB; - use crate::database::db_manager::{RocksDB, SortOrder}; - use crate::model::masternode::{HistoryItem, Masternode, MasternodeBlock}; use chrono::Utc; use tempfile::tempdir; + use super::*; + use crate::{ + data_acces::masternode::MasterNodeDB, + database::db_manager::{RocksDB, SortOrder}, + model::masternode::{HistoryItem, Masternode, MasternodeBlock}, + }; + fn setup_test_db() -> MasterNodeDB { let temp_dir = tempdir().unwrap(); let db = RocksDB::new(temp_dir.path().to_str().unwrap()).unwrap(); // Adjust this according to your RocksDB struct From c391fe8c65675cc38ab5e9da2aaddf2f51a00a1b Mon Sep 17 00:00:00 2001 From: canonbrother Date: Thu, 11 Jan 2024 17:16:10 +0800 Subject: [PATCH 027/185] Ocean: block indexing (#2777) * experimental_allow_proto3_optional * ffi blockv2info * update ocean block apis * pindex->stakeModifier * rm block.reward * add missing column block_by_height * rm unuse --- lib/ain-grpc/build.rs | 1 + lib/ain-ocean/src/api/block.rs | 96 ++++++++++-------------- lib/ain-ocean/src/indexer/mod.rs | 55 ++++++++++++-- lib/ain-ocean/src/lib.rs | 2 +- lib/ain-ocean/src/model/block.rs | 19 +++-- lib/ain-ocean/src/storage/columns/mod.rs | 3 +- lib/ain-rs-exports/src/lib.rs | 19 ++++- lib/ain-rs-exports/src/ocean.rs | 28 +++++-- src/dfi/validation.cpp | 15 +++- 9 files changed, 156 insertions(+), 82 deletions(-) diff --git a/lib/ain-grpc/build.rs b/lib/ain-grpc/build.rs index 2594bf2e396..2f7ed5f6445 100644 --- a/lib/ain-grpc/build.rs +++ b/lib/ain-grpc/build.rs @@ -266,6 +266,7 @@ fn compile_proto_and_generate_services( // There's no way to compile protos using custom generator in tonic, // so we're left with creating a prost config and using that for codegen. let mut config = Config::new(); + config.protoc_arg("--experimental_allow_proto3_optional"); config.out_dir(out_dir); config.service_generator(Box::new(gen)); config diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 3113f8003d4..f141604ce1c 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -3,40 +3,54 @@ use axum::{ routing::get, Json, Router, }; -use serde::{Deserialize, Serialize}; - -use crate::{api_paged_response::ApiPagedResponse, api_query::PaginationQuery, error::OceanResult}; - -#[derive(Deserialize)] -struct BlockId { - id: String, -} - -#[derive(Deserialize)] -struct BlockHash { - hash: String, -} +use bitcoin::BlockHash; + +use crate::{ + api_paged_response::ApiPagedResponse, + api_query::PaginationQuery, + error::OceanResult, + SERVICES, + repository::RepositoryOps, + model::Block, +}; async fn list_blocks( Query(query): Query, ) -> OceanResult>> { - // TODO(): query from lvldb.. or maybe pull from index - let blocks = vec![ - Block { id: "0".into() }, - Block { id: "1".into() }, - Block { id: "2".into() }, - ]; - - Ok(Json(ApiPagedResponse::of(blocks, query.size, |block| { - block.clone().id - }))) + let blocks = SERVICES + .block + .by_height + .list(None)? + .take(query.size) + .map(|item| { + let (_, id) = item?; + let b = SERVICES + .block + .by_id + .get(&id)? + .ok_or("Missing block index")?; + + Ok(b) + }) + .collect::>>()?; + + Ok(Json(ApiPagedResponse::of( + blocks, + query.size, + |block| block.clone().id, + ))) } -async fn get_block(Path(BlockId { id }): Path) -> OceanResult> { - Ok(Json(Block { id })) +async fn get_block(Path(id): Path) -> OceanResult>> { + let block = SERVICES + .block + .by_id + .get(&id)?; + + Ok(Json(block)) } -async fn get_transactions(Path(BlockHash { hash }): Path) -> String { +async fn get_transactions(Path(hash): Path) -> String { format!("Transactions for block with hash {}", hash) } @@ -46,33 +60,3 @@ pub fn router() -> Router { .route("/:id", get(get_block)) .route("/:hash/transactions", get(get_transactions)) } - -#[derive(Clone, Debug, Serialize)] -#[serde(default)] -pub struct Block { - id: String, - // TODO(): type mapping - // hash: H256, - // previous_hash: H256, - - // height: u64, - // version: u64, - // time: u64, // ---------------| block time in seconds since epoch - // median_time: u64, // --------| meidan time of the past 11 block timestamps - - // transaction_count: u64, - - // difficulty: u64, - - // masternode: H256, - // minter: H256, - // minter_block_count: u64, - // reward: f64 - - // state_modifier: H256, - // merkle_root: H256, - - // size: u64, - // size_stripped: u64, - // weight: u64, -} diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 8f31056fa63..0a81fda0c78 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -13,21 +13,64 @@ pub(crate) trait Index { use dftx_rs::{deserialize, Block, DfTx}; use log::debug; -use crate::{model::BlockContext, Result}; +use crate::{ + model::{BlockContext, Block as BlockMapper}, + repository::RepositoryOps, + Result, + SERVICES, +}; -pub fn index_block(block: String, block_height: u32) -> Result<()> { +pub struct BlockV2Info { + pub height: u32, + pub difficulty: u32, + pub version: i32, + pub median_time: i64, + pub minter_block_count: u64, + pub size: usize, + pub size_stripped: usize, + pub weight: i64, + pub stake_modifier: String, + pub minter: String, + pub masternode: String, +} + +pub fn index_block(encoded_block: String, info: &BlockV2Info) -> Result<()> { debug!("[index_block] Indexing block..."); - let hex = hex::decode(block)?; + let hex = hex::decode(&encoded_block)?; debug!("got hex"); let block = deserialize::(&hex)?; debug!("got block"); + let block_hash = block.block_hash(); let ctx = BlockContext { - height: block_height, - hash: block.block_hash(), + height: info.height, + hash: block_hash, time: 0, // TODO median_time: 0, // TODO }; + let block_mapper = BlockMapper { + id: block_hash.to_string(), + hash: block_hash.to_string(), + previous_hash: block.header.prev_blockhash.to_string(), + height: info.height, + version: info.version, + time: block.header.time, + median_time: info.median_time, + transaction_count: block.txdata.len(), + difficulty: info.difficulty, + masternode: info.masternode.to_owned(), + minter: info.minter.to_owned(), + minter_block_count: info.minter_block_count, + stake_modifier: info.stake_modifier.to_owned(), + merkleroot: block.header.merkle_root.to_string(), + size: info.size, + size_stripped: info.size_stripped, + weight: info.weight, + }; + + SERVICES.block.raw.put(&ctx.hash, &encoded_block)?; + SERVICES.block.by_id.put(&ctx.hash, &block_mapper)?; + SERVICES.block.by_height.put(&ctx.height, &block_hash)?; for (idx, tx) in block.txdata.into_iter().enumerate() { let bytes = tx.output[0].script_pubkey.as_bytes(); @@ -60,6 +103,6 @@ pub fn index_block(block: String, block_height: u32) -> Result<()> { Ok(()) } -pub fn invalidate_block(block: String, block_height: u32) -> Result<()> { +pub fn invalidate_block(block: String, info: &BlockV2Info) -> Result<()> { Ok(()) } diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 2b567c7d473..2f170c8d958 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -6,7 +6,7 @@ mod indexer; use std::{path::PathBuf, sync::Arc}; pub use api::ocean_router; -pub use indexer::{index_block, invalidate_block}; +pub use indexer::{BlockV2Info, index_block, invalidate_block}; use repository::{ AuctionHistoryByHeightRepository, AuctionHistoryRepository, BlockByHeightRepository, BlockRepository, MasternodeByHeightRepository, MasternodeRepository, MasternodeStatsRepository, diff --git a/lib/ain-ocean/src/model/block.rs b/lib/ain-ocean/src/model/block.rs index f302d912016..273c89d9cc4 100644 --- a/lib/ain-ocean/src/model/block.rs +++ b/lib/ain-ocean/src/model/block.rs @@ -7,21 +7,20 @@ pub struct Block { pub id: String, pub hash: String, pub previous_hash: String, - pub height: i32, + pub height: u32, pub version: i32, - pub time: i32, - pub median_time: i32, - pub transaction_count: i32, - pub difficulty: i32, + pub time: u32, + pub median_time: i64, + pub transaction_count: usize, + pub difficulty: u32, pub masternode: String, pub minter: String, - pub minter_block_count: i32, - pub reward: String, + pub minter_block_count: u64, pub stake_modifier: String, pub merkleroot: String, - pub size: i32, - pub size_stripped: i32, - pub weight: i32, + pub size: usize, + pub size_stripped: usize, + pub weight: i64, } #[derive(Serialize, Deserialize, Debug, Clone)] diff --git a/lib/ain-ocean/src/storage/columns/mod.rs b/lib/ain-ocean/src/storage/columns/mod.rs index 1da163fbadf..2283a873d1c 100644 --- a/lib/ain-ocean/src/storage/columns/mod.rs +++ b/lib/ain-ocean/src/storage/columns/mod.rs @@ -41,8 +41,9 @@ pub use transaction_vin::*; pub use transaction_vout::*; pub use vault_auction_history::*; -pub const COLUMN_NAMES: [&'static str; 22] = [ +pub const COLUMN_NAMES: [&'static str; 23] = [ block::Block::NAME, + block::BlockByHeight::NAME, masternode_stats::MasternodeStats::NAME, masternode::Masternode::NAME, masternode::MasternodeByHeight::NAME, diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index 1f4c68db583..1b84300e7fb 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -55,6 +55,21 @@ pub mod ffi { fn ain_rs_stop_network_services(result: &mut CrossBoundaryResult); } + #[derive(Default)] + pub struct BlockV2Info { + pub height: u32, + pub difficulty: u32, + pub version: i32, + pub median_time: i64, + pub minter_block_count: u64, + pub size: usize, + pub size_stripped: usize, + pub weight: i64, + pub stake_modifier: String, + pub minter: String, + pub masternode: String, + } + // ========== Block ========== #[derive(Default)] pub struct EVMBlockHeader { @@ -346,11 +361,11 @@ pub mod ffi { fn evm_try_flush_db(result: &mut CrossBoundaryResult); - fn ocean_index_block(result: &mut CrossBoundaryResult, block: String, block_height: u32); + fn ocean_index_block(result: &mut CrossBoundaryResult, block: String, info: &BlockV2Info); fn ocean_invalidate_block( result: &mut CrossBoundaryResult, block: String, - block_height: u32, + info: &BlockV2Info, ); } diff --git a/lib/ain-rs-exports/src/ocean.rs b/lib/ain-rs-exports/src/ocean.rs index eb2b4a0c02e..1f58753c8c4 100644 --- a/lib/ain-rs-exports/src/ocean.rs +++ b/lib/ain-rs-exports/src/ocean.rs @@ -1,7 +1,25 @@ -use crate::ffi::CrossBoundaryResult; +use crate::ffi::{BlockV2Info as BlockV2InfoFFI, CrossBoundaryResult}; +use ain_ocean::BlockV2Info; -pub fn ocean_index_block(result: &mut CrossBoundaryResult, block: String, block_height: u32) { - match ain_ocean::index_block(block, block_height) { +// manually convert since BlockV2InfoFFI is belongs to CPP which can't impl From -> Into +pub fn convert(b: &BlockV2InfoFFI) -> BlockV2Info { + BlockV2Info { + height: b.height, + difficulty: b.difficulty, + version: b.version, + median_time: b.median_time, + minter_block_count: b.minter_block_count, + size: b.size, + size_stripped: b.size_stripped, + weight: b.weight, + stake_modifier: b.stake_modifier.to_owned(), + minter: b.minter.to_owned(), + masternode: b.masternode.to_owned(), + } +} + +pub fn ocean_index_block(result: &mut CrossBoundaryResult, block: String, b: &BlockV2InfoFFI) { + match ain_ocean::index_block(block, &convert(b)) { Ok(()) => result.ok = true, Err(e) => { result.ok = false; @@ -10,8 +28,8 @@ pub fn ocean_index_block(result: &mut CrossBoundaryResult, block: String, block_ } } -pub fn ocean_invalidate_block(result: &mut CrossBoundaryResult, block: String, block_height: u32) { - match ain_ocean::invalidate_block(block, block_height) { +pub fn ocean_invalidate_block(result: &mut CrossBoundaryResult, block: String, b: &BlockV2InfoFFI) { + match ain_ocean::invalidate_block(block, &convert(b)) { Ok(()) => result.ok = true, Err(e) => { result.ok = false; diff --git a/src/dfi/validation.cpp b/src/dfi/validation.cpp index 743f56c836a..d236d2c86b8 100644 --- a/src/dfi/validation.cpp +++ b/src/dfi/validation.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -2798,7 +2799,19 @@ Res ProcessDeFiEventFallible(const CBlock &block, std::string serializedData = HexStr(ss.begin(), ss.end()); CrossBoundaryResult result; - ocean_index_block(result, serializedData, pindex->nHeight); + BlockV2Info info; + info.height = pindex->nHeight; + info.difficulty = pindex->nBits; + info.version = pindex->nVersion; + info.median_time = (int64_t)pindex->GetMedianTimePast(); + info.minter_block_count = pindex->mintedBlocks; + info.size = GetSerializeSize(block, PROTOCOL_VERSION); + info.size_stripped = GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS); + info.weight = GetBlockWeight(block); + info.stake_modifier = pindex->stakeModifier.ToString(); + info.minter = "", // mn operator address + info.masternode = "", // mn owner address + ocean_index_block(result, serializedData, info); // if (!result.ok) { // return Res::Err(result.reason.c_str()); // } From 9f8770d9abcd199afbd80425aeb1e7d33a74b445 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Fri, 12 Jan 2024 16:36:50 +0100 Subject: [PATCH 028/185] Index swap and swap result (#2778) --- lib/Cargo.lock | 287 +++++++++--------- lib/ain-ocean/src/api/block.rs | 27 +- lib/ain-ocean/src/api/loan.rs | 8 +- lib/ain-ocean/src/api/masternode.rs | 12 +- lib/ain-ocean/src/api/poolpairs.rs | 119 +++++++- lib/ain-ocean/src/error.rs | 9 +- lib/ain-ocean/src/indexer/mod.rs | 27 +- lib/ain-ocean/src/indexer/pool.rs | 90 +++++- lib/ain-ocean/src/indexer/tx_result.rs | 15 + lib/ain-ocean/src/lib.rs | 18 +- lib/ain-ocean/src/model/mod.rs | 2 + lib/ain-ocean/src/model/poolswap.rs | 17 +- lib/ain-ocean/src/model/tx_result.rs | 28 ++ lib/ain-ocean/src/repository/mod.rs | 2 + lib/ain-ocean/src/repository/pool_swap.rs | 26 ++ lib/ain-ocean/src/repository/tx_result.rs | 28 ++ lib/ain-ocean/src/storage/columns/mod.rs | 5 +- .../src/storage/columns/pool_swap.rs | 6 +- .../src/storage/columns/tx_result.rs | 19 ++ lib/ain-rs-exports/src/lib.rs | 7 + lib/ain-rs-exports/src/ocean.rs | 37 +-- src/dfi/consensus/poolpairs.cpp | 6 +- src/dfi/mn_checks.cpp | 24 +- src/dfi/mn_checks.h | 12 +- src/test/xvm_tests.cpp | 8 +- src/uint256.h | 9 +- 26 files changed, 596 insertions(+), 252 deletions(-) create mode 100644 lib/ain-ocean/src/indexer/tx_result.rs create mode 100644 lib/ain-ocean/src/model/tx_result.rs create mode 100644 lib/ain-ocean/src/repository/tx_result.rs create mode 100644 lib/ain-ocean/src/storage/columns/tx_result.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index eef3890a310..7b2b397a0d5 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" dependencies = [ "cfg-if", "getrandom 0.2.11", @@ -124,7 +124,7 @@ dependencies = [ "ain-cpp-imports", "ain-db", "anyhow", - "axum 0.7.2", + "axum 0.7.3", "bincode", "ethabi", "ethbloom", @@ -175,7 +175,7 @@ dependencies = [ "ain-ocean", "anyhow", "async-trait", - "axum 0.7.2", + "axum 0.7.3", "cxx", "env_logger", "ethereum", @@ -191,7 +191,7 @@ dependencies = [ "log", "num-traits", "parking_lot", - "prettyplease 0.2.15", + "prettyplease 0.2.16", "proc-macro2", "prost", "prost-build", @@ -204,7 +204,7 @@ dependencies = [ "serde_json", "serde_with", "sha3", - "syn 2.0.43", + "syn 2.0.48", "tokio", "tonic", "tonic-build", @@ -218,7 +218,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -229,7 +229,7 @@ dependencies = [ "ain-db", "ain-macros", "anyhow", - "axum 0.7.2", + "axum 0.7.3", "bincode", "bitcoin", "bitcoin_hashes 0.12.0", @@ -327,9 +327,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.77" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9d19de80eff169429ac1e9f48fffb163916b448a44e8e046186232046d9e1f9" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "approx" @@ -391,13 +391,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.75" +version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -459,12 +459,12 @@ dependencies = [ [[package]] name = "axum" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "202651474fe73c62d9e0a56c6133f7a0ff1dc1c8cf7a5b03381af2a26553ac9d" +checksum = "d09dbe0e490df5da9d69b36dca48a76635288a82f92eca90024883a56202026d" dependencies = [ "async-trait", - "axum-core 0.4.1", + "axum-core 0.4.2", "axum-macros", "bytes", "futures-util", @@ -489,6 +489,7 @@ dependencies = [ "tower", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -510,9 +511,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77cb22c689c44d4c07b0ab44ebc25d69d8ae601a2f28fb8d672d344178fa17aa" +checksum = "e87c8503f93e6d144ee5690907ba22db7ba79ab001a932ab99034f0fe836b3df" dependencies = [ "async-trait", "bytes", @@ -526,6 +527,7 @@ dependencies = [ "sync_wrapper", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -537,7 +539,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -569,9 +571,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.5" +version = "0.21.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "c79fed4cdb43e993fcdadc7e58a09fd0e3e649c4436fa11da71c9f1f3ee7feb9" [[package]] name = "base64ct" @@ -625,13 +627,13 @@ dependencies = [ "lazy_static", "lazycell", "peeking_take_while", - "prettyplease 0.2.15", + "prettyplease 0.2.16", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -660,7 +662,7 @@ dependencies = [ "bitcoin_hashes 0.13.0", "hex-conservative", "hex_lit", - "secp256k1 0.28.0", + "secp256k1 0.28.1", "serde", ] @@ -902,7 +904,7 @@ version = "0.46.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7c8c50262271cdf5abc979a5f76515c234e764fa025d1ba4862c0f0bcda0e95" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.7", "cached_proc_macro", "cached_proc_macro_types", "hashbrown 0.14.3", @@ -981,9 +983,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" dependencies = [ "glob", "libc", @@ -1073,9 +1075,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -1100,44 +1102,37 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.17" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.18" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crunchy" @@ -1225,9 +1220,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.111" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9fc0c733f71e58dedf4f034cd2a266f80b94cc9ed512729e1798651b68c2cba" +checksum = "8de00f15a6fa069c99b88c5c78c4541d0e7899a33b86f7480e23df2431fce0bc" dependencies = [ "cc", "cxxbridge-flags", @@ -1237,9 +1232,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.111" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51bc81d2664db24cf1d35405f66e18a85cffd4d49ab930c71a5c6342a410f38c" +checksum = "0a71e1e631fa2f2f5f92e8b0d860a00c198c6771623a6cefcc863e3554f0d8d6" dependencies = [ "cc", "codespan-reporting", @@ -1247,36 +1242,36 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] name = "cxx-gen" -version = "0.7.111" +version = "0.7.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fff9b9f62092944662d561f5d2202e64490094faa0b96b09102cf6eabdb55cb" +checksum = "65428c17c352f476b40ac6f497c86f9cb365bff3d35d18af68705d6630546849" dependencies = [ "codespan-reporting", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] name = "cxxbridge-flags" -version = "1.0.111" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8511afbe34ea242697784da5cb2c5d4a0afb224ca8b136bdf93bfe180cbe5884" +checksum = "6f3fed61d56ba497c4efef9144dfdbaa25aa58f2f6b3a7cf441d4591c583745c" [[package]] name = "cxxbridge-macro" -version = "1.0.111" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6888cd161769d65134846d4d4981d5a6654307cc46ec83fb917e530aea5f84" +checksum = "8908e380a8efd42150c017b0cfa31509fc49b6d47f7cb6b33e93ffb8f4e3661e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -1324,7 +1319,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -1346,7 +1341,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core 0.20.3", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -1361,9 +1356,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", "serde", @@ -1389,17 +1384,17 @@ checksum = "3ae2a35373c5c74340b79ae6780b498b2b183915ec5dacf263aac5a099bf485a" [[package]] name = "dftx-macro" version = "0.1.0" -source = "git+https://github.com/Jouzo/dftx-rs.git#97fd965134968e19f8990ed27ef9b2a279e45089" +source = "git+https://github.com/Jouzo/dftx-rs.git#e10dea303487f3c0bf5f851669c939a027b8e034" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] name = "dftx-rs" version = "0.1.0" -source = "git+https://github.com/Jouzo/dftx-rs.git#97fd965134968e19f8990ed27ef9b2a279e45089" +source = "git+https://github.com/Jouzo/dftx-rs.git#e10dea303487f3c0bf5f851669c939a027b8e034" dependencies = [ "anyhow", "bitcoin", @@ -1768,7 +1763,7 @@ dependencies = [ "path-slash", "rayon", "regex", - "semver 1.0.20", + "semver 1.0.21", "serde", "serde_json", "solang-parser", @@ -2009,7 +2004,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -2214,7 +2209,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.7", ] [[package]] @@ -2223,7 +2218,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.7", "allocator-api2", ] @@ -2502,9 +2497,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -3091,18 +3086,18 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.151" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" dependencies = [ "cfg-if", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -3188,9 +3183,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.12" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" +checksum = "5f526fdd09d99e19742883e43de41e1aa9e36db0c7ab7f935165d611c5cccc66" dependencies = [ "cc", "pkg-config", @@ -3566,23 +3561,23 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -3850,7 +3845,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -3888,7 +3883,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -3949,12 +3944,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" dependencies = [ "proc-macro2", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -4017,9 +4012,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.71" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] @@ -4105,9 +4100,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -4293,22 +4288,22 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53313ec9f12686aeeffb43462c3ac77aa25f590a5f630eb2cde0de59417b29c7" +checksum = "c4846d4c50d1721b1a3bef8af76924eef20d5e723647333798c1b519b3a9473f" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2566c4bf6845f2c2e83b27043c3f5dfcd5ba8f2937d6c00dc009bfb51a079dc4" +checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -4376,7 +4371,7 @@ version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ - "base64 0.21.5", + "base64 0.21.6", "bytes", "encoding_rs", "futures-core", @@ -4585,7 +4580,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.5", + "base64 0.21.6", ] [[package]] @@ -4669,7 +4664,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.7", "cfg-if", "hashbrown 0.13.2", ] @@ -4739,12 +4734,12 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acea373acb8c21ecb5a23741452acd2593ed44ee3d343e72baaa143bc89d0d5" +checksum = "3f622567e3b4b38154fb8190bcf6b160d7a4301d70595a49195b48c116007a27" dependencies = [ "bitcoin_hashes 0.13.0", - "secp256k1-sys 0.9.1", + "secp256k1-sys 0.9.2", "serde", ] @@ -4759,9 +4754,9 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd97a086ec737e30053fd5c46f097465d25bb81dd3608825f65298c4c98be83" +checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" dependencies = [ "cc", ] @@ -4809,9 +4804,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" dependencies = [ "serde", ] @@ -4824,29 +4819,29 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "itoa", "ryu", @@ -4855,9 +4850,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" +checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c" dependencies = [ "itoa", "serde", @@ -4881,7 +4876,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" dependencies = [ - "base64 0.21.5", + "base64 0.21.6", "chrono", "hex", "indexmap 1.9.3", @@ -4901,7 +4896,7 @@ dependencies = [ "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -5156,7 +5151,7 @@ checksum = "f12dae7cf6c1e825d13ffd4ce16bd9309db7c539929d0302b4443ed451a9f4e5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -5250,7 +5245,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -5314,7 +5309,7 @@ version = "23.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf63ea90ffb5d61048d8fb2fac669114dac198fc2739e913e615f0fd2c36c3e7" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.7", "hash-db 0.16.0", "hashbrown 0.13.2", "lazy_static", @@ -5373,9 +5368,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.44.0" +version = "1.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35935738370302d5e33963665b77541e4b990a3e919ec904c837a56cfc891de1" +checksum = "3c0c74081753a8ce1c8eb10b9f262ab6f7017e5ad3317c17a54c7ab65fcb3c6e" dependencies = [ "Inflector", "num-format", @@ -5479,7 +5474,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -5525,7 +5520,7 @@ dependencies = [ "hex", "once_cell", "reqwest", - "semver 1.0.20", + "semver 1.0.21", "serde", "serde_json", "sha2 0.10.8", @@ -5547,9 +5542,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.43" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -5591,9 +5586,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.12" +version = "0.12.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" +checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae" [[package]] name = "tarpc" @@ -5684,22 +5679,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.52" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a48fd946b02c0a526b2e9481c8e2a17755e47039164a86c4070446e3a4614d" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.52" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7fbe9b594d6568a6a1443250a7e67d80b74e1e96f6d1715e1e21cc1888291d3" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -5830,7 +5825,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -5918,7 +5913,7 @@ checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" dependencies = [ "async-trait", "axum 0.6.20", - "base64 0.21.5", + "base64 0.21.6", "bytes", "futures-core", "futures-util", @@ -5978,7 +5973,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ "async-compression", - "base64 0.21.5", + "base64 0.21.6", "bitflags 2.4.1", "bytes", "futures-core", @@ -6033,7 +6028,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -6408,7 +6403,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -6442,7 +6437,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6666,11 +6661,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.52.0", ] [[package]] @@ -6873,9 +6868,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.31" +version = "0.5.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c" +checksum = "b7520bbdec7211caa7c4e682eb1fbe07abe20cee6756b6e00f537c82c11816aa" dependencies = [ "memchr", ] @@ -6922,7 +6917,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -6942,7 +6937,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index f141604ce1c..809d16cb037 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -6,17 +6,13 @@ use axum::{ use bitcoin::BlockHash; use crate::{ - api_paged_response::ApiPagedResponse, - api_query::PaginationQuery, - error::OceanResult, - SERVICES, - repository::RepositoryOps, - model::Block, + api_paged_response::ApiPagedResponse, api_query::PaginationQuery, model::Block, + repository::RepositoryOps, Result, SERVICES, }; async fn list_blocks( Query(query): Query, -) -> OceanResult>> { +) -> Result>> { let blocks = SERVICES .block .by_height @@ -32,20 +28,15 @@ async fn list_blocks( Ok(b) }) - .collect::>>()?; + .collect::>>()?; - Ok(Json(ApiPagedResponse::of( - blocks, - query.size, - |block| block.clone().id, - ))) + Ok(Json(ApiPagedResponse::of(blocks, query.size, |block| { + block.clone().id + }))) } -async fn get_block(Path(id): Path) -> OceanResult>> { - let block = SERVICES - .block - .by_id - .get(&id)?; +async fn get_block(Path(id): Path) -> Result>> { + let block = SERVICES.block.by_id.get(&id)?; Ok(Json(block)) } diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index 1b0e911463e..98c8d8c8cfb 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -7,8 +7,8 @@ use bitcoin::Txid; use log::debug; use crate::{ - api_paged_response::ApiPagedResponse, api_query::PaginationQuery, error::OceanResult, - model::VaultAuctionBatchHistory, repository::RepositoryOps, SERVICES, + api_paged_response::ApiPagedResponse, api_query::PaginationQuery, + model::VaultAuctionBatchHistory, repository::RepositoryOps, Result, SERVICES, }; async fn list_scheme() -> String { @@ -46,7 +46,7 @@ async fn get_vault(Path(vault_id): Path) -> String { async fn list_vault_auction_history( Path((vault_id, height, batch_index)): Path<(Txid, u32, u32)>, Query(query): Query, -) -> OceanResult>> { +) -> Result>> { println!("listvault auction history"); debug!( "Auction history for vault id {}, height {}, batch index {}", @@ -92,7 +92,7 @@ async fn list_vault_auction_history( Ok(auction) }) - .collect::>>()?; + .collect::>>()?; Ok(Json(ApiPagedResponse::of( auctions, diff --git a/lib/ain-ocean/src/api/masternode.rs b/lib/ain-ocean/src/api/masternode.rs index e2872415c57..9ef015d88e0 100644 --- a/lib/ain-ocean/src/api/masternode.rs +++ b/lib/ain-ocean/src/api/masternode.rs @@ -7,8 +7,8 @@ use bitcoin::Txid; use serde::{Deserialize, Serialize}; use crate::{ - api_paged_response::ApiPagedResponse, api_query::PaginationQuery, error::OceanResult, - model::Masternode, repository::RepositoryOps, SERVICES, + api_paged_response::ApiPagedResponse, api_query::PaginationQuery, model::Masternode, + repository::RepositoryOps, Result, SERVICES, }; #[derive(Serialize, Deserialize, Debug, Default, Clone)] @@ -89,7 +89,7 @@ impl From for MasternodeData { async fn list_masternodes( Query(query): Query, -) -> OceanResult>> { +) -> Result>> { let next = query .next .map(|q| { @@ -120,7 +120,7 @@ async fn list_masternodes( Ok(mn.into()) }) - .collect::>>()?; + .collect::>>()?; Ok(Json(ApiPagedResponse::of( masternodes, @@ -129,9 +129,7 @@ async fn list_masternodes( ))) } -async fn get_masternode( - Path(masternode_id): Path, -) -> OceanResult>> { +async fn get_masternode(Path(masternode_id): Path) -> Result>> { let mn = SERVICES .masternode .by_id diff --git a/lib/ain-ocean/src/api/poolpairs.rs b/lib/ain-ocean/src/api/poolpairs.rs index d8a89dcc1e3..7246c062eba 100644 --- a/lib/ain-ocean/src/api/poolpairs.rs +++ b/lib/ain-ocean/src/api/poolpairs.rs @@ -1,9 +1,18 @@ use axum::{ extract::{Path, Query}, routing::get, - Router, + Json, Router, +}; +use log::debug; +use serde::{Deserialize, Serialize}; + +use crate::{ + api_paged_response::ApiPagedResponse, + api_query::PaginationQuery, + model::{BlockContext, PoolSwap}, + repository::RepositoryOps, + Result, SERVICES, }; -use serde::Deserialize; #[derive(Deserialize)] struct PoolPair { @@ -32,6 +41,57 @@ struct DexPrices { denomination: Option, } +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PoolSwapFromToData { + address: String, + amount: String, + // symbol: String, + // display_symbol: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PoolSwapData { + id: String, + sort: String, + txid: String, + txno: usize, + pool_pair_id: String, + from_amount: String, + from_token_id: u64, + block: BlockContext, + from: PoolSwapFromToData, + to: PoolSwapFromToData, +} + +impl From for PoolSwapData { + fn from(v: PoolSwap) -> Self { + Self { + id: v.id, + sort: v.sort, + txid: v.txid.to_string(), + txno: v.txno, + pool_pair_id: v.pool_id.to_string(), + from_amount: v.from_amount.to_string(), + from_token_id: v.from_token_id, + from: PoolSwapFromToData { + address: v.from.to_hex_string(), + amount: v.from_amount.to_string(), + // symbol: todo!(), + // display_symbol: todo!(), + }, + to: PoolSwapFromToData { + address: v.to.to_hex_string(), + amount: v.to_amount.to_string(), + // symbol: todo!(), + // display_symbol: todo!(), + }, + block: v.block, + } + } +} + async fn list_poolpairs() -> String { "List of poolpairs".to_string() } @@ -40,12 +100,55 @@ async fn get_poolpair(Path(PoolPair { id }): Path) -> String { format!("Details of poolpair with id {}", id) } -async fn list_pool_swaps(Path(PoolPair { id }): Path) -> String { - format!("List of swaps for poolpair {}", id) -} +// Use single method for now since additional verbose keys are indexed +// TODO: assess need for additional verbose method +async fn list_pool_swaps( + Path(id): Path, + Query(query): Query, +) -> Result>> { + debug!("list_pool_swaps for id {id}",); + let next = query + .next + .map(|q| { + let parts: Vec<&str> = q.split('-').collect(); + if parts.len() != 2 { + return Err("Invalid query format"); + } + + let height = parts[0].parse::().map_err(|_| "Invalid height")?; + let txno = parts[1].parse::().map_err(|_| "Invalid txno")?; + + Ok((height, txno)) + }) + .transpose()? + .unwrap_or_default(); + + debug!("next : {:?}", next); + + let size = if query.size > 0 && query.size < 20 { + query.size + } else { + 20 + }; + + let swaps = SERVICES + .pool + .by_id + .list(Some((id, next.0, next.1)))? + .take(size) + .take_while(|item| match item { + Ok((k, _)) => k.0 == id, + _ => true, + }) + .map(|item| { + let (_, swap) = item?; + Ok(PoolSwapData::from(swap)) + }) + .collect::>>()?; -async fn list_pool_swaps_verbose(Path(PoolPair { id }): Path) -> String { - format!("Verbose list of swaps for poolpair {}", id) + Ok(Json(ApiPagedResponse::of(swaps, query.size, |swap| { + swap.sort.to_string() + }))) } async fn list_pool_swap_aggregates( @@ -94,7 +197,7 @@ pub fn router() -> Router { .route("/", get(list_poolpairs)) .route("/:id", get(get_poolpair)) .route("/:id/swaps", get(list_pool_swaps)) - .route("/:id/swaps/verbose", get(list_pool_swaps_verbose)) + .route("/:id/swaps/verbose", get(list_pool_swaps)) .route( "/:id/swaps/aggregate/:interval", get(list_pool_swap_aggregates), diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 1f08d709a28..83d3e9fb5c7 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -1,14 +1,13 @@ use std::num::ParseIntError; use ain_db::DBError; +use anyhow::format_err; use axum::{ http::StatusCode, response::{IntoResponse, Response}, }; use bitcoin::hex::HexToArrayError; use thiserror::Error; -pub type OceanResult = Result; -use anyhow::format_err; #[derive(Error, Debug)] pub enum OceanError { @@ -18,6 +17,12 @@ pub enum OceanError { ParseIntError(#[from] ParseIntError), #[error("Ocean: DBError error: {0:?}")] DBError(#[from] DBError), + #[error("Ocean: IO error: {0:?}")] + IOError(#[from] std::io::Error), + #[error("Ocean: FromHexError error: {0:?}")] + FromHexError(#[from] hex::FromHexError), + #[error("Ocean: Consensus encode error: {0:?}")] + ConsensusEncodeError(#[from] bitcoin::consensus::encode::Error), #[error(transparent)] Other(#[from] anyhow::Error), } diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 0a81fda0c78..66667757b1d 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -2,24 +2,22 @@ mod auction; mod masternode; mod oracle; mod pool; +pub mod tx_result; -use dftx_rs::Transaction; - -pub(crate) trait Index { - fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()>; - fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()>; -} - -use dftx_rs::{deserialize, Block, DfTx}; +use dftx_rs::{deserialize, Block, DfTx, Transaction}; use log::debug; use crate::{ - model::{BlockContext, Block as BlockMapper}, + model::{Block as BlockMapper, BlockContext}, repository::RepositoryOps, - Result, - SERVICES, + Result, SERVICES, }; +pub(crate) trait Index { + fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()>; + fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()>; +} + pub struct BlockV2Info { pub height: u32, pub difficulty: u32, @@ -68,7 +66,7 @@ pub fn index_block(encoded_block: String, info: &BlockV2Info) -> Result<()> { weight: info.weight, }; - SERVICES.block.raw.put(&ctx.hash, &encoded_block)?; + SERVICES.block.raw.put(&ctx.hash, &encoded_block)?; SERVICES.block.by_id.put(&ctx.hash, &block_mapper)?; SERVICES.block.by_height.put(&ctx.height, &block_hash)?; @@ -84,6 +82,7 @@ pub fn index_block(encoded_block: String, info: &BlockV2Info) -> Result<()> { let raw_tx = &bytes[offset..]; let dftx = deserialize::(raw_tx)?; + debug!("dftx : {:?}", dftx); match dftx { DfTx::CreateMasternode(data) => data.index(&ctx, tx, idx)?, DfTx::UpdateMasternode(data) => data.index(&ctx, tx, idx)?, @@ -92,8 +91,8 @@ pub fn index_block(encoded_block: String, info: &BlockV2Info) -> Result<()> { // DfTx::RemoveOracle(data) => data.index(&ctx, tx, idx)?, // DfTx::UpdateOracle(data) => data.index(&ctx, tx, idx)?, // DfTx::SetOracleData(data) => data.index(&ctx, tx, idx)?, - // DfTx::PoolSwap(data) => data.index(&ctx, tx, idx)?, - // DfTx::CompositeSwap(data) => data.index(&ctx, tx, idx)?, + DfTx::PoolSwap(data) => data.index(&ctx, tx, idx)?, + DfTx::CompositeSwap(data) => data.index(&ctx, tx, idx)?, DfTx::PlaceAuctionBid(data) => data.index(&ctx, tx, idx)?, _ => (), } diff --git a/lib/ain-ocean/src/indexer/pool.rs b/lib/ain-ocean/src/indexer/pool.rs index 4a23319e7ae..6e134ff0c1b 100644 --- a/lib/ain-ocean/src/indexer/pool.rs +++ b/lib/ain-ocean/src/indexer/pool.rs @@ -1,24 +1,98 @@ use dftx_rs::{pool::*, Transaction}; +use log::debug; -use super::BlockContext; -use crate::indexer::{Index, Result}; +use crate::{ + indexer::{tx_result, Index, Result}, + model::{self, BlockContext, PoolSwapResult, TxResult}, + repository::RepositoryOps, + SERVICES, +}; impl Index for PoolSwap { fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { - todo!() + debug!("[Poolswap] Indexing..."); + let txid = tx.txid(); + let Some(TxResult::PoolSwap(PoolSwapResult { to_amount, pool_id })) = + SERVICES.result.get(&txid)? + else { + println!("Missing swap result for {}", tx.txid().to_string()); + return Err("Missing swap result".into()); + }; + + let swap = model::PoolSwap { + id: format!("{}-{}", pool_id, txid), + sort: format!("{}-{}", ctx.height, idx), + txid: txid, + txno: idx, + from_amount: self.from_amount, + from_token_id: self.from_token_id.0, + to_token_id: self.to_token_id.0, + to_amount, + pool_id, + from: self.from_script.clone(), + to: self.to_script.clone(), + block: ctx.clone(), + }; + debug!("swap : {:?}", swap); + + SERVICES.pool.by_id.put(&(pool_id, ctx.height, idx), &swap) } - fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { - todo!() + fn invalidate(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + let txid = tx.txid(); + let Some(TxResult::PoolSwap(PoolSwapResult { pool_id, .. })) = + SERVICES.result.get(&txid)? + else { + return Err("Missing swap result".into()); + }; + + SERVICES.pool.by_id.delete(&(pool_id, ctx.height, idx))?; + tx_result::invalidate(&txid) } } impl Index for CompositeSwap { fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { - todo!() + debug!("[CompositeSwap] Indexing..."); + let txid = tx.txid(); + let Some(TxResult::PoolSwap(PoolSwapResult { to_amount, .. })) = + SERVICES.result.get(&txid)? + else { + println!("Missing swap result for {}", txid.to_string()); + return Err("Missing swap result".into()); + }; + + for pool in self.pools.as_ref() { + let pool_id = pool.id.0 as u32; + let swap = model::PoolSwap { + id: format!("{}-{}", pool_id, txid), + sort: format!("{}-{}", ctx.height, idx), + txid: txid, + txno: idx, + from_amount: self.pool_swap.from_amount, + from_token_id: self.pool_swap.from_token_id.0, + to_token_id: self.pool_swap.to_token_id.0, + to_amount, + pool_id, + from: self.pool_swap.from_script.clone(), + to: self.pool_swap.to_script.clone(), + block: ctx.clone(), + }; + debug!("swap : {:?}", swap); + SERVICES + .pool + .by_id + .put(&(pool_id, ctx.height, idx), &swap)?; + } + + Ok(()) } - fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { - todo!() + fn invalidate(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + for pool in self.pools.as_ref() { + let pool_id = pool.id.0 as u32; + SERVICES.pool.by_id.delete(&(pool_id, ctx.height, idx))?; + } + tx_result::invalidate(&tx.txid()) } } diff --git a/lib/ain-ocean/src/indexer/tx_result.rs b/lib/ain-ocean/src/indexer/tx_result.rs new file mode 100644 index 00000000000..1f86843af52 --- /dev/null +++ b/lib/ain-ocean/src/indexer/tx_result.rs @@ -0,0 +1,15 @@ +use bitcoin::{hashes::Hash, Txid}; + +use crate::{model::TxResult, repository::RepositoryOps, Result, SERVICES}; + +pub fn index(tx_type: u8, tx_hash: [u8; 32], result_ptr: usize) -> Result<()> { + let txid = Txid::from_byte_array(tx_hash); + let result = TxResult::from((tx_type, result_ptr)); + println!("txid : {:?}", txid); + println!("result : {:?}", result); + SERVICES.result.put(&txid, &result) +} + +pub fn invalidate(txid: &Txid) -> Result<()> { + SERVICES.result.delete(txid) +} diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 2f170c8d958..0d421cc0dc9 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -6,19 +6,21 @@ mod indexer; use std::{path::PathBuf, sync::Arc}; pub use api::ocean_router; -pub use indexer::{BlockV2Info, index_block, invalidate_block}; +use error::OceanError; +pub use indexer::{index_block, invalidate_block, tx_result, BlockV2Info}; use repository::{ AuctionHistoryByHeightRepository, AuctionHistoryRepository, BlockByHeightRepository, BlockRepository, MasternodeByHeightRepository, MasternodeRepository, MasternodeStatsRepository, - RawBlockRepository, + PoolSwapRepository, RawBlockRepository, TxResultRepository, }; pub mod api; mod model; mod repository; pub mod storage; + use crate::storage::ocean_store::OceanStore; -pub(crate) type Result = std::result::Result>; +pub type Result = std::result::Result; lazy_static::lazy_static! { // Global services exposed by the library @@ -48,10 +50,16 @@ pub struct AuctionService { by_height: AuctionHistoryByHeightRepository, } +pub struct PoolService { + by_id: PoolSwapRepository, +} + pub struct Services { masternode: MasternodeService, block: BlockService, auction: AuctionService, + result: TxResultRepository, + pool: PoolService, } impl Services { @@ -71,6 +79,10 @@ impl Services { by_id: AuctionHistoryRepository::new(Arc::clone(&store)), by_height: AuctionHistoryByHeightRepository::new(Arc::clone(&store)), }, + result: TxResultRepository::new(Arc::clone(&store)), + pool: PoolService { + by_id: PoolSwapRepository::new(Arc::clone(&store)), + }, } } } diff --git a/lib/ain-ocean/src/model/mod.rs b/lib/ain-ocean/src/model/mod.rs index d23d80a0b86..e40062f6941 100644 --- a/lib/ain-ocean/src/model/mod.rs +++ b/lib/ain-ocean/src/model/mod.rs @@ -18,6 +18,7 @@ mod script_unspent; mod transaction; mod transaction_vin; mod transaction_vout; +mod tx_result; mod vault_auction_batch_history; pub use block::*; @@ -40,4 +41,5 @@ pub use script_unspent::*; pub use transaction::*; pub use transaction_vin::*; pub use transaction_vout::*; +pub use tx_result::*; pub use vault_auction_batch_history::*; diff --git a/lib/ain-ocean/src/model/poolswap.rs b/lib/ain-ocean/src/model/poolswap.rs index 86cb1528b6d..ace6dadf4b2 100644 --- a/lib/ain-ocean/src/model/poolswap.rs +++ b/lib/ain-ocean/src/model/poolswap.rs @@ -1,16 +1,23 @@ +use bitcoin::{ScriptBuf, Txid}; use serde::{Deserialize, Serialize}; use super::BlockContext; +pub type PoolSwapKey = (u32, u32, usize); + #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct PoolSwap { pub id: String, - pub txid: String, - pub txno: i32, - pub pool_pair_id: String, + pub txid: Txid, + pub txno: usize, + pub pool_id: u32, pub sort: String, - pub from_amount: String, - pub from_token_id: i32, + pub from_amount: i64, + pub from_token_id: u64, + pub to_amount: i64, + pub to_token_id: u64, + pub from: ScriptBuf, + pub to: ScriptBuf, pub block: BlockContext, } diff --git a/lib/ain-ocean/src/model/tx_result.rs b/lib/ain-ocean/src/model/tx_result.rs new file mode 100644 index 00000000000..435dba120a7 --- /dev/null +++ b/lib/ain-ocean/src/model/tx_result.rs @@ -0,0 +1,28 @@ +use dftx_rs::custom_tx::CustomTxType; +use serde::{Deserialize, Serialize}; + +#[repr(C)] +#[derive(Debug, Serialize, Deserialize, Clone, Copy)] +pub struct PoolSwapResult { + pub to_amount: i64, + pub pool_id: u32, +} + +#[derive(Serialize, Deserialize, Debug)] +pub enum TxResult { + PoolSwap(PoolSwapResult), + None, +} + +impl From<(u8, usize)> for TxResult { + fn from((tx_type, result_ptr): (u8, usize)) -> Self { + let dftx = CustomTxType::from(tx_type); + + match dftx { + CustomTxType::PoolSwap | CustomTxType::PoolSwapV2 => { + TxResult::PoolSwap(unsafe { *(result_ptr as *const PoolSwapResult) }) + } + _ => TxResult::None, + } + } +} diff --git a/lib/ain-ocean/src/repository/mod.rs b/lib/ain-ocean/src/repository/mod.rs index 75ec0cefafa..a8b9f282a4f 100644 --- a/lib/ain-ocean/src/repository/mod.rs +++ b/lib/ain-ocean/src/repository/mod.rs @@ -19,6 +19,7 @@ mod test; mod transaction; mod transaction_vin; mod transaction_vout; +mod tx_result; mod vault_auction_batch_history; pub use block::*; @@ -40,6 +41,7 @@ pub use test::*; pub use transaction::*; pub use transaction_vin::*; pub use transaction_vout::*; +pub use tx_result::*; pub use vault_auction_batch_history::*; pub trait RepositoryOps { diff --git a/lib/ain-ocean/src/repository/pool_swap.rs b/lib/ain-ocean/src/repository/pool_swap.rs index 8b137891791..53bfa3e432e 100644 --- a/lib/ain-ocean/src/repository/pool_swap.rs +++ b/lib/ain-ocean/src/repository/pool_swap.rs @@ -1 +1,27 @@ +use std::sync::Arc; +use ain_db::LedgerColumn; +use ain_macros::Repository; + +use super::RepositoryOps; +use crate::{ + model::{PoolSwap, PoolSwapKey}, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "PoolSwapKey", V = "PoolSwap")] +pub struct PoolSwapRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl PoolSwapRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} diff --git a/lib/ain-ocean/src/repository/tx_result.rs b/lib/ain-ocean/src/repository/tx_result.rs new file mode 100644 index 00000000000..6ca87229d75 --- /dev/null +++ b/lib/ain-ocean/src/repository/tx_result.rs @@ -0,0 +1,28 @@ +use std::sync::Arc; + +use ain_db::LedgerColumn; +use ain_macros::Repository; +use bitcoin::Txid; + +use super::RepositoryOps; +use crate::{ + model::TxResult, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "Txid", V = "TxResult")] +pub struct TxResultRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl TxResultRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} diff --git a/lib/ain-ocean/src/storage/columns/mod.rs b/lib/ain-ocean/src/storage/columns/mod.rs index 2283a873d1c..d892df2bfe8 100644 --- a/lib/ain-ocean/src/storage/columns/mod.rs +++ b/lib/ain-ocean/src/storage/columns/mod.rs @@ -17,6 +17,7 @@ mod script_unspent; mod transaction; mod transaction_vin; mod transaction_vout; +mod tx_result; mod vault_auction_history; use ain_db::ColumnName; @@ -39,9 +40,10 @@ pub use script_unspent::*; pub use transaction::*; pub use transaction_vin::*; pub use transaction_vout::*; +pub use tx_result::*; pub use vault_auction_history::*; -pub const COLUMN_NAMES: [&'static str; 23] = [ +pub const COLUMN_NAMES: [&'static str; 24] = [ block::Block::NAME, block::BlockByHeight::NAME, masternode_stats::MasternodeStats::NAME, @@ -63,6 +65,7 @@ pub const COLUMN_NAMES: [&'static str; 23] = [ transaction::Transaction::NAME, transaction_vin::TransactionVin::NAME, transaction_vout::TransactionVout::NAME, + tx_result::TxResult::NAME, vault_auction_history::VaultAuctionHistory::NAME, vault_auction_history::VaultAuctionHistoryByHeight::NAME, ]; diff --git a/lib/ain-ocean/src/storage/columns/pool_swap.rs b/lib/ain-ocean/src/storage/columns/pool_swap.rs index 1b79dda32a1..db9905dd469 100644 --- a/lib/ain-ocean/src/storage/columns/pool_swap.rs +++ b/lib/ain-ocean/src/storage/columns/pool_swap.rs @@ -1,5 +1,7 @@ use ain_db::{Column, ColumnName, TypedColumn}; +use crate::model; + #[derive(Debug)] pub struct PoolSwap; @@ -8,9 +10,9 @@ impl ColumnName for PoolSwap { } impl Column for PoolSwap { - type Index = String; + type Index = model::PoolSwapKey; } impl TypedColumn for PoolSwap { - type Type = String; + type Type = model::PoolSwap; } diff --git a/lib/ain-ocean/src/storage/columns/tx_result.rs b/lib/ain-ocean/src/storage/columns/tx_result.rs new file mode 100644 index 00000000000..03bbc04f0cc --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/tx_result.rs @@ -0,0 +1,19 @@ +use ain_db::{Column, ColumnName, TypedColumn}; +use bitcoin::Txid; + +use crate::model; + +#[derive(Debug)] +pub struct TxResult; + +impl ColumnName for TxResult { + const NAME: &'static str = "tx_result"; +} + +impl Column for TxResult { + type Index = Txid; +} + +impl TypedColumn for TxResult { + type Type = model::TxResult; +} diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index 1b84300e7fb..40de0bac01d 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -367,6 +367,13 @@ pub mod ffi { block: String, info: &BlockV2Info, ); + + fn ocean_try_set_tx_result( + result: &mut CrossBoundaryResult, + tx_type: u8, + tx_hash: [u8; 32], + result_ptr: usize, + ); } // ========= Debug ========== diff --git a/lib/ain-rs-exports/src/ocean.rs b/lib/ain-rs-exports/src/ocean.rs index 1f58753c8c4..619e93547b8 100644 --- a/lib/ain-rs-exports/src/ocean.rs +++ b/lib/ain-rs-exports/src/ocean.rs @@ -1,5 +1,11 @@ -use crate::ffi::{BlockV2Info as BlockV2InfoFFI, CrossBoundaryResult}; -use ain_ocean::BlockV2Info; +use ain_macros::ffi_fallible; +use ain_ocean::{BlockV2Info, Result}; + +use crate::{ + ffi, + ffi::BlockV2Info as BlockV2InfoFFI, + prelude::{cross_boundary_error_return, cross_boundary_success_return}, +}; // manually convert since BlockV2InfoFFI is belongs to CPP which can't impl From -> Into pub fn convert(b: &BlockV2InfoFFI) -> BlockV2Info { @@ -18,22 +24,17 @@ pub fn convert(b: &BlockV2InfoFFI) -> BlockV2Info { } } -pub fn ocean_index_block(result: &mut CrossBoundaryResult, block: String, b: &BlockV2InfoFFI) { - match ain_ocean::index_block(block, &convert(b)) { - Ok(()) => result.ok = true, - Err(e) => { - result.ok = false; - result.reason = e.to_string() - } - } +#[ffi_fallible] +pub fn ocean_index_block(block: String, b: &BlockV2InfoFFI) -> Result<()> { + ain_ocean::index_block(block, &convert(b)) } -pub fn ocean_invalidate_block(result: &mut CrossBoundaryResult, block: String, b: &BlockV2InfoFFI) { - match ain_ocean::invalidate_block(block, &convert(b)) { - Ok(()) => result.ok = true, - Err(e) => { - result.ok = false; - result.reason = e.to_string() - } - } +#[ffi_fallible] +pub fn ocean_invalidate_block(block: String, b: &BlockV2InfoFFI) -> Result<()> { + ain_ocean::invalidate_block(block, &convert(b)) +} + +#[ffi_fallible] +fn ocean_try_set_tx_result(tx_type: u8, tx_hash: [u8; 32], result_ptr: usize) -> Result<()> { + ain_ocean::tx_result::index(tx_type, tx_hash, result_ptr) } diff --git a/src/dfi/consensus/poolpairs.cpp b/src/dfi/consensus/poolpairs.cpp index dfd81766ab4..20e61750a08 100644 --- a/src/dfi/consensus/poolpairs.cpp +++ b/src/dfi/consensus/poolpairs.cpp @@ -129,9 +129,10 @@ Res CPoolPairsConsensus::operator()(const CPoolSwapMessage &obj) const { const auto &consensus = txCtx.GetConsensus(); const auto height = txCtx.GetHeight(); + const auto &tx = txCtx.GetTransaction(); auto &mnview = blockCtx.GetView(); - return CPoolSwap(obj, height).ExecuteSwap(mnview, {}, consensus); + return CPoolSwap(obj, height, std::make_pair(CustomTxType::PoolSwap, tx.GetHash())).ExecuteSwap(mnview, {}, consensus); } Res CPoolPairsConsensus::operator()(const CPoolSwapMessageV2 &obj) const { @@ -142,9 +143,10 @@ Res CPoolPairsConsensus::operator()(const CPoolSwapMessageV2 &obj) const { const auto &consensus = txCtx.GetConsensus(); const auto height = txCtx.GetHeight(); + const auto &tx = txCtx.GetTransaction(); auto &mnview = blockCtx.GetView(); - return CPoolSwap(obj.swapInfo, height).ExecuteSwap(mnview, obj.poolIDs, consensus); + return CPoolSwap(obj.swapInfo, height, std::make_pair(CustomTxType::PoolSwapV2, tx.GetHash())).ExecuteSwap(mnview, obj.poolIDs, consensus); } Res CPoolPairsConsensus::operator()(const CLiquidityMessage &obj) const { diff --git a/src/dfi/mn_checks.cpp b/src/dfi/mn_checks.cpp index baa61653f30..8672cd2fbd3 100644 --- a/src/dfi/mn_checks.cpp +++ b/src/dfi/mn_checks.cpp @@ -970,6 +970,13 @@ Res CPoolSwap::ExecuteSwap(CCustomCSView &view, // Set amount to be swapped in pool CTokenAmount swapAmountResult{obj.idTokenFrom, obj.amountFrom}; + struct PoolSwapResult { + int64_t toAmount; + uint32_t poolId; + }; + + PoolSwapResult finalSwapAmount; + for (size_t i{0}; i < poolIDs.size(); ++i) { // Also used to generate pool specific error messages for RPC users currentID = poolIDs[i]; @@ -1076,8 +1083,6 @@ Res CPoolSwap::ExecuteSwap(CCustomCSView &view, } intermediateView.Flush(); - const auto token = view.GetToken("DUSD"); - // burn the dex in amount if (dexfeeInAmount.nValue > 0) { res = view.AddBalance(consensus.burnAddress, dexfeeInAmount); @@ -1099,8 +1104,12 @@ Res CPoolSwap::ExecuteSwap(CCustomCSView &view, totalTokenA.swaps += (reserveAmount - initReserveAmount); totalTokenA.commissions += (blockCommission - initBlockCommission); - if (lastSwap && obj.to == consensus.burnAddress) { - totalTokenB.feeburn += swapAmountResult.nValue; + if (lastSwap) { + if (obj.to == consensus.burnAddress) { + totalTokenB.feeburn += swapAmountResult.nValue; + } + + finalSwapAmount = {swapAmountResult.nValue, currentID.v}; } return res; @@ -1135,6 +1144,13 @@ Res CPoolSwap::ExecuteSwap(CCustomCSView &view, // Assign to result for loop testing best pool swap result result = swapAmountResult.nValue; + // Send final swap amount Rust side for indexer + if (txInfo) { + const auto &[txType, txHash] = *txInfo; + CrossBoundaryResult ffiResult; + ocean_try_set_tx_result(ffiResult, static_cast(txType), txHash.GetByteArray(), static_cast(reinterpret_cast(&finalSwapAmount))); + } + return Res::Ok(); } diff --git a/src/dfi/mn_checks.h b/src/dfi/mn_checks.h index ba214400821..c757ed632d7 100644 --- a/src/dfi/mn_checks.h +++ b/src/dfi/mn_checks.h @@ -270,16 +270,18 @@ bool CheckOPReturnSize(const CScript &scriptPubKey, const uint32_t opreturnSize) class CPoolSwap { const CPoolSwapMessage &obj; - uint32_t height; - CAmount result{0}; - DCT_ID currentID; + const uint32_t height; + const std::optional> txInfo; + CAmount result{}; + DCT_ID currentID{}; public: std::vector> errors; - CPoolSwap(const CPoolSwapMessage &obj, uint32_t height) + CPoolSwap(const CPoolSwapMessage &obj, const uint32_t height, const std::optional> txInfo = std::nullopt) : obj(obj), - height(height) {} + height(height), + txInfo(txInfo) {} std::vector CalculateSwaps(CCustomCSView &view, const Consensus::Params &consensus, bool testOnly = false); Res ExecuteSwap(CCustomCSView &view, diff --git a/src/test/xvm_tests.cpp b/src/test/xvm_tests.cpp index cae4765ce27..d687660a013 100644 --- a/src/test/xvm_tests.cpp +++ b/src/test/xvm_tests.cpp @@ -12,7 +12,7 @@ BOOST_AUTO_TEST_CASE(xvm_test_case_1) { auto zero = uint256S("0x0"); auto one = uint256S("0x1"); - auto oneArr = uint256S("0x1").GetByteArray(); + auto oneArr = uint256S("0x1").GetByteArrayRev(); auto oneVec = std::vector(oneArr.begin(), oneArr.end()); auto oneVecReversed = std::vector(oneArr.begin(), oneArr.end()); std::reverse(oneVecReversed.begin(), oneVecReversed.end()); @@ -30,7 +30,7 @@ BOOST_AUTO_TEST_CASE(xvm_test_case_1) XVM xvm4; xvm4.evm.blockHash = uint256(oneVecReversed).GetHex(); - for (const auto& [result, expected]: std::vector> { + for (const auto& [result, expected]: std::vector> { { zero.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000" }, { one.GetHex(), "0000000000000000000000000000000000000000000000000000000000000001" }, { xvm.evm.blockHash, "0000000000000000000000000000000000000000000000000000000000000001" }, @@ -39,10 +39,10 @@ BOOST_AUTO_TEST_CASE(xvm_test_case_1) { xvm4.evm.blockHash, "0000000000000000000000000000000000000000000000000000000000000001" }, { xvm.evm.beneficiary, "00000000000000000002" }, { xvm2->evm.beneficiary, "00000000000000000002" }, - }) { + }) { // BOOST_TEST_MESSAGE("expected: " + expected + ", result: " + result); BOOST_CHECK(result == expected); }; } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/uint256.h b/src/uint256.h index 16346183ca2..dfef91f8de4 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -66,7 +66,7 @@ class base_blob ((uint64_t)ptr[7]) << 56; } - [[nodiscard]] std::array GetByteArray() const + [[nodiscard]] std::array GetByteArrayRev() const { // We store bytes in little endian. So any expectations of // an array of bytes should be in same order as the hex string. @@ -76,6 +76,13 @@ class base_blob return reversedArray; } + [[nodiscard]] std::array GetByteArray() const + { + std::array byteArray; + std::copy(data, data + WIDTH, byteArray.begin()); + return byteArray; + } + unsigned char* begin() { return &data[0]; From 0fe7ce71b0d8c9f433f6e9422e7229331a859e92 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Wed, 24 Jan 2024 17:17:41 +0800 Subject: [PATCH 029/185] Ocean: Genesis block indexed + missing mn info update (#2791) * add mn info * index genesis --- src/dfi/validation.cpp | 19 ++++++++++++++++-- src/init.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/dfi/validation.cpp b/src/dfi/validation.cpp index d236d2c86b8..f1df0756930 100644 --- a/src/dfi/validation.cpp +++ b/src/dfi/validation.cpp @@ -2809,8 +2809,23 @@ Res ProcessDeFiEventFallible(const CBlock &block, info.size_stripped = GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS); info.weight = GetBlockWeight(block); info.stake_modifier = pindex->stakeModifier.ToString(); - info.minter = "", // mn operator address - info.masternode = "", // mn owner address + info.minter = ""; // mn operator address + info.masternode = ""; // mn owner address + + // minter info + CKeyID minter; + block.ExtractMinterKey(minter); + + auto id = mnview.GetMasternodeIdByOperator(minter); + if (id) { + info.masternode = id->ToString(); + auto mn = mnview.GetMasternode(*id); + if (mn) { + auto dest = mn->operatorType == 1 ? CTxDestination(PKHash(minter)) : CTxDestination(WitnessV0KeyHash(minter)); + info.minter = EncodeDestination(dest); + } + } + ocean_index_block(result, serializedData, info); // if (!result.ok) { // return Res::Err(result.reason.c_str()); diff --git a/src/init.cpp b/src/init.cpp index c668d65c1ec..26178e6380a 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2561,5 +2561,50 @@ bool AppInitMain(InitInterfaces& interfaces) }); } + // ********************************************************* Step 16: start genesis ocean indexing + if(gArgs.GetBoolArg("-oceanarchive", DEFAULT_OCEAN_ARCHIVE_ENABLED)) { + const CBlock &block = chainparams.GenesisBlock(); + + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << block; + CBlockIndex* pindex = ::ChainActive().Tip(); + + // Convert the serialized data to a string + std::string serializedData = HexStr(ss.begin(), ss.end()); + + CrossBoundaryResult result; + BlockV2Info info; + info.height = pindex->nHeight; + info.difficulty = pindex->nBits; + info.version = pindex->nVersion; + info.median_time = (int64_t)pindex->GetMedianTimePast(); + info.minter_block_count = pindex->mintedBlocks; + info.size = GetSerializeSize(block, PROTOCOL_VERSION); + info.size_stripped = GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS); + info.weight = GetBlockWeight(block); + info.stake_modifier = pindex->stakeModifier.ToString(); + info.minter = ""; // mn operator address + info.masternode = ""; // mn owner address + + // minter info + CKeyID minter; + block.ExtractMinterKey(minter); + + auto id = pcustomcsview->GetMasternodeIdByOperator(minter); + if (id) { + info.masternode = id->ToString(); + auto mn = pcustomcsview->GetMasternode(*id); + if (mn) { + auto dest = mn->operatorType == 1 ? CTxDestination(PKHash(minter)) : CTxDestination(WitnessV0KeyHash(minter)); + info.minter = EncodeDestination(dest); + } + } + + ocean_index_block(result, serializedData, info); + // if (!result.ok) { + // return Res::Err(result.reason.c_str()); + // } + } + return true; } From 6b6272e6d039a3fd22be993f81df52ff554ae92d Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Wed, 24 Jan 2024 10:47:17 +0100 Subject: [PATCH 030/185] Ocean: RPC client (#2793) * With ApiError into_response * Client auth * Response handling * Expose rpc client to indexer * Remove unused dep * Update client type --- lib/Cargo.lock | 416 +++++++----------- lib/ain-cpp-imports/src/bridge.rs | 2 + lib/ain-cpp-imports/src/lib.rs | 27 ++ lib/ain-grpc/src/lib.rs | 5 +- lib/ain-macros/src/lib.rs | 59 ++- lib/ain-ocean/Cargo.toml | 4 +- lib/ain-ocean/src/api/address.rs | 5 +- lib/ain-ocean/src/api/block.rs | 5 +- lib/ain-ocean/src/api/common.rs | 28 ++ lib/ain-ocean/src/api/fee.rs | 30 +- lib/ain-ocean/src/api/governance.rs | 5 +- lib/ain-ocean/src/api/loan.rs | 5 +- lib/ain-ocean/src/api/masternode.rs | 5 +- lib/ain-ocean/src/api/mod.rs | 91 ++-- lib/ain-ocean/src/api/oracle.rs | 5 +- lib/ain-ocean/src/api/poolpairs.rs | 5 +- lib/ain-ocean/src/api/prices.rs | 5 +- lib/ain-ocean/src/api/rawtx.rs | 5 +- .../response.rs} | 21 +- lib/ain-ocean/src/api/stats.rs | 5 +- lib/ain-ocean/src/api/tokens.rs | 135 +++++- lib/ain-ocean/src/api/transactions.rs | 5 +- lib/ain-ocean/src/error.rs | 79 +++- lib/ain-ocean/src/indexer/mod.rs | 4 + lib/ain-ocean/src/lib.rs | 25 +- lib/cli/src/command.rs | 2 +- src/ffi/ffiexports.cpp | 16 + src/ffi/ffiexports.h | 2 + 28 files changed, 668 insertions(+), 333 deletions(-) create mode 100644 lib/ain-ocean/src/api/common.rs rename lib/ain-ocean/src/{api_paged_response.rs => api/response.rs} (93%) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 7b2b397a0d5..00ebbaf2e56 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -53,7 +53,7 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.12", "once_cell", "version_check", ] @@ -65,7 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" dependencies = [ "cfg-if", - "getrandom 0.2.11", + "getrandom 0.2.12", "once_cell", "version_check", "zerocopy", @@ -124,7 +124,7 @@ dependencies = [ "ain-cpp-imports", "ain-db", "anyhow", - "axum 0.7.3", + "axum 0.7.4", "bincode", "ethabi", "ethbloom", @@ -136,7 +136,7 @@ dependencies = [ "hex", "hex-literal", "jsonrpsee-core 0.16.3", - "jsonrpsee-server 0.16.3", + "jsonrpsee-server", "jsonrpsee-types 0.16.3", "keccak-hash", "lazy_static", @@ -175,7 +175,7 @@ dependencies = [ "ain-ocean", "anyhow", "async-trait", - "axum 0.7.3", + "axum 0.7.4", "cxx", "env_logger", "ethereum", @@ -185,7 +185,7 @@ dependencies = [ "hex", "hyper 0.14.28", "jsonrpsee 0.16.3", - "jsonrpsee-server 0.16.3", + "jsonrpsee-server", "lazy_static", "libsecp256k1", "log", @@ -229,19 +229,21 @@ dependencies = [ "ain-db", "ain-macros", "anyhow", - "axum 0.7.3", + "axum 0.7.4", "bincode", "bitcoin", "bitcoin_hashes 0.12.0", "cached", "chrono", "ctrlc", + "defichain-rpc", "dftx-rs", "futures", "hex", "hyper 0.14.28", "json", - "jsonrpsee 0.20.3", + "jsonrpc", + "jsonrpsee 0.16.3", "keccak-hash", "lazy_static", "log", @@ -375,9 +377,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc2d0cfb2a7388d34f590e76686704c494ed7aaceed62ee1ba35cbf363abc2a5" +checksum = "a116f46a969224200a0a97f29cfd4c50e7534e4b4826bd23ea2c3c533039c82c" dependencies = [ "brotli", "flate2", @@ -459,12 +461,12 @@ dependencies = [ [[package]] name = "axum" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d09dbe0e490df5da9d69b36dca48a76635288a82f92eca90024883a56202026d" +checksum = "1236b4b292f6c4d6dc34604bb5120d85c3fe1d1aa596bd5cc52ca054d13e7b9e" dependencies = [ "async-trait", - "axum-core 0.4.2", + "axum-core 0.4.3", "axum-macros", "bytes", "futures-util", @@ -511,9 +513,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87c8503f93e6d144ee5690907ba22db7ba79ab001a932ab99034f0fe836b3df" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" dependencies = [ "async-trait", "bytes", @@ -532,9 +534,9 @@ dependencies = [ [[package]] name = "axum-macros" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a2edad600410b905404c594e2523549f1bcd4bded1e252c8f74524ccce0b867" +checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa" dependencies = [ "heck 0.4.1", "proc-macro2", @@ -571,9 +573,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.6" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c79fed4cdb43e993fcdadc7e58a09fd0e3e649c4436fa11da71c9f1f3ee7feb9" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64ct" @@ -654,7 +656,7 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitcoin" version = "0.31.0" -source = "git+https://github.com/Jouzo/rust-bitcoin.git#d540306b57be5ff16b120c0e70b87512d289c262" +source = "git+https://github.com/Jouzo/rust-bitcoin.git#b0d721708df119a87193ff23910ab5579ce370b7" dependencies = [ "bech32", "bitcoin-internals", @@ -678,7 +680,7 @@ dependencies = [ [[package]] name = "bitcoin-io" version = "0.1.0" -source = "git+https://github.com/Jouzo/rust-bitcoin.git#d540306b57be5ff16b120c0e70b87512d289c262" +source = "git+https://github.com/Jouzo/rust-bitcoin.git#b0d721708df119a87193ff23910ab5579ce370b7" [[package]] name = "bitcoin-private" @@ -714,9 +716,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "bitvec" @@ -927,9 +929,9 @@ dependencies = [ [[package]] name = "cached_proc_macro_types" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663" +checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" [[package]] name = "cc" @@ -958,9 +960,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "41daef31d7a747c5c847246f36de49ced6f7403b4cdabc807a97b5cc184cda7a" dependencies = [ "android-tzdata", "iana-time-zone", @@ -968,7 +970,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.48.5", + "windows-targets 0.52.0", ] [[package]] @@ -1344,6 +1346,28 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "defichain-rpc" +version = "0.18.0" +source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#793a46b73c098f44a9038a332659381b43205119" +dependencies = [ + "defichain-rpc-json", + "jsonrpc", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "defichain-rpc-json" +version = "0.18.0" +source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#793a46b73c098f44a9038a332659381b43205119" +dependencies = [ + "bitcoin", + "serde", + "serde_json", +] + [[package]] name = "der" version = "0.7.8" @@ -1398,7 +1422,7 @@ source = "git+https://github.com/Jouzo/dftx-rs.git#e10dea303487f3c0bf5f851669c93 dependencies = [ "anyhow", "bitcoin", - "bitflags 2.4.1", + "bitflags 2.4.2", "dftx-macro", "hex", ] @@ -1608,9 +1632,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" dependencies = [ "humantime", "is-terminal", @@ -1719,9 +1743,9 @@ dependencies = [ [[package]] name = "ethers-core" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f03e0bdc216eeb9e355b90cf610ef6c5bb8aca631f97b5ae9980ce34ea7878d" +checksum = "918b1a9ba585ea61022647def2f27c29ba19f6d2a4a4c8f68a9ae97fd5769737" dependencies = [ "arrayvec 0.7.4", "bytes", @@ -1746,9 +1770,9 @@ dependencies = [ [[package]] name = "ethers-solc" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64f710586d147864cff66540a6d64518b9ff37d73ef827fee430538265b595f" +checksum = "cc2e46e3ec8ef0c986145901fa9864205dc4dcee701f9846be2d56112d34bdea" dependencies = [ "cfg-if", "const-hex", @@ -2079,9 +2103,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -2120,7 +2144,7 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.3", + "regex-automata 0.4.4", "regex-syntax 0.8.2", ] @@ -2137,9 +2161,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.22" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" dependencies = [ "bytes", "fnv", @@ -2156,9 +2180,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d308f63daf4181410c242d34c11f928dcb3aa105852019e043c9d1f4e4368a" +checksum = "31d030e59af851932b72ceebadf4a2b5986dba4c3b99dd2493f8273a0f151943" dependencies = [ "bytes", "fnv", @@ -2248,9 +2272,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" [[package]] name = "hex" @@ -2415,7 +2439,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.3.22", + "h2 0.3.24", "http 0.2.11", "http-body 0.4.6", "httparse", @@ -2438,7 +2462,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.0", + "h2 0.4.2", "http 1.0.0", "http-body 1.0.0", "httparse", @@ -2618,7 +2642,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.3", + "hermit-abi 0.3.4", "libc", "windows-sys 0.48.0", ] @@ -2645,8 +2669,8 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" dependencies = [ - "hermit-abi 0.3.3", - "rustix 0.38.28", + "hermit-abi 0.3.4", + "rustix 0.38.30", "windows-sys 0.52.0", ] @@ -2685,9 +2709,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.66" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" dependencies = [ "wasm-bindgen", ] @@ -2698,6 +2722,17 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" +[[package]] +name = "jsonrpc" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8128f36b47411cd3f044be8c1f5cc0c9e24d1d1bfdc45f0a57897b32513053f2" +dependencies = [ + "base64 0.13.1", + "serde", + "serde_json", +] + [[package]] name = "jsonrpsee" version = "0.16.3" @@ -2706,8 +2741,8 @@ checksum = "367a292944c07385839818bb71c8d76611138e2dedb0677d035b8da21d29c78b" dependencies = [ "jsonrpsee-core 0.16.3", "jsonrpsee-http-client 0.16.3", - "jsonrpsee-proc-macros 0.16.3", - "jsonrpsee-server 0.16.3", + "jsonrpsee-proc-macros", + "jsonrpsee-server", "jsonrpsee-types 0.16.3", "tracing", ] @@ -2723,21 +2758,6 @@ dependencies = [ "jsonrpsee-types 0.18.2", ] -[[package]] -name = "jsonrpsee" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "affdc52f7596ccb2d7645231fc6163bb314630c989b64998f3699a28b4d5d4dc" -dependencies = [ - "jsonrpsee-core 0.20.3", - "jsonrpsee-http-client 0.20.3", - "jsonrpsee-proc-macros 0.20.3", - "jsonrpsee-server 0.20.3", - "jsonrpsee-types 0.20.3", - "tokio", - "tracing", -] - [[package]] name = "jsonrpsee-core" version = "0.16.3" @@ -2783,29 +2803,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "jsonrpsee-core" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2327ba8df2fdbd5e897e2b5ed25ce7f299d345b9736b6828814c3dbd1fd47b" -dependencies = [ - "anyhow", - "async-trait", - "beef", - "futures-util", - "hyper 0.14.28", - "jsonrpsee-types 0.20.3", - "parking_lot", - "rand 0.8.5", - "rustc-hash", - "serde", - "serde_json", - "soketto", - "thiserror", - "tokio", - "tracing", -] - [[package]] name = "jsonrpsee-http-client" version = "0.16.3" @@ -2844,26 +2841,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "jsonrpsee-http-client" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f80c17f62c7653ce767e3d7288b793dfec920f97067ceb189ebdd3570f2bc20" -dependencies = [ - "async-trait", - "hyper 0.14.28", - "hyper-rustls", - "jsonrpsee-core 0.20.3", - "jsonrpsee-types 0.20.3", - "serde", - "serde_json", - "thiserror", - "tokio", - "tower", - "tracing", - "url", -] - [[package]] name = "jsonrpsee-proc-macros" version = "0.16.3" @@ -2877,19 +2854,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "jsonrpsee-proc-macros" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29110019693a4fa2dbda04876499d098fa16d70eba06b1e6e2b3f1b251419515" -dependencies = [ - "heck 0.4.1", - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "jsonrpsee-server" version = "0.16.3" @@ -2912,29 +2876,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "jsonrpsee-server" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c39a00449c9ef3f50b84fc00fc4acba20ef8f559f07902244abf4c15c5ab9c" -dependencies = [ - "futures-util", - "http 0.2.11", - "hyper 0.14.28", - "jsonrpsee-core 0.20.3", - "jsonrpsee-types 0.20.3", - "route-recognizer", - "serde", - "serde_json", - "soketto", - "thiserror", - "tokio", - "tokio-stream", - "tokio-util", - "tower", - "tracing", -] - [[package]] name = "jsonrpsee-types" version = "0.16.3" @@ -2963,25 +2904,11 @@ dependencies = [ "tracing", ] -[[package]] -name = "jsonrpsee-types" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be0be325642e850ed0bdff426674d2e66b2b7117c9be23a7caef68a2902b7d9" -dependencies = [ - "anyhow", - "beef", - "serde", - "serde_json", - "thiserror", - "tracing", -] - [[package]] name = "k256" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f01b677d82ef7a676aa37e099defd83a28e15687112cafdd112d60236b6115b" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" dependencies = [ "cfg-if", "ecdsa", @@ -2992,9 +2919,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] @@ -3112,7 +3039,7 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "libc", "redox_syscall", ] @@ -3183,9 +3110,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.13" +version = "1.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f526fdd09d99e19742883e43de41e1aa9e36db0c7ab7f935165d611c5cccc66" +checksum = "295c17e837573c8c821dbaeb3cceb3d745ad082f7572191409e69cbc1b3fd050" dependencies = [ "cc", "pkg-config", @@ -3209,9 +3136,9 @@ checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" [[package]] name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" @@ -3304,7 +3231,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix 0.38.28", + "rustix 0.38.30", ] [[package]] @@ -3441,7 +3368,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "cfg-if", "libc", ] @@ -3555,7 +3482,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.3", + "hermit-abi 0.3.4", "libc", ] @@ -3910,9 +3837,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" [[package]] name = "powerfmt" @@ -4012,9 +3939,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.76" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -4025,7 +3952,7 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "lazy_static", "num-traits", "rand 0.8.5", @@ -4200,7 +4127,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.12", ] [[package]] @@ -4239,9 +4166,9 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" dependencies = [ "either", "rayon-core", @@ -4249,9 +4176,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -4281,7 +4208,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.12", "libredox", "thiserror", ] @@ -4308,13 +4235,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.3", + "regex-automata 0.4.4", "regex-syntax 0.8.2", ] @@ -4329,9 +4256,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" dependencies = [ "aho-corasick", "memchr", @@ -4371,12 +4298,12 @@ version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ - "base64 0.21.6", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2 0.3.22", + "h2 0.3.24", "http 0.2.11", "http-body 0.4.6", "hyper 0.14.28", @@ -4422,7 +4349,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", - "getrandom 0.2.11", + "getrandom 0.2.12", "libc", "spin 0.9.8", "untrusted", @@ -4470,12 +4397,6 @@ dependencies = [ "librocksdb-sys", ] -[[package]] -name = "route-recognizer" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" - [[package]] name = "ruc" version = "4.2.1" @@ -4539,14 +4460,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.28" +version = "0.38.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "errno", "libc", - "linux-raw-sys 0.4.12", + "linux-raw-sys 0.4.13", "windows-sys 0.52.0", ] @@ -4580,7 +4501,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.6", + "base64 0.21.7", ] [[package]] @@ -4739,6 +4660,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f622567e3b4b38154fb8190bcf6b160d7a4301d70595a49195b48c116007a27" dependencies = [ "bitcoin_hashes 0.13.0", + "rand 0.8.5", "secp256k1-sys 0.9.2", "serde", ] @@ -4872,11 +4794,11 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.4.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" +checksum = "f5c9fdb6b00a489875b22efd4b78fe2b363b72265cc5f6eb2e2b9ee270e6140c" dependencies = [ - "base64 0.21.6", + "base64 0.21.7", "chrono", "hex", "indexmap 1.9.3", @@ -4889,9 +4811,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.4.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" +checksum = "dbff351eb4b33600a2e138dfa0b10b65a238ea8ff8fb2387c422c5022a3e8298" dependencies = [ "darling 0.20.3", "proc-macro2", @@ -4980,9 +4902,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" @@ -5039,9 +4961,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.2" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "socket2" @@ -5368,9 +5290,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.45.0" +version = "1.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0c74081753a8ce1c8eb10b9f262ab6f7017e5ad3317c17a54c7ab65fcb3c6e" +checksum = "b1114ee5900b8569bbc8b1a014a942f937b752af4b44f4607430b5f86cedaac0" dependencies = [ "Inflector", "num-format", @@ -5511,9 +5433,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "svm-rs" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20689c7d03b6461b502d0b95d6c24874c7d24dea2688af80486a130a06af3b07" +checksum = "7ce290b5536ab2a42a61c9c6f22d6bfa8f26339c602aa62db4c978c95d1afc47" dependencies = [ "dirs", "fs2", @@ -5644,7 +5566,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall", - "rustix 0.38.28", + "rustix 0.38.30", "windows-sys 0.52.0", ] @@ -5661,9 +5583,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -5913,11 +5835,11 @@ checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" dependencies = [ "async-trait", "axum 0.6.20", - "base64 0.21.6", + "base64 0.21.7", "bytes", "futures-core", "futures-util", - "h2 0.3.22", + "h2 0.3.24", "http 0.2.11", "http-body 0.4.6", "hyper 0.14.28", @@ -5973,8 +5895,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ "async-compression", - "base64 0.21.6", - "bitflags 2.4.1", + "base64 0.21.7", + "bitflags 2.4.2", "bytes", "futures-core", "futures-util", @@ -6193,9 +6115,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -6249,11 +6171,11 @@ dependencies = [ [[package]] name = "uuid" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.12", ] [[package]] @@ -6384,9 +6306,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -6394,9 +6316,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" dependencies = [ "bumpalo", "log", @@ -6409,9 +6331,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.39" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" dependencies = [ "cfg-if", "js-sys", @@ -6421,9 +6343,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6431,9 +6353,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ "proc-macro2", "quote", @@ -6444,9 +6366,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" [[package]] name = "wasmparser" @@ -6592,9 +6514,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.66" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" dependencies = [ "js-sys", "wasm-bindgen", @@ -6615,14 +6537,14 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.28", + "rustix 0.38.30", ] [[package]] name = "wide" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68938b57b33da363195412cfc5fc37c9ed49aa9cfe2156fde64b8d2c9498242" +checksum = "b31891d644eba1789fb6715f27fbc322e4bdf2ecdc412ede1993246159271613" dependencies = [ "bytemuck", "safe_arch", @@ -6868,9 +6790,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.33" +version = "0.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7520bbdec7211caa7c4e682eb1fbe07abe20cee6756b6e00f537c82c11816aa" +checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" dependencies = [ "memchr", ] diff --git a/lib/ain-cpp-imports/src/bridge.rs b/lib/ain-cpp-imports/src/bridge.rs index 5f009290f84..65b9af35a8e 100644 --- a/lib/ain-cpp-imports/src/bridge.rs +++ b/lib/ain-cpp-imports/src/bridge.rs @@ -30,6 +30,8 @@ pub mod ffi { type TransactionData; fn getChainId() -> u64; + fn getRPCPort() -> i32; + fn getRPCAuth() -> String; fn isMining() -> bool; fn publishEthTransaction(data: Vec) -> String; fn getAccounts() -> Vec; diff --git a/lib/ain-cpp-imports/src/lib.rs b/lib/ain-cpp-imports/src/lib.rs index eeccccb108e..a5550a7fbaf 100644 --- a/lib/ain-cpp-imports/src/lib.rs +++ b/lib/ain-cpp-imports/src/lib.rs @@ -33,6 +33,12 @@ mod ffi { pub fn getChainId() -> u64 { unimplemented!("{}", UNIMPL_MSG) } + pub fn getRPCPort() -> i32 { + unimplemented!("{}", UNIMPL_MSG) + } + pub fn getRPCAuth() -> String { + unimplemented!("{}", UNIMPL_MSG) + } pub fn isMining() -> bool { unimplemented!("{}", UNIMPL_MSG) } @@ -137,6 +143,27 @@ pub fn get_chain_id() -> Result> { Ok(chain_id) } +/// Returns the RPC port. +pub fn get_rpc_port() -> i32 { + ffi::getRPCPort() +} + +/// Returns the RPC authorization string. +pub fn get_rpc_auth() -> Result<(String, String), Box> { + match ffi::getRPCAuth() + .splitn(2, ':') + .map(String::from) + .collect::>() + .as_slice() + { + [user, pass] => Ok((user.clone(), pass.clone())), + yo => { + println!("yo : {:?}", yo); + Err("Error getting user and password".into()) + } + } +} + /// Retrieves the client version string. pub fn get_client_version() -> String { ffi::getClientVersion() diff --git a/lib/ain-grpc/src/lib.rs b/lib/ain-grpc/src/lib.rs index 763dcfcb146..cbe8c44131d 100644 --- a/lib/ain-grpc/src/lib.rs +++ b/lib/ain-grpc/src/lib.rs @@ -130,10 +130,9 @@ pub fn init_network_rest_ocean(addr: String) -> Result<()> { let listener = runtime .tokio_runtime .block_on(tokio::net::TcpListener::bind(addr))?; + let ocean_router = ain_ocean::ocean_router()?; let server_handle = runtime.tokio_runtime.spawn(async move { - axum::serve(listener, ain_ocean::ocean_router()) - .await - .unwrap(); + axum::serve(listener, ocean_router).await.unwrap(); }); *runtime.ocean_handle.lock() = Some(server_handle); diff --git a/lib/ain-macros/src/lib.rs b/lib/ain-macros/src/lib.rs index 101d68acce7..9eee261ec0f 100644 --- a/lib/ain-macros/src/lib.rs +++ b/lib/ain-macros/src/lib.rs @@ -2,7 +2,10 @@ extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; -use syn::{parse_macro_input, Attribute, DeriveInput, ItemFn, LitStr, ReturnType, Type}; +use syn::{ + parse_macro_input, parse_quote, Attribute, DeriveInput, Expr, FnArg, ItemFn, LitStr, + ReturnType, Type, +}; #[proc_macro_attribute] pub fn ffi_fallible(_attr: TokenStream, item: TokenStream) -> TokenStream { @@ -123,3 +126,57 @@ pub fn repository_derive(input: TokenStream) -> TokenStream { TokenStream::from(expanded) } + +#[proc_macro_attribute] +pub fn ocean_endpoint(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as ItemFn); + let inputs = &input.sig.inputs; + + let name = &input.sig.ident; + + let output = &input.sig.output; + let inner_type = match output { + ReturnType::Type(_, type_box) => match &**type_box { + Type::Path(type_path) => type_path.path.segments.last().and_then(|pair| { + if let syn::PathArguments::AngleBracketed(angle_bracketed_args) = &pair.arguments { + angle_bracketed_args.args.first() + } else { + None + } + }), + _ => None, + }, + _ => None, + }; + + let param_names: Vec<_> = inputs + .iter() + .filter_map(|arg| { + if let syn::FnArg::Typed(pat_type) = arg { + Some(&pat_type.pat) + } else { + None + } + }) + .collect(); + + let expanded = quote! { + pub async fn #name(axum::extract::OriginalUri(uri): axum::extract::OriginalUri, #inputs) -> std::result::Result, ApiError> { + #input + + match #name(#(#param_names),*).await { + Err(e) => { + let (status, message) = e.into_code_and_message(); + Err(ApiError::new( + status, + message, + uri.to_string() + )) + }, + Ok(v) => Ok(axum::Json(v)) + } + } + }; + + TokenStream::from(expanded) +} diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index 780f2206c96..2097cd45814 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -27,7 +27,7 @@ serde_json = "1.0" json = "0.12.4" tokio-serde = {version="0.8.0"} futures = "0.3.29" -jsonrpsee = { version = "0.20.3", features = ["server", "macros", "http-client", "jsonrpsee-server"] } +jsonrpsee = { workspace = true, features = ["server", "macros", "http-client", "jsonrpsee-server"] } rocksdb = "0.21.0" ctrlc = "3.1.9" tempdir = "0.3.7" @@ -39,3 +39,5 @@ chrono = "0.4.31" cached.workspace = true lazy_static.workspace = true bincode.workspace = true +defichain-rpc = { version = "0.18.0", git = "https://github.com/Jouzo/rust-defichain-rpc.git" } +jsonrpc = "0.14.1" diff --git a/lib/ain-ocean/src/api/address.rs b/lib/ain-ocean/src/api/address.rs index 8bface2c67c..2ec9a8b2684 100644 --- a/lib/ain-ocean/src/api/address.rs +++ b/lib/ain-ocean/src/api/address.rs @@ -1,4 +1,7 @@ +use std::sync::Arc; + use axum::{extract::Path, routing::get, Router}; +use defichain_rpc::{Client, RpcApi}; use serde::Deserialize; #[derive(Deserialize)] @@ -54,7 +57,7 @@ async fn list_transaction_unspent(Path(Address { address }): Path
) -> S format!("List unspent transactions for address {}", address) } -pub fn router() -> Router { +pub fn router(state: Arc) -> Router { Router::new().nest( "/:address", Router::new() diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 809d16cb037..a989e59aa50 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -1,9 +1,12 @@ +use std::sync::Arc; + use axum::{ extract::{Path, Query}, routing::get, Json, Router, }; use bitcoin::BlockHash; +use defichain_rpc::{Client, RpcApi}; use crate::{ api_paged_response::ApiPagedResponse, api_query::PaginationQuery, model::Block, @@ -45,7 +48,7 @@ async fn get_transactions(Path(hash): Path) -> String { format!("Transactions for block with hash {}", hash) } -pub fn router() -> Router { +pub fn router(state: Arc) -> Router { Router::new() .route("/", get(list_blocks)) .route("/:id", get(get_block)) diff --git a/lib/ain-ocean/src/api/common.rs b/lib/ain-ocean/src/api/common.rs new file mode 100644 index 00000000000..9b822f49bbf --- /dev/null +++ b/lib/ain-ocean/src/api/common.rs @@ -0,0 +1,28 @@ +use defichain_rpc::json::token::TokenInfo; + +pub fn parse_display_symbol(token_info: &TokenInfo) -> String { + if token_info.is_lps { + let tokens: Vec<&str> = token_info.symbol.split('-').collect(); + if tokens.len() == 2 { + return format!( + "{}-{}", + parse_dat_symbol(tokens[0]), + parse_dat_symbol(tokens[1]) + ); + } + } else if token_info.is_dat { + return parse_dat_symbol(&token_info.symbol); + } + + token_info.symbol.clone() +} + +fn parse_dat_symbol(symbol: &str) -> String { + let special_symbols = ["DUSD", "DFI", "csETH"]; + + if special_symbols.contains(&symbol) { + symbol.to_string() + } else { + format!("d{}", symbol) + } +} diff --git a/lib/ain-ocean/src/api/fee.rs b/lib/ain-ocean/src/api/fee.rs index 4a042b8a6bd..e5bca56f16f 100644 --- a/lib/ain-ocean/src/api/fee.rs +++ b/lib/ain-ocean/src/api/fee.rs @@ -1,22 +1,36 @@ -use axum::{extract::Query, routing::get, Router}; +use std::sync::Arc; + +use ain_macros::ocean_endpoint; +use axum::{extract::Query, routing::get, Extension, Json, Router}; +use defichain_rpc::{json::mining::SmartFeeEstimation, Client, RpcApi}; use serde::Deserialize; +use super::response::Response; +use crate::{error::ApiError, Result}; + #[derive(Deserialize)] struct EstimateQuery { confirmation_target: i32, } +#[ocean_endpoint] async fn estimate_fee( Query(EstimateQuery { confirmation_target, }): Query, -) -> String { - format!( - "Fee estimate for confirmation target {}", - confirmation_target - ) + Extension(client): Extension>, +) -> Result> { + let estimation: SmartFeeEstimation = client.call( + "estimatesmartfee", + &[confirmation_target.into(), "CONSERVATIVE".into()], + )?; + println!("estimation : {:?}", estimation); + + Ok(Response::new(estimation.feerate.unwrap_or(0.00005000))) } -pub fn router() -> Router { - Router::new().route("/estimate", get(estimate_fee)) +pub fn router(state: Arc) -> Router { + Router::new() + .route("/estimate", get(estimate_fee)) + .layer(Extension(state)) } diff --git a/lib/ain-ocean/src/api/governance.rs b/lib/ain-ocean/src/api/governance.rs index dd0979a2eff..8fca5c52249 100644 --- a/lib/ain-ocean/src/api/governance.rs +++ b/lib/ain-ocean/src/api/governance.rs @@ -1,4 +1,7 @@ +use std::sync::Arc; + use axum::{extract::Path, routing::get, Router}; +use defichain_rpc::{Client, RpcApi}; async fn list_gov_proposals() -> String { "List of governance proposals".to_string() @@ -12,7 +15,7 @@ async fn list_gov_proposal_votes(Path(proposal_id): Path) -> String { format!("Votes for governance proposal with id {}", proposal_id) } -pub fn router() -> Router { +pub fn router(state: Arc) -> Router { Router::new() .route("/proposals", get(list_gov_proposals)) .route("/proposals/:id", get(get_gov_proposal)) diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index 98c8d8c8cfb..96d883e57a2 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -1,9 +1,12 @@ +use std::sync::Arc; + use axum::{ extract::{Path, Query}, routing::get, Json, Router, }; use bitcoin::Txid; +use defichain_rpc::{Client, RpcApi}; use log::debug; use crate::{ @@ -105,7 +108,7 @@ async fn list_auction() -> String { "List of auctions".to_string() } -pub fn router() -> Router { +pub fn router(state: Arc) -> Router { Router::new() .route("/schemes", get(list_scheme)) .route("/schemes/:id", get(get_scheme)) diff --git a/lib/ain-ocean/src/api/masternode.rs b/lib/ain-ocean/src/api/masternode.rs index 9ef015d88e0..f14f17f226b 100644 --- a/lib/ain-ocean/src/api/masternode.rs +++ b/lib/ain-ocean/src/api/masternode.rs @@ -1,9 +1,12 @@ +use std::sync::Arc; + use axum::{ extract::{Path, Query}, routing::get, Json, Router, }; use bitcoin::Txid; +use defichain_rpc::{Client, RpcApi}; use serde::{Deserialize, Serialize}; use crate::{ @@ -139,7 +142,7 @@ async fn get_masternode(Path(masternode_id): Path) -> Result Router { +pub fn router(state: Arc) -> Router { Router::new() .route("/", get(list_masternodes)) .route("/:id", get(get_masternode)) diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index b294179f7e7..6f8f10a17aa 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -1,46 +1,75 @@ -use axum::{http::StatusCode, response::IntoResponse, Router}; +use std::sync::Arc; -mod address; -mod block; +use axum::{extract::Request, http::StatusCode, response::IntoResponse, Json, Router}; + +// mod address; +// mod block; mod fee; -mod governance; -mod loan; -mod masternode; -mod oracle; -mod poolpairs; -mod prices; -mod rawtx; -mod stats; +// mod governance; +// mod loan; +// mod masternode; +// mod oracle; +// mod poolpairs; +// mod prices; +// mod rawtx; +// mod stats; +mod common; +mod response; mod tokens; -mod transactions; +// mod transactions; use axum::routing::get; +use serde::{Deserialize, Serialize}; + +use crate::{Result, SERVICES}; async fn ocean_not_activated() -> impl IntoResponse { (StatusCode::FORBIDDEN, "Ocean is not activated") } -async fn not_found() -> impl IntoResponse { - (StatusCode::NOT_FOUND, "Not found") +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +struct NotFound { + status_code: u16, + message: String, + error: &'static str, +} + +async fn not_found(req: Request) -> impl IntoResponse { + let method = req.method().clone(); + let path = req.uri().path().to_string(); + + let message = format!("Cannot {} {}", method, path); + ( + StatusCode::NOT_FOUND, + Json(NotFound { + status_code: StatusCode::NOT_FOUND.as_u16(), + message, + error: "Not found", + }), + ) } -pub fn ocean_router() -> Router { +pub fn ocean_router() -> Result { if !ain_cpp_imports::is_ocean_rest_enabled() { - return Router::new().route("/*path", get(ocean_not_activated)); + return Ok(Router::new().route("/*path", get(ocean_not_activated))); } - Router::new() - .nest("/address", address::router()) - .nest("/governance", governance::router()) - .nest("/loans", loan::router()) - .nest("/fee", fee::router()) - .nest("/masternodes", masternode::router()) - .nest("/oracles", oracle::router()) - .nest("/poolpairs", poolpairs::router()) - .nest("/prices", prices::router()) - .nest("/rawtx", rawtx::router()) - .nest("/stats", stats::router()) - .nest("/tokens", tokens::router()) - .nest("/transactions", transactions::router()) - .nest("/blocks", block::router()) - .fallback(not_found) + let client = &SERVICES.client; + println!("client : {:?}", client); + + Ok(Router::new() + // .nest("/address", address::router(Arc::clone(client))) + // .nest("/governance", governance::router(Arc::clone(client))) + // .nest("/loans", loan::router(Arc::clone(client))) + .nest("/fee", fee::router(Arc::clone(client))) + // .nest("/masternodes", masternode::router(Arc::clone(client))) + // .nest("/oracles", oracle::router(Arc::clone(client))) + // .nest("/poolpairs", poolpairs::router(Arc::clone(client))) + // .nest("/prices", prices::router(Arc::clone(client))) + // .nest("/rawtx", rawtx::router(Arc::clone(client))) + // .nest("/stats", stats::router(Arc::clone(client))) + .nest("/tokens", tokens::router(Arc::clone(client))) + // .nest("/transactions", transactions::router(Arc::clone(client))) + // .nest("/blocks", block::router(Arc::clone(client))) + .fallback(not_found)) } diff --git a/lib/ain-ocean/src/api/oracle.rs b/lib/ain-ocean/src/api/oracle.rs index bee3856022e..683bbd242dd 100644 --- a/lib/ain-ocean/src/api/oracle.rs +++ b/lib/ain-ocean/src/api/oracle.rs @@ -1,4 +1,7 @@ +use std::sync::Arc; + use axum::{extract::Path, routing::get, Router}; +use defichain_rpc::{Client, RpcApi}; async fn list_oracles() -> String { "List of oracles".to_string() @@ -12,7 +15,7 @@ async fn get_oracle_by_address(Path(address): Path) -> String { format!("Oracle details for address {}", address) } -pub fn router() -> Router { +pub fn router(state: Arc) -> Router { Router::new() .route("/", get(list_oracles)) .route("/:oracleId/:key/feed", get(get_price_feed)) diff --git a/lib/ain-ocean/src/api/poolpairs.rs b/lib/ain-ocean/src/api/poolpairs.rs index 7246c062eba..d4064cbe2bb 100644 --- a/lib/ain-ocean/src/api/poolpairs.rs +++ b/lib/ain-ocean/src/api/poolpairs.rs @@ -1,8 +1,11 @@ +use std::sync::Arc; + use axum::{ extract::{Path, Query}, routing::get, Json, Router, }; +use defichain_rpc::{Client, RpcApi}; use log::debug; use serde::{Deserialize, Serialize}; @@ -192,7 +195,7 @@ async fn list_dex_prices(Query(DexPrices { denomination }): Query) -> format!("List of DEX prices with denomination {:?}", denomination) } -pub fn router() -> Router { +pub fn router(state: Arc) -> Router { Router::new() .route("/", get(list_poolpairs)) .route("/:id", get(get_poolpair)) diff --git a/lib/ain-ocean/src/api/prices.rs b/lib/ain-ocean/src/api/prices.rs index 94d13200839..5e394768646 100644 --- a/lib/ain-ocean/src/api/prices.rs +++ b/lib/ain-ocean/src/api/prices.rs @@ -1,4 +1,7 @@ +use std::sync::Arc; + use axum::{extract::Path, routing::get, Router}; +use defichain_rpc::{Client, RpcApi}; use serde::Deserialize; #[derive(Deserialize)] @@ -38,7 +41,7 @@ async fn get_oracles(Path(PriceKey { key }): Path) -> String { format!("Oracles for price with key {}", key) } -pub fn router() -> Router { +pub fn router(state: Arc) -> Router { Router::new() .route("/", get(list_prices)) .route("/:key", get(get_price)) diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index 98258abbc04..6830d4d0cd1 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -1,8 +1,11 @@ +use std::sync::Arc; + use axum::{ extract::Path, routing::{get, post}, Router, }; +use defichain_rpc::{Client, RpcApi}; async fn send_rawtx() -> String { "Sending raw transaction".to_string() @@ -16,7 +19,7 @@ async fn get_rawtx(Path(txid): Path) -> String { format!("Details of raw transaction with txid {}", txid) } -pub fn router() -> Router { +pub fn router(state: Arc) -> Router { Router::new() .route("/send", post(send_rawtx)) .route("/test", get(test_rawtx)) diff --git a/lib/ain-ocean/src/api_paged_response.rs b/lib/ain-ocean/src/api/response.rs similarity index 93% rename from lib/ain-ocean/src/api_paged_response.rs rename to lib/ain-ocean/src/api/response.rs index 24a877707f6..4b9c2444509 100644 --- a/lib/ain-ocean/src/api_paged_response.rs +++ b/lib/ain-ocean/src/api/response.rs @@ -1,5 +1,16 @@ use serde::Serialize; +#[derive(Debug, Serialize)] +pub struct Response { + data: T, +} + +impl Response { + pub fn new(data: T) -> Self { + Self { data } + } +} + /// ApiPagedResponse indicates that this response of data array slice is part of a sorted list of items. /// Items are part of a larger sorted list and the slice indicates a window within the large sorted list. /// Each ApiPagedResponse holds the data array and the "token" for next part of the slice. @@ -61,23 +72,21 @@ struct ApiPage { } impl ApiPagedResponse { - pub fn new(data: Vec, next: Option<&str>) -> Self { + pub fn new(data: Vec, next: Option) -> Self { Self { data, - page: ApiPage { - next: next.map(Into::into), - }, + page: ApiPage { next }, } // Option<&str> -> Option } - pub fn next(data: Vec, next: Option<&str>) -> Self { + pub fn next(data: Vec, next: Option) -> Self { Self::new(data, next) } pub fn of(data: Vec, limit: usize, next_provider: impl Fn(&T) -> String) -> Self { if data.len() == limit && data.len() > 0 && limit > 0 { let next = next_provider(&data[limit - 1]); - Self::next(data, Some(next.as_str())) + Self::next(data, Some(next)) } else { Self::next(data, None) } diff --git a/lib/ain-ocean/src/api/stats.rs b/lib/ain-ocean/src/api/stats.rs index 8077b4b009b..89f16b2ec48 100644 --- a/lib/ain-ocean/src/api/stats.rs +++ b/lib/ain-ocean/src/api/stats.rs @@ -1,4 +1,7 @@ +use std::sync::Arc; + use axum::{routing::get, Router}; +use defichain_rpc::{Client, RpcApi}; async fn get_stats() -> String { "General stats".to_string() @@ -16,7 +19,7 @@ async fn get_burn() -> String { "Burn stats".to_string() } -pub fn router() -> Router { +pub fn router(state: Arc) -> Router { Router::new() .route("/", get(get_stats)) .route("/rewards/distribution", get(get_reward_distribution)) diff --git a/lib/ain-ocean/src/api/tokens.rs b/lib/ain-ocean/src/api/tokens.rs index 3b3d0f455d8..92c9d348433 100644 --- a/lib/ain-ocean/src/api/tokens.rs +++ b/lib/ain-ocean/src/api/tokens.rs @@ -1,21 +1,138 @@ -use axum::{extract::Path, routing::get, Router}; -use serde::Deserialize; +use std::sync::Arc; -#[derive(Deserialize)] -struct TokenId { +use ain_macros::ocean_endpoint; +use axum::{ + extract::{Path, Query}, + routing::get, + Extension, Json, Router, +}; +use defichain_rpc::{ + json::token::{TokenInfo, TokenResult}, + Client, RpcApi, +}; +use serde::Serialize; +use serde_json::json; + +use super::{ + common::parse_display_symbol, + response::{ApiPagedResponse, Response}, +}; +use crate::{api_query::PaginationQuery, error::ApiError, Result}; + +#[derive(Serialize, Debug, Clone, Default)] +pub struct TxHeight { + tx: String, + height: i64, +} + +#[derive(Serialize, Debug, Clone, Default)] +#[serde(rename_all = "camelCase")] +pub struct TokenData { id: u32, + symbol: String, + symbol_key: String, + name: String, + decimal: u8, + limit: i64, + mintable: bool, + tradeable: bool, + #[serde(rename = "isDAT")] + is_dat: bool, + #[serde(rename = "isLPS")] + is_lps: bool, + is_loan_token: bool, + finalized: bool, + minted: String, + creation: TxHeight, + destruction: TxHeight, + display_symbol: String, + #[serde(skip_serializing_if = "Option::is_none")] + collateral_address: Option, } -async fn list_tokens() -> String { - "List of tokens".to_string() +impl TokenData { + fn from_with_id(id: u32, token: TokenInfo) -> Self { + let display_symbol = parse_display_symbol(&token); + Self { + id, + symbol: token.symbol, + display_symbol, + symbol_key: token.symbol_key, + name: token.name, + decimal: token.decimal, + limit: token.limit, + mintable: token.mintable, + tradeable: token.tradeable, + is_dat: token.is_dat, + is_lps: token.is_lps, + is_loan_token: token.is_loan_token, + finalized: token.finalized, + minted: token.minted.to_string(), + creation: TxHeight { + height: token.creation_height, + tx: token.creation_tx, + }, + destruction: TxHeight { + height: token.destruction_height, + tx: token.destruction_tx, + }, + collateral_address: token.collateral_address.and_then(|addr| { + if addr.is_empty() { + None + } else { + Some(addr) + } + }), + } + } } -async fn get_token(Path(TokenId { id }): Path) -> String { - format!("Details of token with id {}", id) +#[ocean_endpoint] +async fn list_tokens( + Query(query): Query, + Extension(client): Extension>, +) -> Result> { + let tokens: TokenResult = client.call( + "listtokens", + &[ + json!({ + "limit": query.size, + "start": query.next.as_ref().and_then(|n| n.parse::().ok()).unwrap_or_default(), + "including_start": query.next.is_none() + }), + true.into(), + ], + )?; + + let res = tokens + .0 + .into_iter() + .map(|(k, v)| TokenData::from_with_id(k, v)) + .collect::>(); + Ok(ApiPagedResponse::of(res, query.size, |token| { + token.id.to_string() + })) +} + +#[ocean_endpoint] +async fn get_token( + Path(id): Path, + Extension(client): Extension>, +) -> Result>> { + let mut v: TokenResult = client.call("gettoken", &[id.into()])?; + + let res = if let Some(token) = v.0.remove(&id) { + Some(TokenData::from_with_id(id, token)) + } else { + None + }; + + Ok(Response::new(res)) } -pub fn router() -> Router { +pub fn router(state: Arc) -> Router { Router::new() .route("/", get(list_tokens)) .route("/:id", get(get_token)) + .layer(Extension(state)) } diff --git a/lib/ain-ocean/src/api/transactions.rs b/lib/ain-ocean/src/api/transactions.rs index f75592a8cde..9bb495fa306 100644 --- a/lib/ain-ocean/src/api/transactions.rs +++ b/lib/ain-ocean/src/api/transactions.rs @@ -1,4 +1,7 @@ +use std::sync::Arc; + use axum::{extract::Path, routing::get, Router}; +use defichain_rpc::{Client, RpcApi}; use serde::Deserialize; #[derive(Deserialize)] @@ -18,7 +21,7 @@ async fn get_vouts(Path(TransactionId { id }): Path) -> String { format!("Vouts for transaction with id {}", id) } -pub fn router() -> Router { +pub fn router(state: Arc) -> Router { Router::new() .route("/:id", get(get_transaction)) .route("/:id/vins", get(get_vins)) diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 83d3e9fb5c7..eda9fff4ba6 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -5,8 +5,10 @@ use anyhow::format_err; use axum::{ http::StatusCode, response::{IntoResponse, Response}, + Json, }; use bitcoin::hex::HexToArrayError; +use serde::Serialize; use thiserror::Error; #[derive(Error, Debug)] @@ -23,18 +25,83 @@ pub enum OceanError { FromHexError(#[from] hex::FromHexError), #[error("Ocean: Consensus encode error: {0:?}")] ConsensusEncodeError(#[from] bitcoin::consensus::encode::Error), + #[error("Ocean: jsonrpsee error: {0:?}")] + JsonrpseeError(#[from] jsonrpsee::core::Error), + #[error("Ocean: serde_json error: {0:?}")] + SerdeJSONError(#[from] serde_json::Error), + #[error("Ocean: RPC error: {0:?}")] + RpcError(#[from] defichain_rpc::Error), #[error(transparent)] Other(#[from] anyhow::Error), } -impl IntoResponse for OceanError { +#[derive(Serialize)] +pub enum ErrorType { + NotFound, + Unknown, +} + +#[derive(Serialize)] +struct ApiErrorData { + code: u16, + r#type: ErrorType, + at: u128, + message: String, + url: String, +} +#[derive(Serialize)] +pub struct ApiError { + error: ApiErrorData, + #[serde(skip)] + status: StatusCode, +} + +impl ApiError { + pub fn new(status: StatusCode, message: String, url: String) -> Self { + let current_time = std::time::SystemTime::now(); + let at = current_time + .duration_since(std::time::UNIX_EPOCH) + .expect("Time went backwards") + .as_millis(); + + let r#type = match status { + StatusCode::NOT_FOUND => ErrorType::NotFound, + _ => ErrorType::Unknown, + }; + + Self { + error: ApiErrorData { + r#type, + code: status.as_u16(), + message, + url, + at, + }, + status, + } + } +} + +impl IntoResponse for ApiError { fn into_response(self) -> Response { - let code: StatusCode = match self { - // OceanError::SomeError => StatusCode::SomeCode, - _ => StatusCode::INTERNAL_SERVER_ERROR, + let status = self.status; + let reason = Json(self); + (status, reason).into_response() + } +} + +impl OceanError { + pub fn into_code_and_message(self) -> (StatusCode, String) { + let (code, reason) = match self { + OceanError::RpcError(defichain_rpc::Error::JsonRpc(jsonrpc::error::Error::Rpc(e))) => { + println!("e : {:?}", e); + + (StatusCode::NOT_FOUND, format!("")) + } + _ => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()), }; - let reason = self.to_string(); - (code, reason).into_response() + println!("reason : {:?}", reason); + (code, reason) } } diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 66667757b1d..6b336671ce5 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -4,6 +4,7 @@ mod oracle; mod pool; pub mod tx_result; +use defichain_rpc::RpcApi; use dftx_rs::{deserialize, Block, DfTx, Transaction}; use log::debug; @@ -70,6 +71,9 @@ pub fn index_block(encoded_block: String, info: &BlockV2Info) -> Result<()> { SERVICES.block.by_id.put(&ctx.hash, &block_mapper)?; SERVICES.block.by_height.put(&ctx.height, &block_hash)?; + let block_count = SERVICES.client.get_block_count()?; + println!("block_count : {:?}", block_count); + for (idx, tx) in block.txdata.into_iter().enumerate() { let bytes = tx.output[0].script_pubkey.as_bytes(); if bytes.len() > 2 && bytes[0] == 0x6a && bytes[1] <= 0x4e { diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 0d421cc0dc9..3bfd5c0aa0c 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -1,4 +1,3 @@ -pub mod api_paged_response; pub mod api_query; pub mod error; mod indexer; @@ -17,6 +16,7 @@ pub mod api; mod model; mod repository; pub mod storage; +use defichain_rpc::{Auth, Client}; use crate::storage::ocean_store::OceanStore; @@ -25,11 +25,7 @@ pub type Result = std::result::Result; lazy_static::lazy_static! { // Global services exposed by the library pub static ref SERVICES: Services = { - let datadir = ain_cpp_imports::get_datadir(); - let store = OceanStore::new(&PathBuf::from(datadir)).expect("Error initialization Ocean storage"); - Services::new( - Arc::new(store) - ) + Services::new().expect("Error initialization Ocean services") }; } @@ -60,11 +56,21 @@ pub struct Services { auction: AuctionService, result: TxResultRepository, pool: PoolService, + client: Arc, } impl Services { - fn new(store: Arc) -> Self { - Self { + fn new() -> Result { + let datadir = ain_cpp_imports::get_datadir(); + let store = Arc::new(OceanStore::new(&PathBuf::from(datadir))?); + + let (user, pass) = ain_cpp_imports::get_rpc_auth()?; + let client = Arc::new(Client::new( + &format!("localhost:{}", ain_cpp_imports::get_rpc_port()), + Auth::UserPass(user, pass), + )?); + + Ok(Self { masternode: MasternodeService { by_id: MasternodeRepository::new(Arc::clone(&store)), by_height: MasternodeByHeightRepository::new(Arc::clone(&store)), @@ -83,6 +89,7 @@ impl Services { pool: PoolService { by_id: PoolSwapRepository::new(Arc::clone(&store)), }, - } + client, + }) } } diff --git a/lib/cli/src/command.rs b/lib/cli/src/command.rs index c3eff6ef4c3..bbca1e23270 100644 --- a/lib/cli/src/command.rs +++ b/lib/cli/src/command.rs @@ -1,5 +1,5 @@ use ain_grpc::rpc::MetachainRPCClient; -use jsonrpsee::http_client::HttpClient; +use defichain_rpc::{Client, RpcApi}; use crate::{result::RpcResult, MetachainCLI}; diff --git a/src/ffi/ffiexports.cpp b/src/ffi/ffiexports.cpp index 3eb81ba89cc..c66d42e51b0 100644 --- a/src/ffi/ffiexports.cpp +++ b/src/ffi/ffiexports.cpp @@ -23,6 +23,22 @@ uint64_t getChainId() { return Params().GetConsensus().evmChainId; } +int getRPCPort() { + return BaseParams().RPCPort(); +} + +rust::string getRPCAuth() { + // Get credentials + std::string strRPCUserColonPass; + if (gArgs.GetArg("-rpcpassword", "") == "") { + // Try fall back to cookie-based authentication if no password is provided + GetAuthCookie(&strRPCUserColonPass); + } else { + strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", ""); + } + return strRPCUserColonPass; +} + bool isMining() { return gArgs.GetBoolArg("-gen", false); } diff --git a/src/ffi/ffiexports.h b/src/ffi/ffiexports.h index 748fb4c9d5c..52514f67b03 100644 --- a/src/ffi/ffiexports.h +++ b/src/ffi/ffiexports.h @@ -72,6 +72,8 @@ enum class TransactionDataDirection : uint8_t { }; uint64_t getChainId(); +int getRPCPort(); +rust::string getRPCAuth(); bool isMining(); rust::string publishEthTransaction(rust::Vec rawTransaction); rust::vec getAccounts(); From 2639bf2e3d8251a3413748841bf9172748eb11c5 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Thu, 25 Jan 2024 10:41:26 +0100 Subject: [PATCH 031/185] Ocean: Highest block endpoint (#2799) * Ocean endpoints impl for blocks * Fix default iter mode --- lib/ain-db/src/lib.rs | 4 ++-- lib/ain-ocean/src/api/block.rs | 29 ++++++++++++++++++++--------- lib/ain-ocean/src/api/mod.rs | 4 ++-- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/lib/ain-db/src/lib.rs b/lib/ain-db/src/lib.rs index 45fffbd2bce..57d21cbbd9c 100644 --- a/lib/ain-db/src/lib.rs +++ b/lib/ain-db/src/lib.rs @@ -187,8 +187,8 @@ where .map(|i| C::key(i)) .transpose()? .unwrap_or_default(); - let iterator_mode = from.map_or(IteratorMode::Start, |_| { - IteratorMode::From(&index, rocksdb::Direction::Forward) + let iterator_mode = from.map_or(IteratorMode::End, |_| { + IteratorMode::From(&index, rocksdb::Direction::Reverse) }); Ok(self .backend diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index a989e59aa50..e8ffccf2336 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use ain_macros::ocean_endpoint; use axum::{ extract::{Path, Query}, routing::get, @@ -8,14 +9,14 @@ use axum::{ use bitcoin::BlockHash; use defichain_rpc::{Client, RpcApi}; +use super::response::{ApiPagedResponse, Response}; use crate::{ - api_paged_response::ApiPagedResponse, api_query::PaginationQuery, model::Block, - repository::RepositoryOps, Result, SERVICES, + api_query::PaginationQuery, error::ApiError, model::Block, repository::RepositoryOps, + storage::ocean_store, Result, SERVICES, }; -async fn list_blocks( - Query(query): Query, -) -> Result>> { +#[ocean_endpoint] +async fn list_blocks(Query(query): Query) -> Result> { let blocks = SERVICES .block .by_height @@ -33,24 +34,34 @@ async fn list_blocks( }) .collect::>>()?; - Ok(Json(ApiPagedResponse::of(blocks, query.size, |block| { + Ok(ApiPagedResponse::of(blocks, query.size, |block| { block.clone().id - }))) + })) } -async fn get_block(Path(id): Path) -> Result>> { +#[ocean_endpoint] +async fn get_block(Path(id): Path) -> Result>> { let block = SERVICES.block.by_id.get(&id)?; - Ok(Json(block)) + Ok(Response::new(block)) } async fn get_transactions(Path(hash): Path) -> String { format!("Transactions for block with hash {}", hash) } +// Get highest indexed block +#[ocean_endpoint] +async fn get_highest() -> Result>> { + let block = SERVICES.block.by_height.get_highest()?; + + Ok(Response::new(block)) +} + pub fn router(state: Arc) -> Router { Router::new() .route("/", get(list_blocks)) + .route("/highest", get(get_highest)) .route("/:id", get(get_block)) .route("/:hash/transactions", get(get_transactions)) } diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index 6f8f10a17aa..ad9245719c0 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use axum::{extract::Request, http::StatusCode, response::IntoResponse, Json, Router}; // mod address; -// mod block; +mod block; mod fee; // mod governance; // mod loan; @@ -70,6 +70,6 @@ pub fn ocean_router() -> Result { // .nest("/stats", stats::router(Arc::clone(client))) .nest("/tokens", tokens::router(Arc::clone(client))) // .nest("/transactions", transactions::router(Arc::clone(client))) - // .nest("/blocks", block::router(Arc::clone(client))) + .nest("/blocks", block::router(Arc::clone(client))) .fallback(not_found)) } From 4ad383c6a64d37bb254bf233f58c8bea7fc9a9b6 Mon Sep 17 00:00:00 2001 From: jouzo Date: Thu, 25 Jan 2024 11:07:15 +0100 Subject: [PATCH 032/185] Accept height in /blocks/:id --- lib/ain-ocean/src/api/block.rs | 41 +++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index e8ffccf2336..1c69aa85282 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -4,17 +4,39 @@ use ain_macros::ocean_endpoint; use axum::{ extract::{Path, Query}, routing::get, - Json, Router, + Router, }; use bitcoin::BlockHash; -use defichain_rpc::{Client, RpcApi}; +use defichain_rpc::Client; +use serde::{Deserialize, Deserializer}; use super::response::{ApiPagedResponse, Response}; use crate::{ - api_query::PaginationQuery, error::ApiError, model::Block, repository::RepositoryOps, - storage::ocean_store, Result, SERVICES, + api_query::PaginationQuery, error::ApiError, model::Block, repository::RepositoryOps, Result, + SERVICES, }; +enum HashOrHeight { + Height(u32), + Id(BlockHash), +} + +impl<'de> Deserialize<'de> for HashOrHeight { + fn deserialize(deserializer: D) -> std::result::Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + if let Ok(height) = s.parse::() { + Ok(HashOrHeight::Height(height)) + } else if let Ok(id) = s.parse::() { + Ok(HashOrHeight::Id(id)) + } else { + Err(serde::de::Error::custom("Error parsing HashOrHeight")) + } + } +} + #[ocean_endpoint] async fn list_blocks(Query(query): Query) -> Result> { let blocks = SERVICES @@ -40,8 +62,15 @@ async fn list_blocks(Query(query): Query) -> Result) -> Result>> { - let block = SERVICES.block.by_id.get(&id)?; +async fn get_block(Path(id): Path) -> Result>> { + let block = if let Some(id) = match id { + HashOrHeight::Height(n) => SERVICES.block.by_height.get(&n)?, + HashOrHeight::Id(id) => Some(id), + } { + SERVICES.block.by_id.get(&id)? + } else { + None + }; Ok(Response::new(block)) } From 03f03afdb51e7e94f992011a237efc2528120091 Mon Sep 17 00:00:00 2001 From: Nagaraj <144004792+nagarajm22@users.noreply.github.com> Date: Thu, 25 Jan 2024 11:01:22 +0000 Subject: [PATCH 033/185] WIP: Implementation for ocean-API transaction module (#2781) * added transaction index * added transaction api implementation * fixed .cpp file formats * fixed id to Txid * added transction list method by block_hash * added transaction indexing * removed transaction by block_hash from trx module * update txid strong type * removed method list_trasnction_txid * added vin and vout index in transaction with query * updated vin and vout table as Txid * fixed conflicts in transaction branch * fixed fmt * Restore cpp fmt --------- Co-authored-by: jouzo --- lib/ain-ocean/src/api/response.rs | 4 +- lib/ain-ocean/src/api/transactions.rs | 83 +++++++++++++--- lib/ain-ocean/src/indexer/mod.rs | 1 + lib/ain-ocean/src/indexer/transaction.rs | 94 +++++++++++++++++++ lib/ain-ocean/src/lib.rs | 22 ++++- lib/ain-ocean/src/model/transaction.rs | 3 +- lib/ain-ocean/src/repository/transaction.rs | 26 +++++ .../src/repository/transaction_vin.rs | 27 ++++++ .../src/repository/transaction_vout.rs | 27 ++++++ .../src/storage/columns/transaction.rs | 20 +++- .../src/storage/columns/transaction_vin.rs | 7 +- .../src/storage/columns/transaction_vout.rs | 7 +- 12 files changed, 300 insertions(+), 21 deletions(-) create mode 100644 lib/ain-ocean/src/indexer/transaction.rs diff --git a/lib/ain-ocean/src/api/response.rs b/lib/ain-ocean/src/api/response.rs index 4b9c2444509..83cbcd35c28 100644 --- a/lib/ain-ocean/src/api/response.rs +++ b/lib/ain-ocean/src/api/response.rs @@ -128,7 +128,9 @@ mod tests { fn should_next_with_value() { let items: Vec = vec![Item::new("0", "a"), Item::new("1", "b")]; - let next = ApiPagedResponse::next(items, Some("b")).page.next; + let next = ApiPagedResponse::next(items, Some("b".to_string())) + .page + .next; assert_eq!(next, Some("b".into())); } diff --git a/lib/ain-ocean/src/api/transactions.rs b/lib/ain-ocean/src/api/transactions.rs index 9bb495fa306..ef2784ea890 100644 --- a/lib/ain-ocean/src/api/transactions.rs +++ b/lib/ain-ocean/src/api/transactions.rs @@ -1,24 +1,85 @@ -use std::sync::Arc; - -use axum::{extract::Path, routing::get, Router}; -use defichain_rpc::{Client, RpcApi}; +use axum::{ + extract::{Path, Query}, + routing::get, + Json, Router, +}; +use bitcoin::Txid; use serde::Deserialize; +use crate::{ + api_paged_response::ApiPagedResponse, + api_query::PaginationQuery, + model::{Transaction, TransactionVin, TransactionVout}, + repository::RepositoryOps, + Result, SERVICES, +}; + #[derive(Deserialize)] struct TransactionId { - id: String, + id: Txid, } -async fn get_transaction(Path(TransactionId { id }): Path) -> String { - format!("Details of transaction with id {}", id) +async fn get_transaction( + Path(TransactionId { id }): Path, +) -> Result>> { + format!("Details of transaction with id {}", id); + let transactions = SERVICES.transaction.by_id.get(&id)?; + Ok(Json(transactions)) } -async fn get_vins(Path(TransactionId { id }): Path) -> String { - format!("Vins for transaction with id {}", id) +async fn get_vins( + Query(query): Query, +) -> Result>> { + let transaction_list = SERVICES + .transaction + .vin_by_id + .list(None)? + .take(query.size) + .map(|item| { + let (txid, id) = item?; + let b = SERVICES + .transaction + .vin_by_id + .get(&txid)? + .ok_or("Missing block index")?; + + Ok(b) + }) + .collect::>>()?; + + Ok(Json(ApiPagedResponse::of( + transaction_list, + query.size, + |transaction_list| transaction_list.id.clone(), + ))) } -async fn get_vouts(Path(TransactionId { id }): Path) -> String { - format!("Vouts for transaction with id {}", id) +//get list of vout transaction, by passing id which contains txhash + vout_idx +async fn get_vouts( + Query(query): Query, +) -> Result>> { + let transaction_list = SERVICES + .transaction + .vout_by_id + .list(None)? + .take(query.size) + .map(|item| { + let (txid, id) = item?; + let b = SERVICES + .transaction + .vout_by_id + .get(&txid)? + .ok_or("Missing block index")?; + + Ok(b) + }) + .collect::>>()?; + + Ok(Json(ApiPagedResponse::of( + transaction_list, + query.size, + |transaction_list| transaction_list.id.clone(), + ))) } pub fn router(state: Arc) -> Router { diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 6b336671ce5..b3b93b56f63 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -2,6 +2,7 @@ mod auction; mod masternode; mod oracle; mod pool; +pub mod transaction; pub mod tx_result; use defichain_rpc::RpcApi; diff --git a/lib/ain-ocean/src/indexer/transaction.rs b/lib/ain-ocean/src/indexer/transaction.rs new file mode 100644 index 00000000000..95301caf7b8 --- /dev/null +++ b/lib/ain-ocean/src/indexer/transaction.rs @@ -0,0 +1,94 @@ +use bitcoin::{blockdata::locktime::absolute::LockTime, Txid}; +use dftx_rs::{Block, Transaction}; +use log::debug; + +use super::BlockContext; +use crate::{ + indexer::Result, + model::{ + Transaction as TrasnactionMapper, TransactionVin, TransactionVinScript, TransactionVinVout, + TransactionVinVoutScript, TransactionVout, TransactionVoutScript, + }, + repository::RepositoryOps, + SERVICES, +}; + +pub fn index_transactions(ctx: &BlockContext, tx: Transaction) -> Result<()> { + debug!("[CreateTransaction] Indexing..."); + let tx_id = tx.txid(); + + let lock_time_as_i32 = match tx.lock_time { + LockTime::Blocks(value) => value.to_consensus_u32(), + LockTime::Seconds(value) => value.to_consensus_u32(), + }; + let total_vout_value: u64 = tx.output.iter().map(|output| output.value.to_sat()).sum(); + let weight = tx.weight(); + let weight_i32 = weight.to_vbytes_ceil() as i32; + + let trx = TrasnactionMapper { + id: tx_id, + order: 0, + block: ctx.clone(), + txid: tx_id.to_string(), + hash: ctx.hash.to_string(), + version: tx.version.0, + size: tx.total_size() as i32, + v_size: tx.vsize() as i32, + weight: weight_i32, + total_vout_value: total_vout_value.to_string(), + lock_time: lock_time_as_i32 as i32, + vin_count: tx.input.len() as i32, + vout_count: tx.output.len() as i32, + }; + // Index transaction + SERVICES.transaction.by_id.put(&tx_id, &trx)?; + // Indexing transaction vin + for (vin_idx, vin) in tx.input.iter().enumerate() { + let trx_vin = TransactionVin { + id: format!("{}-{}", tx_id, vin_idx), + txid: tx_id.to_string(), + coinbase: vin.script_sig.to_string(), + vout: TransactionVinVout { + id: format!("{}-{}-vout", tx_id, vin_idx), + txid: tx_id.to_string(), + n: vin.previous_output.vout as i32, + value: "0".to_string(), + token_id: 0, + script: TransactionVinVoutScript { + hex: vin.script_sig.to_string(), + }, + }, + script: TransactionVinScript { + hex: vin.script_sig.to_string(), + }, + tx_in_witness: vec![], + sequence: vin.sequence.to_string(), + }; + + SERVICES.transaction.vin_by_id.put(&tx_id, &trx_vin)?; + } + // Index transaction vout + for (vout_idx, vout) in tx.output.iter().enumerate() { + let trx_vout = TransactionVout { + id: format!("{}-{}", tx_id, vout_idx), + txid: tx_id.to_string(), + n: vout_idx as i32, + value: vout.value.to_string(), + token_id: 0, + script: TransactionVoutScript { + hex: vout.script_pubkey.to_string(), + r#type: "pubkey".to_string(), + }, + }; + SERVICES.transaction.vout_by_id.put(&tx_id, &trx_vout)?; + // .put(&format!("{}-{}", tx_id, vout_idx), &trx_vout)?; //need + } + + Ok(()) +} + +pub fn invalidate_transaction(ctx: &BlockContext, tx: Txid, idx: usize) -> Result<()> { + debug!("[CreateMasternode] Invalidating..."); + SERVICES.transaction.by_id.delete(&tx)?; + Ok(()) +} diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 3bfd5c0aa0c..f0852aef327 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -6,11 +6,17 @@ use std::{path::PathBuf, sync::Arc}; pub use api::ocean_router; use error::OceanError; -pub use indexer::{index_block, invalidate_block, tx_result, BlockV2Info}; +pub use indexer::{ + index_block, invalidate_block, + transaction::{index_transactions, invalidate_transaction}, + tx_result, BlockV2Info, +}; +use model::TransactionVin; use repository::{ AuctionHistoryByHeightRepository, AuctionHistoryRepository, BlockByHeightRepository, BlockRepository, MasternodeByHeightRepository, MasternodeRepository, MasternodeStatsRepository, - PoolSwapRepository, RawBlockRepository, TxResultRepository, + PoolSwapRepository, RawBlockRepository, TransactionRepository, TransactionVinRepository, + TransactionVoutRepository, TxResultRepository, }; pub mod api; mod model; @@ -50,6 +56,12 @@ pub struct PoolService { by_id: PoolSwapRepository, } +pub struct TransactionService { + by_id: TransactionRepository, + vin_by_id: TransactionVinRepository, + vout_by_id: TransactionVoutRepository, +} + pub struct Services { masternode: MasternodeService, block: BlockService, @@ -57,6 +69,7 @@ pub struct Services { result: TxResultRepository, pool: PoolService, client: Arc, + transaction: TransactionService, } impl Services { @@ -89,6 +102,11 @@ impl Services { pool: PoolService { by_id: PoolSwapRepository::new(Arc::clone(&store)), }, + transaction: TransactionService { + by_id: TransactionRepository::new(Arc::clone(&store)), + vin_by_id: TransactionVinRepository::new(Arc::clone(&store)), + vout_by_id: TransactionVoutRepository::new(Arc::clone(&store)), + }, client, }) } diff --git a/lib/ain-ocean/src/model/transaction.rs b/lib/ain-ocean/src/model/transaction.rs index f1573415d29..f4ba1207036 100644 --- a/lib/ain-ocean/src/model/transaction.rs +++ b/lib/ain-ocean/src/model/transaction.rs @@ -1,3 +1,4 @@ +use bitcoin::Txid; use serde::{Deserialize, Serialize}; use super::BlockContext; @@ -5,7 +6,7 @@ use super::BlockContext; #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Transaction { - pub id: String, + pub id: Txid, pub order: i32, pub block: BlockContext, pub txid: String, diff --git a/lib/ain-ocean/src/repository/transaction.rs b/lib/ain-ocean/src/repository/transaction.rs index 8b137891791..a8f271694ba 100644 --- a/lib/ain-ocean/src/repository/transaction.rs +++ b/lib/ain-ocean/src/repository/transaction.rs @@ -1 +1,27 @@ +use std::sync::Arc; +use ain_db::LedgerColumn; +use ain_macros::Repository; +use bitcoin::{BlockHash, Txid}; + +use super::RepositoryOps; +use crate::{ + model::Transaction, + storage::{columns, ocean_store::OceanStore}, + Result, +}; +#[derive(Repository)] +#[repository(K = "Txid", V = "Transaction")] +pub struct TransactionRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl TransactionRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} diff --git a/lib/ain-ocean/src/repository/transaction_vin.rs b/lib/ain-ocean/src/repository/transaction_vin.rs index 8b137891791..7d2c2ff3755 100644 --- a/lib/ain-ocean/src/repository/transaction_vin.rs +++ b/lib/ain-ocean/src/repository/transaction_vin.rs @@ -1 +1,28 @@ +use std::sync::Arc; +use ain_db::LedgerColumn; +use ain_macros::Repository; +use bitcoin::Txid; + +use super::RepositoryOps; +use crate::{ + model::TransactionVin, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "Txid", V = "TransactionVin")] +pub struct TransactionVinRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl TransactionVinRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} diff --git a/lib/ain-ocean/src/repository/transaction_vout.rs b/lib/ain-ocean/src/repository/transaction_vout.rs index 8b137891791..1bbd8cc6a27 100644 --- a/lib/ain-ocean/src/repository/transaction_vout.rs +++ b/lib/ain-ocean/src/repository/transaction_vout.rs @@ -1 +1,28 @@ +use std::sync::Arc; +use ain_db::LedgerColumn; +use ain_macros::Repository; +use bitcoin::Txid; + +use super::RepositoryOps; +use crate::{ + model::TransactionVout, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "Txid", V = "TransactionVout")] +pub struct TransactionVoutRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl TransactionVoutRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} diff --git a/lib/ain-ocean/src/storage/columns/transaction.rs b/lib/ain-ocean/src/storage/columns/transaction.rs index 8c2052f21a4..d3fefc45584 100644 --- a/lib/ain-ocean/src/storage/columns/transaction.rs +++ b/lib/ain-ocean/src/storage/columns/transaction.rs @@ -1,5 +1,7 @@ use ain_db::{Column, ColumnName, TypedColumn}; +use bitcoin::{BlockHash, Txid}; +use crate::model; #[derive(Debug)] pub struct Transaction; @@ -8,9 +10,23 @@ impl ColumnName for Transaction { } impl Column for Transaction { - type Index = String; + type Index = Txid; } impl TypedColumn for Transaction { - type Type = String; + type Type = model::Transaction; +} + +pub struct TransactionByBlockHash; + +impl ColumnName for TransactionByBlockHash { + const NAME: &'static str = "transaction_by_block_hash"; +} + +impl Column for TransactionByBlockHash { + type Index = BlockHash; +} + +impl TypedColumn for TransactionByBlockHash { + type Type = model::Transaction; } diff --git a/lib/ain-ocean/src/storage/columns/transaction_vin.rs b/lib/ain-ocean/src/storage/columns/transaction_vin.rs index a8149b1e5b4..bbe2fa4b513 100644 --- a/lib/ain-ocean/src/storage/columns/transaction_vin.rs +++ b/lib/ain-ocean/src/storage/columns/transaction_vin.rs @@ -1,4 +1,7 @@ use ain_db::{Column, ColumnName, TypedColumn}; +use bitcoin::Txid; + +use crate::model; #[derive(Debug)] pub struct TransactionVin; @@ -8,9 +11,9 @@ impl ColumnName for TransactionVin { } impl Column for TransactionVin { - type Index = String; + type Index = Txid; } impl TypedColumn for TransactionVin { - type Type = String; + type Type = model::TransactionVin; } diff --git a/lib/ain-ocean/src/storage/columns/transaction_vout.rs b/lib/ain-ocean/src/storage/columns/transaction_vout.rs index 7de7b41c183..3af1bd48da6 100644 --- a/lib/ain-ocean/src/storage/columns/transaction_vout.rs +++ b/lib/ain-ocean/src/storage/columns/transaction_vout.rs @@ -1,4 +1,7 @@ use ain_db::{Column, ColumnName, TypedColumn}; +use bitcoin::Txid; + +use crate::model; #[derive(Debug)] pub struct TransactionVout; @@ -7,9 +10,9 @@ impl ColumnName for TransactionVout { } impl Column for TransactionVout { - type Index = String; + type Index = Txid; } impl TypedColumn for TransactionVout { - type Type = String; + type Type = model::TransactionVout; } From 11b48608884183ff72adbca0b36db72ac25a70b3 Mon Sep 17 00:00:00 2001 From: jouzo Date: Thu, 25 Jan 2024 21:04:35 +0100 Subject: [PATCH 034/185] Log indexing time --- lib/ain-ocean/src/indexer/mod.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index b3b93b56f63..dd586d1de53 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -5,6 +5,8 @@ mod pool; pub mod transaction; pub mod tx_result; +use std::time::Instant; + use defichain_rpc::RpcApi; use dftx_rs::{deserialize, Block, DfTx, Transaction}; use log::debug; @@ -34,8 +36,14 @@ pub struct BlockV2Info { pub masternode: String, } +fn log_elapsed(previous: Instant, msg: &str) { + let now = Instant::now(); + println!("{} in {} ms", msg, now.duration_since(previous).as_millis()); +} + pub fn index_block(encoded_block: String, info: &BlockV2Info) -> Result<()> { debug!("[index_block] Indexing block..."); + let start = Instant::now(); let hex = hex::decode(&encoded_block)?; debug!("got hex"); @@ -72,10 +80,8 @@ pub fn index_block(encoded_block: String, info: &BlockV2Info) -> Result<()> { SERVICES.block.by_id.put(&ctx.hash, &block_mapper)?; SERVICES.block.by_height.put(&ctx.height, &block_hash)?; - let block_count = SERVICES.client.get_block_count()?; - println!("block_count : {:?}", block_count); - for (idx, tx) in block.txdata.into_iter().enumerate() { + let start = Instant::now(); let bytes = tx.output[0].script_pubkey.as_bytes(); if bytes.len() > 2 && bytes[0] == 0x6a && bytes[1] <= 0x4e { let offset = 1 + match bytes[1] { @@ -88,7 +94,7 @@ pub fn index_block(encoded_block: String, info: &BlockV2Info) -> Result<()> { let raw_tx = &bytes[offset..]; let dftx = deserialize::(raw_tx)?; debug!("dftx : {:?}", dftx); - match dftx { + match &dftx { DfTx::CreateMasternode(data) => data.index(&ctx, tx, idx)?, DfTx::UpdateMasternode(data) => data.index(&ctx, tx, idx)?, DfTx::ResignMasternode(data) => data.index(&ctx, tx, idx)?, @@ -101,9 +107,12 @@ pub fn index_block(encoded_block: String, info: &BlockV2Info) -> Result<()> { DfTx::PlaceAuctionBid(data) => data.index(&ctx, tx, idx)?, _ => (), } + log_elapsed(start, &format!("Indexed tx {:?}", dftx)); } } + log_elapsed(start, "Indexed block"); + Ok(()) } From d9598bb50118b4f212b542bcaf24a065f2e25af2 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Thu, 25 Jan 2024 23:21:06 +0100 Subject: [PATCH 035/185] Ocean: Fix Transaction index typing (#2801) * Proper transaction typing * Fix txid type --- lib/ain-ocean/src/indexer/transaction.rs | 41 ++++++++++------------ lib/ain-ocean/src/lib.rs | 2 +- lib/ain-ocean/src/model/transaction.rs | 21 ++++++----- lib/ain-ocean/src/model/transaction_vin.rs | 9 ++--- 4 files changed, 35 insertions(+), 38 deletions(-) diff --git a/lib/ain-ocean/src/indexer/transaction.rs b/lib/ain-ocean/src/indexer/transaction.rs index 95301caf7b8..ec76c414acd 100644 --- a/lib/ain-ocean/src/indexer/transaction.rs +++ b/lib/ain-ocean/src/indexer/transaction.rs @@ -1,44 +1,41 @@ use bitcoin::{blockdata::locktime::absolute::LockTime, Txid}; -use dftx_rs::{Block, Transaction}; +use dftx_rs::Transaction; use log::debug; use super::BlockContext; use crate::{ indexer::Result, model::{ - Transaction as TrasnactionMapper, TransactionVin, TransactionVinScript, TransactionVinVout, + Transaction as TransactionMapper, TransactionVin, TransactionVinScript, TransactionVinVout, TransactionVinVoutScript, TransactionVout, TransactionVoutScript, }, repository::RepositoryOps, SERVICES, }; -pub fn index_transactions(ctx: &BlockContext, tx: Transaction) -> Result<()> { - debug!("[CreateTransaction] Indexing..."); +pub fn index_transaction(ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + debug!("[index_transaction] Indexing..."); let tx_id = tx.txid(); - let lock_time_as_i32 = match tx.lock_time { + let lock_time = match tx.lock_time { LockTime::Blocks(value) => value.to_consensus_u32(), LockTime::Seconds(value) => value.to_consensus_u32(), }; - let total_vout_value: u64 = tx.output.iter().map(|output| output.value.to_sat()).sum(); - let weight = tx.weight(); - let weight_i32 = weight.to_vbytes_ceil() as i32; + let total_vout_value = tx.output.iter().map(|output| output.value.to_sat()).sum(); - let trx = TrasnactionMapper { + let trx = TransactionMapper { id: tx_id, - order: 0, + order: idx, block: ctx.clone(), - txid: tx_id.to_string(), - hash: ctx.hash.to_string(), + hash: ctx.hash, version: tx.version.0, - size: tx.total_size() as i32, - v_size: tx.vsize() as i32, - weight: weight_i32, - total_vout_value: total_vout_value.to_string(), - lock_time: lock_time_as_i32 as i32, - vin_count: tx.input.len() as i32, - vout_count: tx.output.len() as i32, + size: tx.total_size(), + v_size: tx.vsize(), + weight: tx.weight().to_wu(), + total_vout_value, + lock_time: lock_time, + vin_count: tx.input.len(), + vout_count: tx.output.len(), }; // Index transaction SERVICES.transaction.by_id.put(&tx_id, &trx)?; @@ -46,11 +43,11 @@ pub fn index_transactions(ctx: &BlockContext, tx: Transaction) -> Result<()> { for (vin_idx, vin) in tx.input.iter().enumerate() { let trx_vin = TransactionVin { id: format!("{}-{}", tx_id, vin_idx), - txid: tx_id.to_string(), + txid: tx_id, coinbase: vin.script_sig.to_string(), vout: TransactionVinVout { id: format!("{}-{}-vout", tx_id, vin_idx), - txid: tx_id.to_string(), + txid: tx_id, n: vin.previous_output.vout as i32, value: "0".to_string(), token_id: 0, @@ -88,7 +85,7 @@ pub fn index_transactions(ctx: &BlockContext, tx: Transaction) -> Result<()> { } pub fn invalidate_transaction(ctx: &BlockContext, tx: Txid, idx: usize) -> Result<()> { - debug!("[CreateMasternode] Invalidating..."); + debug!("[invalidate_transaction] Invalidating..."); SERVICES.transaction.by_id.delete(&tx)?; Ok(()) } diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index f0852aef327..3e2eac8d87c 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -8,7 +8,7 @@ pub use api::ocean_router; use error::OceanError; pub use indexer::{ index_block, invalidate_block, - transaction::{index_transactions, invalidate_transaction}, + transaction::{index_transaction, invalidate_transaction}, tx_result, BlockV2Info, }; use model::TransactionVin; diff --git a/lib/ain-ocean/src/model/transaction.rs b/lib/ain-ocean/src/model/transaction.rs index f4ba1207036..7cbeb26c9ab 100644 --- a/lib/ain-ocean/src/model/transaction.rs +++ b/lib/ain-ocean/src/model/transaction.rs @@ -1,4 +1,4 @@ -use bitcoin::Txid; +use bitcoin::{BlockHash, Txid}; use serde::{Deserialize, Serialize}; use super::BlockContext; @@ -7,16 +7,15 @@ use super::BlockContext; #[serde(rename_all = "camelCase")] pub struct Transaction { pub id: Txid, - pub order: i32, + pub order: usize, pub block: BlockContext, - pub txid: String, - pub hash: String, + pub hash: BlockHash, pub version: i32, - pub size: i32, - pub v_size: i32, - pub weight: i32, - pub total_vout_value: String, - pub lock_time: i32, - pub vin_count: i32, - pub vout_count: i32, + pub size: usize, + pub v_size: usize, + pub weight: u64, + pub total_vout_value: u64, + pub lock_time: u32, + pub vin_count: usize, + pub vout_count: usize, } diff --git a/lib/ain-ocean/src/model/transaction_vin.rs b/lib/ain-ocean/src/model/transaction_vin.rs index f3317ec5cad..6694ab21c72 100644 --- a/lib/ain-ocean/src/model/transaction_vin.rs +++ b/lib/ain-ocean/src/model/transaction_vin.rs @@ -1,8 +1,9 @@ +use bitcoin::Txid; use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct TransactionVin { pub id: String, - pub txid: String, + pub txid: Txid, pub coinbase: String, pub vout: TransactionVinVout, pub script: TransactionVinScript, @@ -10,10 +11,10 @@ pub struct TransactionVin { pub sequence: String, } -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct TransactionVinVout { pub id: String, - pub txid: String, + pub txid: Txid, pub n: i32, pub value: String, pub token_id: i32, From b9ff0c8105b992e89baebad39c86e0a4712a7491 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Mon, 29 Jan 2024 10:55:54 +0100 Subject: [PATCH 036/185] Ocean: Governance API (#2805) * Governance API * Make query types public --- lib/Cargo.lock | 6 +- lib/ain-macros/src/lib.rs | 5 +- lib/ain-ocean/Cargo.toml | 1 + lib/ain-ocean/src/api/block.rs | 15 ++- lib/ain-ocean/src/api/fee.rs | 9 +- lib/ain-ocean/src/api/governance.rs | 109 ++++++++++++++++++-- lib/ain-ocean/src/api/mod.rs | 4 +- lib/ain-ocean/src/api/response.rs | 4 +- lib/ain-ocean/src/api/tokens.rs | 16 ++- lib/ain-ocean/src/api_query.rs | 40 ++++++- lib/ain-ocean/src/error.rs | 22 ++-- lib/ain-ocean/src/indexer/mod.rs | 1 - lib/ain-ocean/src/lib.rs | 1 - lib/ain-ocean/src/repository/transaction.rs | 2 +- src/init.cpp | 2 + 15 files changed, 186 insertions(+), 51 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 00ebbaf2e56..54e01604207 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -250,6 +250,7 @@ dependencies = [ "rocksdb", "serde", "serde_json", + "serde_urlencoded", "structopt", "tarpc", "tempdir", @@ -1349,7 +1350,7 @@ dependencies = [ [[package]] name = "defichain-rpc" version = "0.18.0" -source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#793a46b73c098f44a9038a332659381b43205119" +source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#fc9a999c32d9b7c081830221099cc9a65dc86080" dependencies = [ "defichain-rpc-json", "jsonrpc", @@ -1361,11 +1362,12 @@ dependencies = [ [[package]] name = "defichain-rpc-json" version = "0.18.0" -source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#793a46b73c098f44a9038a332659381b43205119" +source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#fc9a999c32d9b7c081830221099cc9a65dc86080" dependencies = [ "bitcoin", "serde", "serde_json", + "serde_with", ] [[package]] diff --git a/lib/ain-macros/src/lib.rs b/lib/ain-macros/src/lib.rs index 9eee261ec0f..bab85414385 100644 --- a/lib/ain-macros/src/lib.rs +++ b/lib/ain-macros/src/lib.rs @@ -2,10 +2,7 @@ extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; -use syn::{ - parse_macro_input, parse_quote, Attribute, DeriveInput, Expr, FnArg, ItemFn, LitStr, - ReturnType, Type, -}; +use syn::{parse_macro_input, Attribute, DeriveInput, ItemFn, LitStr, ReturnType, Type}; #[proc_macro_attribute] pub fn ffi_fallible(_attr: TokenStream, item: TokenStream) -> TokenStream { diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index 2097cd45814..15ec86316d0 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -41,3 +41,4 @@ lazy_static.workspace = true bincode.workspace = true defichain-rpc = { version = "0.18.0", git = "https://github.com/Jouzo/rust-defichain-rpc.git" } jsonrpc = "0.14.1" +serde_urlencoded = { version = "0.7" } diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 1c69aa85282..a1c18bad4fd 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -1,22 +1,21 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; -use axum::{ - extract::{Path, Query}, - routing::get, - Router, -}; +use axum::{extract::Path, routing::get, Router}; use bitcoin::BlockHash; use defichain_rpc::Client; use serde::{Deserialize, Deserializer}; use super::response::{ApiPagedResponse, Response}; use crate::{ - api_query::PaginationQuery, error::ApiError, model::Block, repository::RepositoryOps, Result, - SERVICES, + api_query::{PaginationQuery, Query}, + error::ApiError, + model::Block, + repository::RepositoryOps, + Result, SERVICES, }; -enum HashOrHeight { +pub enum HashOrHeight { Height(u32), Id(BlockHash), } diff --git a/lib/ain-ocean/src/api/fee.rs b/lib/ain-ocean/src/api/fee.rs index e5bca56f16f..476f654e0b1 100644 --- a/lib/ain-ocean/src/api/fee.rs +++ b/lib/ain-ocean/src/api/fee.rs @@ -1,15 +1,15 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; -use axum::{extract::Query, routing::get, Extension, Json, Router}; +use axum::{routing::get, Extension, Router}; use defichain_rpc::{json::mining::SmartFeeEstimation, Client, RpcApi}; use serde::Deserialize; use super::response::Response; -use crate::{error::ApiError, Result}; +use crate::{api_query::Query, error::ApiError, Result}; -#[derive(Deserialize)] -struct EstimateQuery { +#[derive(Deserialize, Default)] +pub struct EstimateQuery { confirmation_target: i32, } @@ -24,7 +24,6 @@ async fn estimate_fee( "estimatesmartfee", &[confirmation_target.into(), "CONSERVATIVE".into()], )?; - println!("estimation : {:?}", estimation); Ok(Response::new(estimation.feerate.unwrap_or(0.00005000))) } diff --git a/lib/ain-ocean/src/api/governance.rs b/lib/ain-ocean/src/api/governance.rs index 8fca5c52249..6d7b4f979d7 100644 --- a/lib/ain-ocean/src/api/governance.rs +++ b/lib/ain-ocean/src/api/governance.rs @@ -1,18 +1,110 @@ use std::sync::Arc; -use axum::{extract::Path, routing::get, Router}; -use defichain_rpc::{Client, RpcApi}; +use ain_macros::ocean_endpoint; +use axum::{extract::Path, routing::get, Extension, Router}; +use bitcoin::Txid; +use defichain_rpc::{json::governance::*, Client, GovernanceRPC}; +use serde::Deserialize; -async fn list_gov_proposals() -> String { - "List of governance proposals".to_string() +use super::response::{ApiPagedResponse, Response}; +use crate::{ + api_query::{PaginationQuery, Query}, + error::{ApiError, NotFoundKind, OceanError}, + Result, +}; + +#[derive(Deserialize, Default)] +pub struct GovernanceQuery { + #[serde(flatten)] + pub pagination: PaginationQuery, + pub status: Option, + pub r#type: Option, + pub cycle: Option, + pub all: Option, + pub masternode: Option, } -async fn get_gov_proposal(Path(proposal_id): Path) -> String { - format!("Details of governance proposal with id {}", proposal_id) +#[ocean_endpoint] +async fn list_gov_proposals( + Query(query): Query, + Extension(client): Extension>, +) -> Result> { + let size = match query.all { + Some(true) => 0, + _ => query.pagination.size, + }; + + let opts = ListProposalsOptions { + pagination: Some(ListProposalsPagination { + limit: Some(size), + ..ListProposalsPagination::default() + }), + status: query.status, + r#type: query.r#type, + cycle: query.cycle, + }; + let proposals = client.list_gov_proposals(Some(opts))?; + + Ok(ApiPagedResponse::of(proposals, size, |proposal| { + proposal.proposal_id.to_string() + })) } -async fn list_gov_proposal_votes(Path(proposal_id): Path) -> String { - format!("Votes for governance proposal with id {}", proposal_id) +#[ocean_endpoint] +async fn get_gov_proposal( + Path(proposal_id): Path, + Extension(client): Extension>, +) -> Result> { + let txid: Txid = proposal_id + .parse() + .map_err(|_| OceanError::NotFound(NotFoundKind::Proposal))?; + + let proposal = client.get_gov_proposal(txid)?; + Ok(Response::new(proposal)) +} + +#[ocean_endpoint] +async fn list_gov_proposal_votes( + Path(proposal_id): Path, + Query(query): Query, + Extension(client): Extension>, +) -> Result> { + let proposal_id: Txid = proposal_id + .parse() + .map_err(|_| OceanError::NotFound(NotFoundKind::Proposal))?; + + let size = match query.all { + Some(true) => 0, + _ => query.pagination.size, + }; + + let start = query + .pagination + .next + .map(|v| v.parse::()) + .transpose()?; + + let opts = ListGovProposalVotesOptions { + proposal_id: Some(proposal_id), + masternode: query.masternode, + pagination: Some(ListGovProposalVotesPagination { + limit: Some(size), + start, + ..ListGovProposalVotesPagination::default() + }), + cycle: query.cycle, + aggregate: None, + valid: None, + }; + let votes = client.list_gov_proposal_votes(Some(opts))?; + let len = votes.len(); + Ok(ApiPagedResponse::of(votes, size, |_| { + if let Some(next) = start { + return next + len; + } else { + len - 1 + } + })) } pub fn router(state: Arc) -> Router { @@ -20,4 +112,5 @@ pub fn router(state: Arc) -> Router { .route("/proposals", get(list_gov_proposals)) .route("/proposals/:id", get(get_gov_proposal)) .route("/proposals/:id/votes", get(list_gov_proposal_votes)) + .layer(Extension(state)) } diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index ad9245719c0..ceb13f579ae 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -5,7 +5,7 @@ use axum::{extract::Request, http::StatusCode, response::IntoResponse, Json, Rou // mod address; mod block; mod fee; -// mod governance; +mod governance; // mod loan; // mod masternode; // mod oracle; @@ -59,7 +59,7 @@ pub fn ocean_router() -> Result { Ok(Router::new() // .nest("/address", address::router(Arc::clone(client))) - // .nest("/governance", governance::router(Arc::clone(client))) + .nest("/governance", governance::router(Arc::clone(client))) // .nest("/loans", loan::router(Arc::clone(client))) .nest("/fee", fee::router(Arc::clone(client))) // .nest("/masternodes", masternode::router(Arc::clone(client))) diff --git a/lib/ain-ocean/src/api/response.rs b/lib/ain-ocean/src/api/response.rs index 83cbcd35c28..ddb86e31892 100644 --- a/lib/ain-ocean/src/api/response.rs +++ b/lib/ain-ocean/src/api/response.rs @@ -83,9 +83,9 @@ impl ApiPagedResponse { Self::new(data, next) } - pub fn of(data: Vec, limit: usize, next_provider: impl Fn(&T) -> String) -> Self { + pub fn of(data: Vec, limit: usize, next_provider: impl Fn(&T) -> U) -> Self { if data.len() == limit && data.len() > 0 && limit > 0 { - let next = next_provider(&data[limit - 1]); + let next = next_provider(&data[limit - 1]).to_string(); Self::next(data, Some(next)) } else { Self::next(data, None) diff --git a/lib/ain-ocean/src/api/tokens.rs b/lib/ain-ocean/src/api/tokens.rs index 92c9d348433..7df0d7cd49d 100644 --- a/lib/ain-ocean/src/api/tokens.rs +++ b/lib/ain-ocean/src/api/tokens.rs @@ -1,11 +1,7 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; -use axum::{ - extract::{Path, Query}, - routing::get, - Extension, Json, Router, -}; +use axum::{extract::Path, routing::get, Extension, Router}; use defichain_rpc::{ json::token::{TokenInfo, TokenResult}, Client, RpcApi, @@ -17,7 +13,11 @@ use super::{ common::parse_display_symbol, response::{ApiPagedResponse, Response}, }; -use crate::{api_query::PaginationQuery, error::ApiError, Result}; +use crate::{ + api_query::{PaginationQuery, Query}, + error::ApiError, + Result, +}; #[derive(Serialize, Debug, Clone, Default)] pub struct TxHeight { @@ -109,9 +109,7 @@ async fn list_tokens( .into_iter() .map(|(k, v)| TokenData::from_with_id(k, v)) .collect::>(); - Ok(ApiPagedResponse::of(res, query.size, |token| { - token.id.to_string() - })) + Ok(ApiPagedResponse::of(res, query.size, |token| token.id)) } #[ocean_endpoint] diff --git a/lib/ain-ocean/src/api_query.rs b/lib/ain-ocean/src/api_query.rs index fd831456678..21d41e12407 100644 --- a/lib/ain-ocean/src/api_query.rs +++ b/lib/ain-ocean/src/api_query.rs @@ -1,7 +1,43 @@ -use serde::Deserialize; +use axum::{ + async_trait, + extract::FromRequestParts, + http::{request::Parts, StatusCode}, +}; +use serde::{de::DeserializeOwned, Deserialize}; -#[derive(Deserialize)] +use crate::error::ApiError; + +pub fn default_pagination_size() -> usize { + 30 +} + +#[derive(Deserialize, Default, Debug)] pub struct PaginationQuery { + #[serde(default = "default_pagination_size")] pub size: usize, pub next: Option, } + +pub struct Query(pub T); + +#[async_trait] +impl FromRequestParts for Query +where + T: Default + DeserializeOwned, + S: Send + Sync, +{ + type Rejection = ApiError; + + async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result { + let query = parts.uri.query().unwrap_or_default(); + + match serde_urlencoded::from_str(query) { + Ok(v) => Ok(Query(v)), + Err(e) => Err(ApiError::new( + StatusCode::BAD_REQUEST, + format!("Invalid query parameter value for {query}. {e}"), + parts.uri.to_string(), + )), + } + } +} diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index eda9fff4ba6..aaf5053ce23 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -11,6 +11,12 @@ use bitcoin::hex::HexToArrayError; use serde::Serialize; use thiserror::Error; +#[derive(Error, Debug)] +pub enum NotFoundKind { + #[error("proposal")] + Proposal, +} + #[derive(Error, Debug)] pub enum OceanError { #[error("Ocean: HexToArrayError error: {0:?}")] @@ -31,20 +37,23 @@ pub enum OceanError { SerdeJSONError(#[from] serde_json::Error), #[error("Ocean: RPC error: {0:?}")] RpcError(#[from] defichain_rpc::Error), + #[error("Unable to find {0:}")] + NotFound(NotFoundKind), #[error(transparent)] Other(#[from] anyhow::Error), } #[derive(Serialize)] -pub enum ErrorType { +pub enum ErrorKind { NotFound, + BadRequest, Unknown, } #[derive(Serialize)] struct ApiErrorData { code: u16, - r#type: ErrorType, + r#type: ErrorKind, at: u128, message: String, url: String, @@ -65,8 +74,9 @@ impl ApiError { .as_millis(); let r#type = match status { - StatusCode::NOT_FOUND => ErrorType::NotFound, - _ => ErrorType::Unknown, + StatusCode::NOT_FOUND => ErrorKind::NotFound, + StatusCode::BAD_REQUEST => ErrorKind::BadRequest, + _ => ErrorKind::Unknown, }; Self { @@ -96,11 +106,11 @@ impl OceanError { OceanError::RpcError(defichain_rpc::Error::JsonRpc(jsonrpc::error::Error::Rpc(e))) => { println!("e : {:?}", e); - (StatusCode::NOT_FOUND, format!("")) + (StatusCode::NOT_FOUND, format!("{}", e.message)) } + OceanError::NotFound(reason) => (StatusCode::NOT_FOUND, format!("{reason}")), _ => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()), }; - println!("reason : {:?}", reason); (code, reason) } } diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index dd586d1de53..40997243b54 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -7,7 +7,6 @@ pub mod tx_result; use std::time::Instant; -use defichain_rpc::RpcApi; use dftx_rs::{deserialize, Block, DfTx, Transaction}; use log::debug; diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 3e2eac8d87c..46c8f3067e5 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -11,7 +11,6 @@ pub use indexer::{ transaction::{index_transaction, invalidate_transaction}, tx_result, BlockV2Info, }; -use model::TransactionVin; use repository::{ AuctionHistoryByHeightRepository, AuctionHistoryRepository, BlockByHeightRepository, BlockRepository, MasternodeByHeightRepository, MasternodeRepository, MasternodeStatsRepository, diff --git a/lib/ain-ocean/src/repository/transaction.rs b/lib/ain-ocean/src/repository/transaction.rs index a8f271694ba..3a92b97ffc0 100644 --- a/lib/ain-ocean/src/repository/transaction.rs +++ b/lib/ain-ocean/src/repository/transaction.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use ain_db::LedgerColumn; use ain_macros::Repository; -use bitcoin::{BlockHash, Txid}; +use bitcoin::Txid; use super::RepositoryOps; use crate::{ diff --git a/src/init.cpp b/src/init.cpp index 26178e6380a..9aefc3cace5 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2404,6 +2404,7 @@ bool AppInitMain(InitInterfaces& interfaces) } // bind ocean REST addresses + if (gArgs.GetBoolArg("-oceanarchive", DEFAULT_OCEAN_ARCHIVE_ENABLED)) { // for (auto it = ocean_endpoints.begin(); it != ocean_endpoints.end(); ++it) { // LogPrint(BCLog::HTTP, "Binding ocean server on endpoint %s\n", *it); auto res = XResultStatusLogged(ain_rs_init_network_rest_ocean(result, "127.0.0.1:3002")) @@ -2412,6 +2413,7 @@ bool AppInitMain(InitInterfaces& interfaces) return false; } // } + } } uiInterface.InitMessage(_("Done loading").translated); From aea2a9644658a3ab89e10d9421dd5ced6c37b6e9 Mon Sep 17 00:00:00 2001 From: jouzo Date: Tue, 30 Jan 2024 09:51:33 +0100 Subject: [PATCH 037/185] Format cpp --- src/dfi/consensus/poolpairs.cpp | 6 ++++-- src/dfi/mn_checks.cpp | 5 ++++- src/dfi/mn_checks.h | 4 +++- src/dfi/validation.cpp | 9 +++++---- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/dfi/consensus/poolpairs.cpp b/src/dfi/consensus/poolpairs.cpp index 20e61750a08..cf36b105141 100644 --- a/src/dfi/consensus/poolpairs.cpp +++ b/src/dfi/consensus/poolpairs.cpp @@ -132,7 +132,8 @@ Res CPoolPairsConsensus::operator()(const CPoolSwapMessage &obj) const { const auto &tx = txCtx.GetTransaction(); auto &mnview = blockCtx.GetView(); - return CPoolSwap(obj, height, std::make_pair(CustomTxType::PoolSwap, tx.GetHash())).ExecuteSwap(mnview, {}, consensus); + return CPoolSwap(obj, height, std::make_pair(CustomTxType::PoolSwap, tx.GetHash())) + .ExecuteSwap(mnview, {}, consensus); } Res CPoolPairsConsensus::operator()(const CPoolSwapMessageV2 &obj) const { @@ -146,7 +147,8 @@ Res CPoolPairsConsensus::operator()(const CPoolSwapMessageV2 &obj) const { const auto &tx = txCtx.GetTransaction(); auto &mnview = blockCtx.GetView(); - return CPoolSwap(obj.swapInfo, height, std::make_pair(CustomTxType::PoolSwapV2, tx.GetHash())).ExecuteSwap(mnview, obj.poolIDs, consensus); + return CPoolSwap(obj.swapInfo, height, std::make_pair(CustomTxType::PoolSwapV2, tx.GetHash())) + .ExecuteSwap(mnview, obj.poolIDs, consensus); } Res CPoolPairsConsensus::operator()(const CLiquidityMessage &obj) const { diff --git a/src/dfi/mn_checks.cpp b/src/dfi/mn_checks.cpp index 8672cd2fbd3..8adbf2a9664 100644 --- a/src/dfi/mn_checks.cpp +++ b/src/dfi/mn_checks.cpp @@ -1148,7 +1148,10 @@ Res CPoolSwap::ExecuteSwap(CCustomCSView &view, if (txInfo) { const auto &[txType, txHash] = *txInfo; CrossBoundaryResult ffiResult; - ocean_try_set_tx_result(ffiResult, static_cast(txType), txHash.GetByteArray(), static_cast(reinterpret_cast(&finalSwapAmount))); + ocean_try_set_tx_result(ffiResult, + static_cast(txType), + txHash.GetByteArray(), + static_cast(reinterpret_cast(&finalSwapAmount))); } return Res::Ok(); diff --git a/src/dfi/mn_checks.h b/src/dfi/mn_checks.h index c757ed632d7..1444d185b1a 100644 --- a/src/dfi/mn_checks.h +++ b/src/dfi/mn_checks.h @@ -278,7 +278,9 @@ class CPoolSwap { public: std::vector> errors; - CPoolSwap(const CPoolSwapMessage &obj, const uint32_t height, const std::optional> txInfo = std::nullopt) + CPoolSwap(const CPoolSwapMessage &obj, + const uint32_t height, + const std::optional> txInfo = std::nullopt) : obj(obj), height(height), txInfo(txInfo) {} diff --git a/src/dfi/validation.cpp b/src/dfi/validation.cpp index f1df0756930..54a6710d053 100644 --- a/src/dfi/validation.cpp +++ b/src/dfi/validation.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -21,7 +22,6 @@ #include #include #include -#include #include @@ -2809,8 +2809,8 @@ Res ProcessDeFiEventFallible(const CBlock &block, info.size_stripped = GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS); info.weight = GetBlockWeight(block); info.stake_modifier = pindex->stakeModifier.ToString(); - info.minter = ""; // mn operator address - info.masternode = ""; // mn owner address + info.minter = ""; // mn operator address + info.masternode = ""; // mn owner address // minter info CKeyID minter; @@ -2821,7 +2821,8 @@ Res ProcessDeFiEventFallible(const CBlock &block, info.masternode = id->ToString(); auto mn = mnview.GetMasternode(*id); if (mn) { - auto dest = mn->operatorType == 1 ? CTxDestination(PKHash(minter)) : CTxDestination(WitnessV0KeyHash(minter)); + auto dest = + mn->operatorType == 1 ? CTxDestination(PKHash(minter)) : CTxDestination(WitnessV0KeyHash(minter)); info.minter = EncodeDestination(dest); } } From d69bf288f9ea6e4ed750592962cf339da4187415 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Wed, 31 Jan 2024 16:57:42 +0800 Subject: [PATCH 038/185] Ocean CI Refinement (#2764) * point to working jf branch * build on current branch * test masternode only * mv docker-build into test * rm specific test * rm ci docker build * defid-e2e/module.api * rm Response wrapper * fix wrong e2e path * serde camelcase on fee api query * add oceanarchiveport flag * update ci test path --- .github/workflows/tests-ocean.yml | 50 ++++++++--------------------- lib/ain-ocean/src/api/block.rs | 10 +++--- lib/ain-ocean/src/api/fee.rs | 5 +-- lib/ain-ocean/src/api/governance.rs | 4 +-- lib/ain-ocean/src/api/tokens.rs | 4 +-- src/ffi/ffiexports.h | 1 + src/init.cpp | 4 ++- 7 files changed, 30 insertions(+), 48 deletions(-) diff --git a/.github/workflows/tests-ocean.yml b/.github/workflows/tests-ocean.yml index ad01b0f43e9..87836b5873c 100644 --- a/.github/workflows/tests-ocean.yml +++ b/.github/workflows/tests-ocean.yml @@ -23,6 +23,8 @@ jobs: steps: - uses: actions/checkout@v4 + with: + ref: 'canonbrother/ocean-ci-testing' - run: git config --global --add safe.directory '*' - name: Populate environment @@ -48,35 +50,10 @@ jobs: name: defi-bins path: build/src/defid - docker-build: - runs-on: ubuntu-latest - needs: [build] - - steps: - - uses: actions/checkout@v4 - - - name: Populate environment - run: ./make.sh ci-export-vars - - - name: Download binaries - uses: actions/download-artifact@v3 - with: - name: defi-bins - path: ./build/ - - - name: Build docker - run: "docker build -t test-build-container -f ./contrib/dockerfiles/x86_64-pc-linux-gnu.dockerfile ." - - - name: Upload docker - uses: actions/upload-artifact@v3 - with: - name: defi-docker - path: . - test: name: Jellyfish Whale Api tests runs-on: ubuntu-latest - needs: [build, docker-build] + needs: [build] strategy: fail-fast: false @@ -84,18 +61,14 @@ jobs: - uses: actions/checkout@v4 with: repository: birthdayresearch/jellyfishsdk - ref: 'main' + # ref: 'main' + ref: 'canonbrother/whale-defid' # TODO(): remove before merge to master - name: Download binaries uses: actions/download-artifact@v3 with: name: defi-bins - - name: Download docker - uses: actions/download-artifact@v3 - with: - name: defi-docker - - name: Setup permissions run: | chmod uog+x "$(pwd)/defid" @@ -104,10 +77,15 @@ jobs: with: node-version: '18' - - name: Install dependencies - run: | - npm ci + - uses: actions/checkout@v4 + with: + path: defichain + ref: 'canonbrother/ocean-ci-testing' + + - name: Populate environment + run: cd defichain && ./make.sh ci-export-vars - name: Run tests run: | - DEFICHAIN_DOCKER_IMAGE=test-build-container DEFID="$(pwd)/defid" npm t apps/whale-api/src/module.api + npm ci + DEFID="$(pwd)/defid" npm run defid apps/whale-api/src/module.api/__defid__ diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index a1c18bad4fd..d4017fa8ff3 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -6,7 +6,7 @@ use bitcoin::BlockHash; use defichain_rpc::Client; use serde::{Deserialize, Deserializer}; -use super::response::{ApiPagedResponse, Response}; +use super::response::ApiPagedResponse; use crate::{ api_query::{PaginationQuery, Query}, error::ApiError, @@ -61,7 +61,7 @@ async fn list_blocks(Query(query): Query) -> Result) -> Result>> { +async fn get_block(Path(id): Path) -> Result> { let block = if let Some(id) = match id { HashOrHeight::Height(n) => SERVICES.block.by_height.get(&n)?, HashOrHeight::Id(id) => Some(id), @@ -71,7 +71,7 @@ async fn get_block(Path(id): Path) -> Result) -> String { @@ -80,10 +80,10 @@ async fn get_transactions(Path(hash): Path) -> String { // Get highest indexed block #[ocean_endpoint] -async fn get_highest() -> Result>> { +async fn get_highest() -> Result> { let block = SERVICES.block.by_height.get_highest()?; - Ok(Response::new(block)) + Ok(block) } pub fn router(state: Arc) -> Router { diff --git a/lib/ain-ocean/src/api/fee.rs b/lib/ain-ocean/src/api/fee.rs index 476f654e0b1..e7779d217eb 100644 --- a/lib/ain-ocean/src/api/fee.rs +++ b/lib/ain-ocean/src/api/fee.rs @@ -9,6 +9,7 @@ use super::response::Response; use crate::{api_query::Query, error::ApiError, Result}; #[derive(Deserialize, Default)] +#[serde(rename_all = "camelCase")] pub struct EstimateQuery { confirmation_target: i32, } @@ -19,13 +20,13 @@ async fn estimate_fee( confirmation_target, }): Query, Extension(client): Extension>, -) -> Result> { +) -> Result { let estimation: SmartFeeEstimation = client.call( "estimatesmartfee", &[confirmation_target.into(), "CONSERVATIVE".into()], )?; - Ok(Response::new(estimation.feerate.unwrap_or(0.00005000))) + Ok(estimation.feerate.unwrap_or(0.00005000)) } pub fn router(state: Arc) -> Router { diff --git a/lib/ain-ocean/src/api/governance.rs b/lib/ain-ocean/src/api/governance.rs index 6d7b4f979d7..7f50477c819 100644 --- a/lib/ain-ocean/src/api/governance.rs +++ b/lib/ain-ocean/src/api/governance.rs @@ -54,13 +54,13 @@ async fn list_gov_proposals( async fn get_gov_proposal( Path(proposal_id): Path, Extension(client): Extension>, -) -> Result> { +) -> Result { let txid: Txid = proposal_id .parse() .map_err(|_| OceanError::NotFound(NotFoundKind::Proposal))?; let proposal = client.get_gov_proposal(txid)?; - Ok(Response::new(proposal)) + Ok(proposal) } #[ocean_endpoint] diff --git a/lib/ain-ocean/src/api/tokens.rs b/lib/ain-ocean/src/api/tokens.rs index 7df0d7cd49d..ecb6b48b939 100644 --- a/lib/ain-ocean/src/api/tokens.rs +++ b/lib/ain-ocean/src/api/tokens.rs @@ -116,7 +116,7 @@ async fn list_tokens( async fn get_token( Path(id): Path, Extension(client): Extension>, -) -> Result>> { +) -> Result> { let mut v: TokenResult = client.call("gettoken", &[id.into()])?; let res = if let Some(token) = v.0.remove(&id) { @@ -125,7 +125,7 @@ async fn get_token( None }; - Ok(Response::new(res)) + Ok(res) } pub fn router(state: Arc) -> Router { diff --git a/src/ffi/ffiexports.h b/src/ffi/ffiexports.h index 52514f67b03..7572bfe1fca 100644 --- a/src/ffi/ffiexports.h +++ b/src/ffi/ffiexports.h @@ -30,6 +30,7 @@ static constexpr bool DEFAULT_ETH_DEBUG_TRACE_ENABLED = true; static constexpr bool DEFAULT_ETH_SUBSCRIPTION_ENABLED = true; static constexpr bool DEFAULT_OCEAN_ARCHIVE_ENABLED = false; +static constexpr uint32_t DEFAULT_OCEAN_ARCHIVE_PORT = 3002; struct Attributes { uint64_t blockGasTargetFactor; diff --git a/src/init.cpp b/src/init.cpp index 9aefc3cace5..c85eb6070be 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -669,6 +669,7 @@ void SetupServerArgs() gArgs.AddArg("-ethdebug", strprintf("Enable debug_* ETH RPCs (default: %b)", DEFAULT_ETH_DEBUG_ENABLED), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); gArgs.AddArg("-ethdebugtrace", strprintf("Enable debug_trace* ETH RPCs (default: %b)", DEFAULT_ETH_DEBUG_TRACE_ENABLED), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); gArgs.AddArg("-oceanarchive", strprintf("Enable ocean archive and REST server (default: %b)", DEFAULT_OCEAN_ARCHIVE_ENABLED), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); + gArgs.AddArg("-oceanarchiveport=", strprintf("Listen for ocean archive connections on (default: %u)", DEFAULT_OCEAN_ARCHIVE_PORT), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC); #if HAVE_DECL_DAEMON gArgs.AddArg("-daemon", "Run in the background as a daemon and accept commands", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -2407,7 +2408,8 @@ bool AppInitMain(InitInterfaces& interfaces) if (gArgs.GetBoolArg("-oceanarchive", DEFAULT_OCEAN_ARCHIVE_ENABLED)) { // for (auto it = ocean_endpoints.begin(); it != ocean_endpoints.end(); ++it) { // LogPrint(BCLog::HTTP, "Binding ocean server on endpoint %s\n", *it); - auto res = XResultStatusLogged(ain_rs_init_network_rest_ocean(result, "127.0.0.1:3002")) + auto port = gArgs.GetArg("-oceanarchiveport", DEFAULT_OCEAN_ARCHIVE_PORT); + auto res = XResultStatusLogged(ain_rs_init_network_rest_ocean(result, strprintf("127.0.0.1:%s", port))) if (!res) { // LogPrintf("Binding websocket server on endpoint %s failed.\n", *it); return false; From 45a3a89d2e5142e66d93e77885396aea816d386e Mon Sep 17 00:00:00 2001 From: canonbrother Date: Wed, 31 Jan 2024 17:05:42 +0800 Subject: [PATCH 039/185] update ocean ci target branch --- .github/workflows/tests-ocean.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests-ocean.yml b/.github/workflows/tests-ocean.yml index 87836b5873c..6f46822c403 100644 --- a/.github/workflows/tests-ocean.yml +++ b/.github/workflows/tests-ocean.yml @@ -24,7 +24,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: 'canonbrother/ocean-ci-testing' + ref: 'feature/ocean-archive' - run: git config --global --add safe.directory '*' - name: Populate environment @@ -80,7 +80,7 @@ jobs: - uses: actions/checkout@v4 with: path: defichain - ref: 'canonbrother/ocean-ci-testing' + ref: 'feature/ocean-archive' - name: Populate environment run: cd defichain && ./make.sh ci-export-vars From 2c24380792c6720f02b5f5a842c4fcdb5b0efe50 Mon Sep 17 00:00:00 2001 From: Nagaraj <144004792+nagarajm22@users.noreply.github.com> Date: Thu, 1 Feb 2024 12:06:28 +0000 Subject: [PATCH 040/185] WIP : Ocean Fixing transaction Indexing bugs (#2802) * updated trasnction id while saving vin and vout with invalidate method * fixed format * fixed transaction data type and updated index_transaction * fixed transaction structure for indexing trasnaction,vin and vout * fixed transaction id to tuple * Restore cpp fmt * Remove unwrap in check_if_evm_tx * Remove ffi exports of index_transaction_* * Remove transaction clone * Remove second iteration for total_vout_value * Index vout by TransactionVoutKey * Fix TransactionVout typing * Index vin by TransactionVinKey * Index from getblock 2 format * Cleanup --------- Co-authored-by: jouzo --- lib/Cargo.lock | 7 +- lib/Cargo.toml | 2 + lib/ain-db/Cargo.toml | 3 +- lib/ain-db/src/lib.rs | 10 +- lib/ain-ocean/Cargo.toml | 2 +- lib/ain-ocean/src/api/address.rs | 2 +- lib/ain-ocean/src/api/block.rs | 37 +++-- lib/ain-ocean/src/api/fee.rs | 10 +- lib/ain-ocean/src/api/governance.rs | 20 +-- lib/ain-ocean/src/api/loan.rs | 9 +- lib/ain-ocean/src/api/masternode.rs | 10 +- lib/ain-ocean/src/api/mod.rs | 29 ++-- lib/ain-ocean/src/api/oracle.rs | 2 +- lib/ain-ocean/src/api/poolpairs.rs | 6 +- lib/ain-ocean/src/api/prices.rs | 2 +- lib/ain-ocean/src/api/rawtx.rs | 2 +- lib/ain-ocean/src/api/stats.rs | 2 +- lib/ain-ocean/src/api/tokens.rs | 16 +-- lib/ain-ocean/src/api/transactions.rs | 14 +- lib/ain-ocean/src/error.rs | 3 +- lib/ain-ocean/src/indexer/auction.rs | 46 +++--- lib/ain-ocean/src/indexer/masternode.rs | 81 ++++++----- lib/ain-ocean/src/indexer/mod.rs | 125 ++++++++-------- lib/ain-ocean/src/indexer/oracle.rs | 27 ++-- lib/ain-ocean/src/indexer/pool.rs | 67 +++++---- lib/ain-ocean/src/indexer/transaction.rs | 136 +++++++++--------- lib/ain-ocean/src/indexer/tx_result.rs | 19 ++- lib/ain-ocean/src/lib.rs | 60 ++++---- lib/ain-ocean/src/model/block.rs | 25 ++-- lib/ain-ocean/src/model/masternode.rs | 12 +- lib/ain-ocean/src/model/transaction.rs | 12 +- lib/ain-ocean/src/model/transaction_vin.rs | 67 ++++++--- lib/ain-ocean/src/model/transaction_vout.rs | 15 +- .../src/repository/transaction_vin.rs | 3 +- .../src/repository/transaction_vout.rs | 5 +- lib/ain-ocean/src/storage/columns/block.rs | 16 ++- .../src/storage/columns/transaction_vin.rs | 3 +- .../src/storage/columns/transaction_vout.rs | 3 +- lib/ain-rs-exports/Cargo.toml | 1 + lib/ain-rs-exports/src/lib.rs | 23 +-- lib/ain-rs-exports/src/ocean.rs | 33 ++--- src/dfi/validation.cpp | 43 +----- src/init.cpp | 73 ++++------ 43 files changed, 552 insertions(+), 531 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 54e01604207..bdfe2dd9ad0 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -109,9 +109,9 @@ dependencies = [ name = "ain-db" version = "0.1.0" dependencies = [ - "ain-cpp-imports", "anyhow", "bincode", + "num_cpus", "rocksdb", "serde", ] @@ -273,6 +273,7 @@ dependencies = [ "anyhow", "cxx", "cxx-gen", + "defichain-rpc", "ethabi", "ethereum", "ethereum-types", @@ -1350,7 +1351,7 @@ dependencies = [ [[package]] name = "defichain-rpc" version = "0.18.0" -source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#fc9a999c32d9b7c081830221099cc9a65dc86080" +source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#261421ae27f89953015643e25943bd558c8432e9" dependencies = [ "defichain-rpc-json", "jsonrpc", @@ -1362,7 +1363,7 @@ dependencies = [ [[package]] name = "defichain-rpc-json" version = "0.18.0" -source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#fc9a999c32d9b7c081830221099cc9a65dc86080" +source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#261421ae27f89953015643e25943bd558c8432e9" dependencies = [ "bitcoin", "serde", diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 340905285b1..77e20409002 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -63,6 +63,7 @@ sha3 = "0.10" num = { version = "0.4", default-features = false, features = ["alloc"] } num-traits = "0.2" +num_cpus = "1.0" hex = "0.4" hex-literal = "0.4" @@ -121,6 +122,7 @@ substrate-bn = "0.6" dftx-rs = { git = "https://github.com/Jouzo/dftx-rs.git" } bitcoin = "0.31" cached = "0.46" +defichain-rpc = { version = "0.18.0", git = "https://github.com/Jouzo/rust-defichain-rpc.git" } ### Local crates ain-cpp-imports = { path = "./ain-cpp-imports" } diff --git a/lib/ain-db/Cargo.toml b/lib/ain-db/Cargo.toml index 8230f3971a8..b319eba6251 100644 --- a/lib/ain-db/Cargo.toml +++ b/lib/ain-db/Cargo.toml @@ -9,5 +9,6 @@ edition = "2021" serde.workspace = true bincode.workspace = true rocksdb.workspace = true -ain-cpp-imports.workspace = true anyhow.workspace = true +num_cpus.workspace = true + diff --git a/lib/ain-db/src/lib.rs b/lib/ain-db/src/lib.rs index 57d21cbbd9c..3bf3a0a4aef 100644 --- a/lib/ain-db/src/lib.rs +++ b/lib/ain-db/src/lib.rs @@ -21,8 +21,8 @@ fn get_db_options() -> Options { options.create_if_missing(true); options.create_missing_column_families(true); - let n = ain_cpp_imports::get_num_cores(); - options.increase_parallelism(n); + let n = num_cpus::get(); + options.increase_parallelism(n as i32); let mut env = rocksdb::Env::new().unwrap(); @@ -239,3 +239,9 @@ impl From for DBError { DBError::Bincode(e) } } + +impl From for DBError { + fn from(e: anyhow::Error) -> Self { + DBError::Custom(e) + } +} diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index 15ec86316d0..1e1424c328a 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -39,6 +39,6 @@ chrono = "0.4.31" cached.workspace = true lazy_static.workspace = true bincode.workspace = true -defichain-rpc = { version = "0.18.0", git = "https://github.com/Jouzo/rust-defichain-rpc.git" } +defichain-rpc.workspace = true jsonrpc = "0.14.1" serde_urlencoded = { version = "0.7" } diff --git a/lib/ain-ocean/src/api/address.rs b/lib/ain-ocean/src/api/address.rs index 2ec9a8b2684..296055c0116 100644 --- a/lib/ain-ocean/src/api/address.rs +++ b/lib/ain-ocean/src/api/address.rs @@ -57,7 +57,7 @@ async fn list_transaction_unspent(Path(Address { address }): Path
) -> S format!("List unspent transactions for address {}", address) } -pub fn router(state: Arc) -> Router { +pub fn router(services: Arc) -> Router { Router::new().nest( "/:address", Router::new() diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index d4017fa8ff3..93973f13c36 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -1,9 +1,8 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; -use axum::{extract::Path, routing::get, Router}; +use axum::{extract::Path, routing::get, Extension, Router}; use bitcoin::BlockHash; -use defichain_rpc::Client; use serde::{Deserialize, Deserializer}; use super::response::ApiPagedResponse; @@ -12,7 +11,7 @@ use crate::{ error::ApiError, model::Block, repository::RepositoryOps, - Result, SERVICES, + Result, Services, }; pub enum HashOrHeight { @@ -37,15 +36,18 @@ impl<'de> Deserialize<'de> for HashOrHeight { } #[ocean_endpoint] -async fn list_blocks(Query(query): Query) -> Result> { - let blocks = SERVICES +async fn list_blocks( + Query(query): Query, + Extension(services): Extension>, +) -> Result> { + let blocks = services .block .by_height .list(None)? .take(query.size) .map(|item| { let (_, id) = item?; - let b = SERVICES + let b = services .block .by_id .get(&id)? @@ -56,17 +58,20 @@ async fn list_blocks(Query(query): Query) -> Result>>()?; Ok(ApiPagedResponse::of(blocks, query.size, |block| { - block.clone().id + block.clone().hash })) } #[ocean_endpoint] -async fn get_block(Path(id): Path) -> Result> { +async fn get_block( + Path(id): Path, + Extension(services): Extension>, +) -> Result> { let block = if let Some(id) = match id { - HashOrHeight::Height(n) => SERVICES.block.by_height.get(&n)?, + HashOrHeight::Height(n) => services.block.by_height.get(&n)?, HashOrHeight::Id(id) => Some(id), } { - SERVICES.block.by_id.get(&id)? + services.block.by_id.get(&id)? } else { None }; @@ -74,22 +79,26 @@ async fn get_block(Path(id): Path) -> Result> { Ok(block) } -async fn get_transactions(Path(hash): Path) -> String { +async fn get_transactions( + Path(hash): Path, + Extension(services): Extension>, +) -> String { format!("Transactions for block with hash {}", hash) } // Get highest indexed block #[ocean_endpoint] -async fn get_highest() -> Result> { - let block = SERVICES.block.by_height.get_highest()?; +async fn get_highest(Extension(services): Extension>) -> Result> { + let block = services.block.by_height.get_highest()?; Ok(block) } -pub fn router(state: Arc) -> Router { +pub fn router(services: Arc) -> Router { Router::new() .route("/", get(list_blocks)) .route("/highest", get(get_highest)) .route("/:id", get(get_block)) .route("/:hash/transactions", get(get_transactions)) + .layer(Extension(services)) } diff --git a/lib/ain-ocean/src/api/fee.rs b/lib/ain-ocean/src/api/fee.rs index e7779d217eb..ab0a8f2c8d5 100644 --- a/lib/ain-ocean/src/api/fee.rs +++ b/lib/ain-ocean/src/api/fee.rs @@ -6,7 +6,7 @@ use defichain_rpc::{json::mining::SmartFeeEstimation, Client, RpcApi}; use serde::Deserialize; use super::response::Response; -use crate::{api_query::Query, error::ApiError, Result}; +use crate::{api_query::Query, error::ApiError, Result, Services}; #[derive(Deserialize, Default)] #[serde(rename_all = "camelCase")] @@ -19,9 +19,9 @@ async fn estimate_fee( Query(EstimateQuery { confirmation_target, }): Query, - Extension(client): Extension>, + Extension(services): Extension>, ) -> Result { - let estimation: SmartFeeEstimation = client.call( + let estimation: SmartFeeEstimation = services.client.call( "estimatesmartfee", &[confirmation_target.into(), "CONSERVATIVE".into()], )?; @@ -29,8 +29,8 @@ async fn estimate_fee( Ok(estimation.feerate.unwrap_or(0.00005000)) } -pub fn router(state: Arc) -> Router { +pub fn router(services: Arc) -> Router { Router::new() .route("/estimate", get(estimate_fee)) - .layer(Extension(state)) + .layer(Extension(services)) } diff --git a/lib/ain-ocean/src/api/governance.rs b/lib/ain-ocean/src/api/governance.rs index 7f50477c819..cd12ac23dca 100644 --- a/lib/ain-ocean/src/api/governance.rs +++ b/lib/ain-ocean/src/api/governance.rs @@ -3,14 +3,14 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; use axum::{extract::Path, routing::get, Extension, Router}; use bitcoin::Txid; -use defichain_rpc::{json::governance::*, Client, GovernanceRPC}; +use defichain_rpc::{json::governance::*, GovernanceRPC}; use serde::Deserialize; use super::response::{ApiPagedResponse, Response}; use crate::{ api_query::{PaginationQuery, Query}, error::{ApiError, NotFoundKind, OceanError}, - Result, + Result, Services, }; #[derive(Deserialize, Default)] @@ -27,7 +27,7 @@ pub struct GovernanceQuery { #[ocean_endpoint] async fn list_gov_proposals( Query(query): Query, - Extension(client): Extension>, + Extension(services): Extension>, ) -> Result> { let size = match query.all { Some(true) => 0, @@ -43,7 +43,7 @@ async fn list_gov_proposals( r#type: query.r#type, cycle: query.cycle, }; - let proposals = client.list_gov_proposals(Some(opts))?; + let proposals = services.client.list_gov_proposals(Some(opts))?; Ok(ApiPagedResponse::of(proposals, size, |proposal| { proposal.proposal_id.to_string() @@ -53,13 +53,13 @@ async fn list_gov_proposals( #[ocean_endpoint] async fn get_gov_proposal( Path(proposal_id): Path, - Extension(client): Extension>, + Extension(services): Extension>, ) -> Result { let txid: Txid = proposal_id .parse() .map_err(|_| OceanError::NotFound(NotFoundKind::Proposal))?; - let proposal = client.get_gov_proposal(txid)?; + let proposal = services.client.get_gov_proposal(txid)?; Ok(proposal) } @@ -67,7 +67,7 @@ async fn get_gov_proposal( async fn list_gov_proposal_votes( Path(proposal_id): Path, Query(query): Query, - Extension(client): Extension>, + Extension(services): Extension>, ) -> Result> { let proposal_id: Txid = proposal_id .parse() @@ -96,7 +96,7 @@ async fn list_gov_proposal_votes( aggregate: None, valid: None, }; - let votes = client.list_gov_proposal_votes(Some(opts))?; + let votes = services.client.list_gov_proposal_votes(Some(opts))?; let len = votes.len(); Ok(ApiPagedResponse::of(votes, size, |_| { if let Some(next) = start { @@ -107,10 +107,10 @@ async fn list_gov_proposal_votes( })) } -pub fn router(state: Arc) -> Router { +pub fn router(services: Arc) -> Router { Router::new() .route("/proposals", get(list_gov_proposals)) .route("/proposals/:id", get(get_gov_proposal)) .route("/proposals/:id/votes", get(list_gov_proposal_votes)) - .layer(Extension(state)) + .layer(Extension(services)) } diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index 96d883e57a2..0a3bd11538c 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -11,7 +11,7 @@ use log::debug; use crate::{ api_paged_response::ApiPagedResponse, api_query::PaginationQuery, - model::VaultAuctionBatchHistory, repository::RepositoryOps, Result, SERVICES, + model::VaultAuctionBatchHistory, repository::RepositoryOps, services, Result, }; async fn list_scheme() -> String { @@ -50,7 +50,6 @@ async fn list_vault_auction_history( Path((vault_id, height, batch_index)): Path<(Txid, u32, u32)>, Query(query): Query, ) -> Result>> { - println!("listvault auction history"); debug!( "Auction history for vault id {}, height {}, batch index {}", vault_id, height, batch_index @@ -75,7 +74,7 @@ async fn list_vault_auction_history( let size = if query.size > 0 { query.size } else { 20 }; - let auctions = SERVICES + let auctions = services .auction .by_height .list(Some((vault_id, batch_index, next.0, next.1)))? @@ -87,7 +86,7 @@ async fn list_vault_auction_history( .map(|item| { let (_, id) = item?; - let auction = SERVICES + let auction = services .auction .by_id .get(&id)? @@ -108,7 +107,7 @@ async fn list_auction() -> String { "List of auctions".to_string() } -pub fn router(state: Arc) -> Router { +pub fn router(services: Arc) -> Router { Router::new() .route("/schemes", get(list_scheme)) .route("/schemes/:id", get(get_scheme)) diff --git a/lib/ain-ocean/src/api/masternode.rs b/lib/ain-ocean/src/api/masternode.rs index f14f17f226b..f00994c5b72 100644 --- a/lib/ain-ocean/src/api/masternode.rs +++ b/lib/ain-ocean/src/api/masternode.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; use crate::{ api_paged_response::ApiPagedResponse, api_query::PaginationQuery, model::Masternode, - repository::RepositoryOps, Result, SERVICES, + repository::RepositoryOps, services, Result, }; #[derive(Serialize, Deserialize, Debug, Default, Clone)] @@ -108,14 +108,14 @@ async fn list_masternodes( }) .transpose()?; - let masternodes = SERVICES + let masternodes = services .masternode .by_height .list(next)? .take(query.size) .map(|item| { let (_, id) = item?; - let mn = SERVICES + let mn = services .masternode .by_id .get(&id)? @@ -133,7 +133,7 @@ async fn list_masternodes( } async fn get_masternode(Path(masternode_id): Path) -> Result>> { - let mn = SERVICES + let mn = services .masternode .by_id .get(&masternode_id)? @@ -142,7 +142,7 @@ async fn get_masternode(Path(masternode_id): Path) -> Result) -> Router { +pub fn router(services: Arc) -> Router { Router::new() .route("/", get(list_masternodes)) .route("/:id", get(get_masternode)) diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index ceb13f579ae..1aff6f7f50b 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -54,22 +54,21 @@ pub fn ocean_router() -> Result { return Ok(Router::new().route("/*path", get(ocean_not_activated))); } - let client = &SERVICES.client; - println!("client : {:?}", client); + let services = &SERVICES; Ok(Router::new() - // .nest("/address", address::router(Arc::clone(client))) - .nest("/governance", governance::router(Arc::clone(client))) - // .nest("/loans", loan::router(Arc::clone(client))) - .nest("/fee", fee::router(Arc::clone(client))) - // .nest("/masternodes", masternode::router(Arc::clone(client))) - // .nest("/oracles", oracle::router(Arc::clone(client))) - // .nest("/poolpairs", poolpairs::router(Arc::clone(client))) - // .nest("/prices", prices::router(Arc::clone(client))) - // .nest("/rawtx", rawtx::router(Arc::clone(client))) - // .nest("/stats", stats::router(Arc::clone(client))) - .nest("/tokens", tokens::router(Arc::clone(client))) - // .nest("/transactions", transactions::router(Arc::clone(client))) - .nest("/blocks", block::router(Arc::clone(client))) + // .nest("/address", address::router(Arc::clone(services))) + .nest("/governance", governance::router(Arc::clone(services))) + // .nest("/loans", loan::router(Arc::clone(services))) + .nest("/fee", fee::router(Arc::clone(services))) + // .nest("/masternodes", masternode::router(Arc::clone(services))) + // .nest("/oracles", oracle::router(Arc::clone(services))) + // .nest("/poolpairs", poolpairs::router(Arc::clone(services))) + // .nest("/prices", prices::router(Arc::clone(services))) + // .nest("/rawtx", rawtx::router(Arc::clone(services))) + // .nest("/stats", stats::router(Arc::clone(services))) + .nest("/tokens", tokens::router(Arc::clone(services))) + // .nest("/transactions", transactions::router(Arc::clone(services))) + .nest("/blocks", block::router(Arc::clone(services))) .fallback(not_found)) } diff --git a/lib/ain-ocean/src/api/oracle.rs b/lib/ain-ocean/src/api/oracle.rs index 683bbd242dd..902d221314f 100644 --- a/lib/ain-ocean/src/api/oracle.rs +++ b/lib/ain-ocean/src/api/oracle.rs @@ -15,7 +15,7 @@ async fn get_oracle_by_address(Path(address): Path) -> String { format!("Oracle details for address {}", address) } -pub fn router(state: Arc) -> Router { +pub fn router(services: Arc) -> Router { Router::new() .route("/", get(list_oracles)) .route("/:oracleId/:key/feed", get(get_price_feed)) diff --git a/lib/ain-ocean/src/api/poolpairs.rs b/lib/ain-ocean/src/api/poolpairs.rs index d4064cbe2bb..be0e514921c 100644 --- a/lib/ain-ocean/src/api/poolpairs.rs +++ b/lib/ain-ocean/src/api/poolpairs.rs @@ -14,7 +14,7 @@ use crate::{ api_query::PaginationQuery, model::{BlockContext, PoolSwap}, repository::RepositoryOps, - Result, SERVICES, + services, Result, }; #[derive(Deserialize)] @@ -134,7 +134,7 @@ async fn list_pool_swaps( 20 }; - let swaps = SERVICES + let swaps = services .pool .by_id .list(Some((id, next.0, next.1)))? @@ -195,7 +195,7 @@ async fn list_dex_prices(Query(DexPrices { denomination }): Query) -> format!("List of DEX prices with denomination {:?}", denomination) } -pub fn router(state: Arc) -> Router { +pub fn router(services: Arc) -> Router { Router::new() .route("/", get(list_poolpairs)) .route("/:id", get(get_poolpair)) diff --git a/lib/ain-ocean/src/api/prices.rs b/lib/ain-ocean/src/api/prices.rs index 5e394768646..4739886898f 100644 --- a/lib/ain-ocean/src/api/prices.rs +++ b/lib/ain-ocean/src/api/prices.rs @@ -41,7 +41,7 @@ async fn get_oracles(Path(PriceKey { key }): Path) -> String { format!("Oracles for price with key {}", key) } -pub fn router(state: Arc) -> Router { +pub fn router(services: Arc) -> Router { Router::new() .route("/", get(list_prices)) .route("/:key", get(get_price)) diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index 6830d4d0cd1..954afd7f398 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -19,7 +19,7 @@ async fn get_rawtx(Path(txid): Path) -> String { format!("Details of raw transaction with txid {}", txid) } -pub fn router(state: Arc) -> Router { +pub fn router(services: Arc) -> Router { Router::new() .route("/send", post(send_rawtx)) .route("/test", get(test_rawtx)) diff --git a/lib/ain-ocean/src/api/stats.rs b/lib/ain-ocean/src/api/stats.rs index 89f16b2ec48..e7c8194e116 100644 --- a/lib/ain-ocean/src/api/stats.rs +++ b/lib/ain-ocean/src/api/stats.rs @@ -19,7 +19,7 @@ async fn get_burn() -> String { "Burn stats".to_string() } -pub fn router(state: Arc) -> Router { +pub fn router(services: Arc) -> Router { Router::new() .route("/", get(get_stats)) .route("/rewards/distribution", get(get_reward_distribution)) diff --git a/lib/ain-ocean/src/api/tokens.rs b/lib/ain-ocean/src/api/tokens.rs index ecb6b48b939..e423a9c84ec 100644 --- a/lib/ain-ocean/src/api/tokens.rs +++ b/lib/ain-ocean/src/api/tokens.rs @@ -4,7 +4,7 @@ use ain_macros::ocean_endpoint; use axum::{extract::Path, routing::get, Extension, Router}; use defichain_rpc::{ json::token::{TokenInfo, TokenResult}, - Client, RpcApi, + RpcApi, }; use serde::Serialize; use serde_json::json; @@ -16,7 +16,7 @@ use super::{ use crate::{ api_query::{PaginationQuery, Query}, error::ApiError, - Result, + Result, Services, }; #[derive(Serialize, Debug, Clone, Default)] @@ -90,9 +90,9 @@ impl TokenData { #[ocean_endpoint] async fn list_tokens( Query(query): Query, - Extension(client): Extension>, + Extension(services): Extension>, ) -> Result> { - let tokens: TokenResult = client.call( + let tokens: TokenResult = services.client.call( "listtokens", &[ json!({ @@ -115,9 +115,9 @@ async fn list_tokens( #[ocean_endpoint] async fn get_token( Path(id): Path, - Extension(client): Extension>, + Extension(services): Extension>, ) -> Result> { - let mut v: TokenResult = client.call("gettoken", &[id.into()])?; + let mut v: TokenResult = services.client.call("gettoken", &[id.into()])?; let res = if let Some(token) = v.0.remove(&id) { Some(TokenData::from_with_id(id, token)) @@ -128,9 +128,9 @@ async fn get_token( Ok(res) } -pub fn router(state: Arc) -> Router { +pub fn router(services: Arc) -> Router { Router::new() .route("/", get(list_tokens)) .route("/:id", get(get_token)) - .layer(Extension(state)) + .layer(Extension(services)) } diff --git a/lib/ain-ocean/src/api/transactions.rs b/lib/ain-ocean/src/api/transactions.rs index ef2784ea890..2380d963740 100644 --- a/lib/ain-ocean/src/api/transactions.rs +++ b/lib/ain-ocean/src/api/transactions.rs @@ -11,7 +11,7 @@ use crate::{ api_query::PaginationQuery, model::{Transaction, TransactionVin, TransactionVout}, repository::RepositoryOps, - Result, SERVICES, + services, Result, }; #[derive(Deserialize)] @@ -23,21 +23,21 @@ async fn get_transaction( Path(TransactionId { id }): Path, ) -> Result>> { format!("Details of transaction with id {}", id); - let transactions = SERVICES.transaction.by_id.get(&id)?; + let transactions = services.transaction.by_id.get(&id)?; Ok(Json(transactions)) } async fn get_vins( Query(query): Query, ) -> Result>> { - let transaction_list = SERVICES + let transaction_list = services .transaction .vin_by_id .list(None)? .take(query.size) .map(|item| { let (txid, id) = item?; - let b = SERVICES + let b = services .transaction .vin_by_id .get(&txid)? @@ -58,14 +58,14 @@ async fn get_vins( async fn get_vouts( Query(query): Query, ) -> Result>> { - let transaction_list = SERVICES + let transaction_list = services .transaction .vout_by_id .list(None)? .take(query.size) .map(|item| { let (txid, id) = item?; - let b = SERVICES + let b = services .transaction .vout_by_id .get(&txid)? @@ -82,7 +82,7 @@ async fn get_vouts( ))) } -pub fn router(state: Arc) -> Router { +pub fn router(services: Arc) -> Router { Router::new() .route("/:id", get(get_transaction)) .route("/:id/vins", get(get_vins)) diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index aaf5053ce23..44fcb2c80e7 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -8,6 +8,7 @@ use axum::{ Json, }; use bitcoin::hex::HexToArrayError; +use log::debug; use serde::Serialize; use thiserror::Error; @@ -104,7 +105,7 @@ impl OceanError { pub fn into_code_and_message(self) -> (StatusCode, String) { let (code, reason) = match self { OceanError::RpcError(defichain_rpc::Error::JsonRpc(jsonrpc::error::Error::Rpc(e))) => { - println!("e : {:?}", e); + debug!("e : {:?}", e); (StatusCode::NOT_FOUND, format!("{}", e.message)) } diff --git a/lib/ain-ocean/src/indexer/auction.rs b/lib/ain-ocean/src/indexer/auction.rs index c6d50122db7..2c460620147 100644 --- a/lib/ain-ocean/src/indexer/auction.rs +++ b/lib/ain-ocean/src/indexer/auction.rs @@ -1,48 +1,52 @@ -use dftx_rs::{vault::PlaceAuctionBid, Transaction}; +use std::sync::Arc; + +use dftx_rs::vault::PlaceAuctionBid; use log::debug; -use super::BlockContext; +use super::Context; use crate::{ indexer::{Index, Result}, model::VaultAuctionBatchHistory, repository::RepositoryOps, - SERVICES, + Services, }; impl Index for PlaceAuctionBid { - fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[PlaceAuctionBid] Indexing..."); let auction = VaultAuctionBatchHistory { - id: format!("{}-{}-{}", self.vault_id, self.index, tx.txid()), + id: format!("{}-{}-{}", self.vault_id, self.index, ctx.tx.txid), key: format!("{}-{}", self.vault_id, self.index), - sort: format!("{}-{}", ctx.height, idx), + sort: format!("{}-{}", ctx.block.height, ctx.tx_idx), vault_id: self.vault_id, - index: idx, + index: ctx.tx_idx, from: self.from.clone(), amount: self.token_amount.amount, token_id: self.token_amount.token.0, - block: ctx.clone(), + block: ctx.block.clone(), }; debug!("auction : {:?}", auction); - let key = (self.vault_id, self.index, tx.txid()); - SERVICES.auction.by_id.put(&key, &auction)?; - SERVICES - .auction - .by_height - .put(&(self.vault_id, self.index, ctx.height, idx), &key) + let key = (self.vault_id, self.index, ctx.tx.txid); + services.auction.by_id.put(&key, &auction)?; + services.auction.by_height.put( + &(self.vault_id, self.index, ctx.block.height, ctx.tx_idx), + &key, + ) } - fn invalidate(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn invalidate(&self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[PlaceAuctionBid] Invalidating..."); - SERVICES + services .auction .by_id - .delete(&(self.vault_id, self.index, tx.txid()))?; - SERVICES - .auction - .by_height - .delete(&(self.vault_id, self.index, ctx.height, idx)) + .delete(&(self.vault_id, self.index, ctx.tx.txid))?; + services.auction.by_height.delete(&( + self.vault_id, + self.index, + ctx.block.height, + ctx.tx_idx, + )) } } diff --git a/lib/ain-ocean/src/indexer/masternode.rs b/lib/ain-ocean/src/indexer/masternode.rs index 23bb114df13..eaf02bc947d 100644 --- a/lib/ain-ocean/src/indexer/masternode.rs +++ b/lib/ain-ocean/src/indexer/masternode.rs @@ -1,13 +1,15 @@ +use std::sync::Arc; + use bitcoin::{hashes::Hash, PubkeyHash, ScriptBuf, WPubkeyHash}; -use dftx_rs::{masternode::*, Transaction}; +use dftx_rs::masternode::*; use log::debug; -use super::BlockContext; +use super::Context; use crate::{ indexer::{Index, Result}, model::{HistoryItem, Masternode}, repository::RepositoryOps, - SERVICES, + Services, }; fn get_operator_script(hash: &PubkeyHash, r#type: u8) -> Result { @@ -21,40 +23,50 @@ fn get_operator_script(hash: &PubkeyHash, r#type: u8) -> Result { } impl Index for CreateMasternode { - fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[CreateMasternode] Indexing..."); - let txid = tx.txid(); + let txid = ctx.tx.txid; + let Some(ref addresses) = ctx.tx.vout[1].script_pub_key.addresses else { + return Err("Missing owner address".into()); + }; let masternode = Masternode { id: txid, - sort: format!("{}-{}", ctx.height, idx), - owner_address: tx.output[1].script_pubkey.clone(), - operator_address: get_operator_script(&self.operator_pub_key_hash, self.operator_type)?, - creation_height: ctx.height, + sort: format!("{}-{}", ctx.block.height, ctx.tx_idx), + owner_address: addresses[0].clone(), + operator_address: get_operator_script(&self.operator_pub_key_hash, self.operator_type)? + .to_hex_string(), + creation_height: ctx.block.height, resign_height: None, resign_tx: None, minted_blocks: 0, timelock: self.timelock.0.unwrap_or_default(), - block: ctx.clone(), - collateral: tx.output[1].value.to_string(), + block: ctx.block.clone(), + collateral: ctx.tx.vout[1].value, history: Vec::new(), }; - SERVICES.masternode.by_id.put(&txid, &masternode)?; - SERVICES.masternode.by_height.put(&(ctx.height, idx), &txid) + services.masternode.by_id.put(&txid, &masternode)?; + services + .masternode + .by_height + .put(&(ctx.block.height, ctx.tx_idx), &txid) } - fn invalidate(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn invalidate(&self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[CreateMasternode] Invalidating..."); - SERVICES.masternode.by_id.delete(&tx.txid())?; - SERVICES.masternode.by_height.delete(&(ctx.height, idx)) + services.masternode.by_id.delete(&ctx.tx.txid)?; + services + .masternode + .by_height + .delete(&(ctx.block.height, ctx.tx_idx)) } } impl Index for UpdateMasternode { - fn index(&self, _ctx: &BlockContext, tx: Transaction, _idx: usize) -> Result<()> { + fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[UpdateMasternode] Indexing..."); - if let Some(mut mn) = SERVICES.masternode.by_id.get(&self.node_id)? { + if let Some(mut mn) = services.masternode.by_id.get(&self.node_id)? { mn.history.push(HistoryItem { owner_address: mn.owner_address.clone(), operator_address: mn.operator_address.clone(), @@ -63,44 +75,49 @@ impl Index for UpdateMasternode { for update in self.updates.as_ref() { debug!("update : {:?}", update); match update.r#type { - 0x1 => mn.owner_address = tx.output[1].script_pubkey.clone(), + 0x1 => { + if let Some(ref addresses) = ctx.tx.vout[1].script_pub_key.addresses { + mn.owner_address = addresses[0].clone() + } + } 0x2 => { if let Some(hash) = update.address.address_pub_key_hash { - mn.operator_address = get_operator_script(&hash, update.address.r#type)? + mn.operator_address = + get_operator_script(&hash, update.address.r#type)?.to_hex_string() } } _ => (), } } - SERVICES.masternode.by_id.put(&self.node_id, &mn)?; + services.masternode.by_id.put(&self.node_id, &mn)?; } Ok(()) } - fn invalidate(&self, _ctx: &BlockContext, _tx: Transaction, _idx: usize) -> Result<()> { + fn invalidate(&self, services: &Arc, _ctx: &Context) -> Result<()> { debug!("[UpdateMasternode] Invalidating..."); - if let Some(mut mn) = SERVICES.masternode.by_id.get(&self.node_id)? { + if let Some(mut mn) = services.masternode.by_id.get(&self.node_id)? { if let Some(history_item) = mn.history.pop() { mn.owner_address = history_item.owner_address; mn.operator_address = history_item.operator_address; } - SERVICES.masternode.by_id.put(&self.node_id, &mn)?; + services.masternode.by_id.put(&self.node_id, &mn)?; } Ok(()) } } impl Index for ResignMasternode { - fn index(&self, ctx: &BlockContext, tx: Transaction, _idx: usize) -> Result<()> { + fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[ResignMasternode] Indexing..."); - if let Some(mn) = SERVICES.masternode.by_id.get(&self.node_id)? { - SERVICES.masternode.by_id.put( + if let Some(mn) = services.masternode.by_id.get(&self.node_id)? { + services.masternode.by_id.put( &self.node_id, &Masternode { - resign_height: Some(ctx.height), - resign_tx: Some(tx.txid()), + resign_height: Some(ctx.block.height), + resign_tx: Some(ctx.tx.txid), ..mn }, )?; @@ -108,10 +125,10 @@ impl Index for ResignMasternode { Ok(()) } - fn invalidate(&self, _ctx: &BlockContext, _tx: Transaction, _idx: usize) -> Result<()> { + fn invalidate(&self, services: &Arc, _ctx: &Context) -> Result<()> { debug!("[ResignMasternode] Invalidating..."); - if let Some(mn) = SERVICES.masternode.by_id.get(&self.node_id)? { - SERVICES.masternode.by_id.put( + if let Some(mn) = services.masternode.by_id.get(&self.node_id)? { + services.masternode.by_id.put( &self.node_id, &Masternode { resign_height: None, diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 40997243b54..f687fbccd7f 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -5,83 +5,82 @@ mod pool; pub mod transaction; pub mod tx_result; -use std::time::Instant; +use std::{sync::Arc, time::Instant}; -use dftx_rs::{deserialize, Block, DfTx, Transaction}; +use defichain_rpc::json::blockchain::{Block, Transaction}; +use dftx_rs::{deserialize, DfTx}; use log::debug; use crate::{ + index_transaction, model::{Block as BlockMapper, BlockContext}, repository::RepositoryOps, - Result, SERVICES, + Result, Services, }; pub(crate) trait Index { - fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()>; - fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()>; + fn index(&self, services: &Arc, ctx: &Context) -> Result<()>; + + fn invalidate(&self, services: &Arc, ctx: &Context) -> Result<()>; } -pub struct BlockV2Info { - pub height: u32, - pub difficulty: u32, - pub version: i32, - pub median_time: i64, - pub minter_block_count: u64, - pub size: usize, - pub size_stripped: usize, - pub weight: i64, - pub stake_modifier: String, - pub minter: String, - pub masternode: String, +pub struct Context { + block: BlockContext, + tx: Transaction, + tx_idx: usize, } fn log_elapsed(previous: Instant, msg: &str) { let now = Instant::now(); - println!("{} in {} ms", msg, now.duration_since(previous).as_millis()); + debug!("{} in {} ms", msg, now.duration_since(previous).as_millis()); } -pub fn index_block(encoded_block: String, info: &BlockV2Info) -> Result<()> { +pub fn index_block(services: &Arc, block: Block) -> Result<()> { debug!("[index_block] Indexing block..."); let start = Instant::now(); - let hex = hex::decode(&encoded_block)?; - debug!("got hex"); - let block = deserialize::(&hex)?; - debug!("got block"); - let block_hash = block.block_hash(); - let ctx = BlockContext { - height: info.height, + let block_hash = block.hash; + let block_ctx = BlockContext { + height: block.height, hash: block_hash, - time: 0, // TODO - median_time: 0, // TODO + time: block.time, + median_time: block.mediantime, }; + let block_mapper = BlockMapper { - id: block_hash.to_string(), - hash: block_hash.to_string(), - previous_hash: block.header.prev_blockhash.to_string(), - height: info.height, - version: info.version, - time: block.header.time, - median_time: info.median_time, - transaction_count: block.txdata.len(), - difficulty: info.difficulty, - masternode: info.masternode.to_owned(), - minter: info.minter.to_owned(), - minter_block_count: info.minter_block_count, - stake_modifier: info.stake_modifier.to_owned(), - merkleroot: block.header.merkle_root.to_string(), - size: info.size, - size_stripped: info.size_stripped, - weight: info.weight, + hash: block_hash, + previous_hash: block.previousblockhash, + height: block.height, + version: block.version, + time: block.time, + median_time: block.mediantime, + transaction_count: block.tx.len(), + difficulty: block.difficulty, + masternode: block.masternode, + minter: block.minter, + minter_block_count: block.minted_blocks, + stake_modifier: block.stake_modifier.to_owned(), + merkleroot: block.merkleroot, + size: block.size, + size_stripped: block.strippedsize, + weight: block.weight, }; - SERVICES.block.raw.put(&ctx.hash, &encoded_block)?; - SERVICES.block.by_id.put(&ctx.hash, &block_mapper)?; - SERVICES.block.by_height.put(&ctx.height, &block_hash)?; + // services.block.raw.put(&ctx.hash, &encoded_block)?; TODO + services.block.by_id.put(&block_ctx.hash, &block_mapper)?; + services + .block + .by_height + .put(&block_ctx.height, &block_hash)?; - for (idx, tx) in block.txdata.into_iter().enumerate() { + for (tx_idx, tx) in block.tx.into_iter().enumerate() { let start = Instant::now(); - let bytes = tx.output[0].script_pubkey.as_bytes(); + let ctx = Context { + block: block_ctx.clone(), + tx, + tx_idx, + }; + let bytes = ctx.tx.vout[0].script_pub_key.hex.as_bytes(); if bytes.len() > 2 && bytes[0] == 0x6a && bytes[1] <= 0x4e { let offset = 1 + match bytes[1] { 0x4c => 2, @@ -93,21 +92,25 @@ pub fn index_block(encoded_block: String, info: &BlockV2Info) -> Result<()> { let raw_tx = &bytes[offset..]; let dftx = deserialize::(raw_tx)?; debug!("dftx : {:?}", dftx); + match &dftx { - DfTx::CreateMasternode(data) => data.index(&ctx, tx, idx)?, - DfTx::UpdateMasternode(data) => data.index(&ctx, tx, idx)?, - DfTx::ResignMasternode(data) => data.index(&ctx, tx, idx)?, - // DfTx::AppointOracle(data) => data.index(&ctx, tx, idx)?, - // DfTx::RemoveOracle(data) => data.index(&ctx, tx, idx)?, - // DfTx::UpdateOracle(data) => data.index(&ctx, tx, idx)?, - // DfTx::SetOracleData(data) => data.index(&ctx, tx, idx)?, - DfTx::PoolSwap(data) => data.index(&ctx, tx, idx)?, - DfTx::CompositeSwap(data) => data.index(&ctx, tx, idx)?, - DfTx::PlaceAuctionBid(data) => data.index(&ctx, tx, idx)?, + DfTx::CreateMasternode(data) => data.index(services, &ctx)?, + DfTx::UpdateMasternode(data) => data.index(services, &ctx)?, + DfTx::ResignMasternode(data) => data.index(services, &ctx)?, + // DfTx::AppointOracle(data) => data.index(services,&ctx)?, + // DfTx::RemoveOracle(data) => data.index(services,&ctx)?, + // DfTx::UpdateOracle(data) => data.index(services,&ctx)?, + // DfTx::SetOracleData(data) => data.index(services,&ctx)?, + DfTx::PoolSwap(data) => data.index(services, &ctx)?, + DfTx::CompositeSwap(data) => data.index(services, &ctx)?, + DfTx::PlaceAuctionBid(data) => data.index(services, &ctx)?, + _ => (), } log_elapsed(start, &format!("Indexed tx {:?}", dftx)); } + + index_transaction(services, ctx)?; } log_elapsed(start, "Indexed block"); @@ -115,6 +118,6 @@ pub fn index_block(encoded_block: String, info: &BlockV2Info) -> Result<()> { Ok(()) } -pub fn invalidate_block(block: String, info: &BlockV2Info) -> Result<()> { +pub fn invalidate_block(block: Block) -> Result<()> { Ok(()) } diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index 32f2465e157..48b25311060 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -1,44 +1,49 @@ -use dftx_rs::{oracles::*, Transaction}; +use std::sync::Arc; -use super::BlockContext; -use crate::indexer::{Index, Result}; +use dftx_rs::oracles::*; + +use super::Context; +use crate::{ + indexer::{Index, Result}, + Services, +}; impl Index for AppointOracle { - fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { todo!() } - fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { todo!() } } impl Index for RemoveOracle { - fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { todo!() } - fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { todo!() } } impl Index for UpdateOracle { - fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { todo!() } - fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { todo!() } } impl Index for SetOracleData { - fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { todo!() } - fn invalidate(&self, context: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { todo!() } } diff --git a/lib/ain-ocean/src/indexer/pool.rs b/lib/ain-ocean/src/indexer/pool.rs index 6e134ff0c1b..8f933e73fe2 100644 --- a/lib/ain-ocean/src/indexer/pool.rs +++ b/lib/ain-ocean/src/indexer/pool.rs @@ -1,27 +1,31 @@ -use dftx_rs::{pool::*, Transaction}; +use std::sync::Arc; + +use dftx_rs::pool::*; use log::debug; +use super::Context; use crate::{ indexer::{tx_result, Index, Result}, - model::{self, BlockContext, PoolSwapResult, TxResult}, + model::{self, PoolSwapResult, TxResult}, repository::RepositoryOps, - SERVICES, + Services, }; impl Index for PoolSwap { - fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[Poolswap] Indexing..."); - let txid = tx.txid(); + let txid = ctx.tx.txid; + let idx = ctx.tx_idx; let Some(TxResult::PoolSwap(PoolSwapResult { to_amount, pool_id })) = - SERVICES.result.get(&txid)? + services.result.get(&txid)? else { - println!("Missing swap result for {}", tx.txid().to_string()); + debug!("Missing swap result for {}", ctx.tx.txid.to_string()); return Err("Missing swap result".into()); }; let swap = model::PoolSwap { id: format!("{}-{}", pool_id, txid), - sort: format!("{}-{}", ctx.height, idx), + sort: format!("{}-{}", ctx.block.height, idx), txid: txid, txno: idx, from_amount: self.from_amount, @@ -31,34 +35,40 @@ impl Index for PoolSwap { pool_id, from: self.from_script.clone(), to: self.to_script.clone(), - block: ctx.clone(), + block: ctx.block.clone(), }; debug!("swap : {:?}", swap); - SERVICES.pool.by_id.put(&(pool_id, ctx.height, idx), &swap) + services + .pool + .by_id + .put(&(pool_id, ctx.block.height, idx), &swap) } - fn invalidate(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { - let txid = tx.txid(); + fn invalidate(&self, services: &Arc, ctx: &Context) -> Result<()> { + let txid = ctx.tx.txid; let Some(TxResult::PoolSwap(PoolSwapResult { pool_id, .. })) = - SERVICES.result.get(&txid)? + services.result.get(&txid)? else { return Err("Missing swap result".into()); }; - SERVICES.pool.by_id.delete(&(pool_id, ctx.height, idx))?; - tx_result::invalidate(&txid) + services + .pool + .by_id + .delete(&(pool_id, ctx.block.height, ctx.tx_idx))?; + tx_result::invalidate(services, &txid) } } impl Index for CompositeSwap { - fn index(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[CompositeSwap] Indexing..."); - let txid = tx.txid(); + let txid = ctx.tx.txid; let Some(TxResult::PoolSwap(PoolSwapResult { to_amount, .. })) = - SERVICES.result.get(&txid)? + services.result.get(&txid)? else { - println!("Missing swap result for {}", txid.to_string()); + debug!("Missing swap result for {}", txid.to_string()); return Err("Missing swap result".into()); }; @@ -66,9 +76,9 @@ impl Index for CompositeSwap { let pool_id = pool.id.0 as u32; let swap = model::PoolSwap { id: format!("{}-{}", pool_id, txid), - sort: format!("{}-{}", ctx.height, idx), + sort: format!("{}-{}", ctx.block.height, ctx.tx_idx), txid: txid, - txno: idx, + txno: ctx.tx_idx, from_amount: self.pool_swap.from_amount, from_token_id: self.pool_swap.from_token_id.0, to_token_id: self.pool_swap.to_token_id.0, @@ -76,23 +86,26 @@ impl Index for CompositeSwap { pool_id, from: self.pool_swap.from_script.clone(), to: self.pool_swap.to_script.clone(), - block: ctx.clone(), + block: ctx.block.clone(), }; debug!("swap : {:?}", swap); - SERVICES + services .pool .by_id - .put(&(pool_id, ctx.height, idx), &swap)?; + .put(&(pool_id, ctx.block.height, ctx.tx_idx), &swap)?; } Ok(()) } - fn invalidate(&self, ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { + fn invalidate(&self, services: &Arc, ctx: &Context) -> Result<()> { for pool in self.pools.as_ref() { let pool_id = pool.id.0 as u32; - SERVICES.pool.by_id.delete(&(pool_id, ctx.height, idx))?; + services + .pool + .by_id + .delete(&(pool_id, ctx.block.height, ctx.tx_idx))?; } - tx_result::invalidate(&tx.txid()) + tx_result::invalidate(services, &ctx.tx.txid) } } diff --git a/lib/ain-ocean/src/indexer/transaction.rs b/lib/ain-ocean/src/indexer/transaction.rs index ec76c414acd..1bf5270418e 100644 --- a/lib/ain-ocean/src/indexer/transaction.rs +++ b/lib/ain-ocean/src/indexer/transaction.rs @@ -1,91 +1,91 @@ -use bitcoin::{blockdata::locktime::absolute::LockTime, Txid}; -use dftx_rs::Transaction; +use std::sync::Arc; + +use bitcoin::{hashes::Hash, Txid}; +use defichain_rpc::json::blockchain::{Transaction, Vin}; use log::debug; -use super::BlockContext; +use super::Context; use crate::{ indexer::Result, model::{ - Transaction as TransactionMapper, TransactionVin, TransactionVinScript, TransactionVinVout, - TransactionVinVoutScript, TransactionVout, TransactionVoutScript, + Transaction as TransactionMapper, TransactionVin, TransactionVout, TransactionVoutScript, }, repository::RepositoryOps, - SERVICES, + Services, }; -pub fn index_transaction(ctx: &BlockContext, tx: Transaction, idx: usize) -> Result<()> { +pub fn index_transaction(services: &Arc, ctx: Context) -> Result<()> { debug!("[index_transaction] Indexing..."); - let tx_id = tx.txid(); - - let lock_time = match tx.lock_time { - LockTime::Blocks(value) => value.to_consensus_u32(), - LockTime::Seconds(value) => value.to_consensus_u32(), - }; - let total_vout_value = tx.output.iter().map(|output| output.value.to_sat()).sum(); + let idx = ctx.tx_idx; + let is_evm = check_if_evm_tx(&ctx.tx); - let trx = TransactionMapper { - id: tx_id, - order: idx, - block: ctx.clone(), - hash: ctx.hash, - version: tx.version.0, - size: tx.total_size(), - v_size: tx.vsize(), - weight: tx.weight().to_wu(), - total_vout_value, - lock_time: lock_time, - vin_count: tx.input.len(), - vout_count: tx.output.len(), - }; - // Index transaction - SERVICES.transaction.by_id.put(&tx_id, &trx)?; - // Indexing transaction vin - for (vin_idx, vin) in tx.input.iter().enumerate() { - let trx_vin = TransactionVin { - id: format!("{}-{}", tx_id, vin_idx), - txid: tx_id, - coinbase: vin.script_sig.to_string(), - vout: TransactionVinVout { - id: format!("{}-{}-vout", tx_id, vin_idx), - txid: tx_id, - n: vin.previous_output.vout as i32, - value: "0".to_string(), - token_id: 0, - script: TransactionVinVoutScript { - hex: vin.script_sig.to_string(), - }, - }, - script: TransactionVinScript { - hex: vin.script_sig.to_string(), - }, - tx_in_witness: vec![], - sequence: vin.sequence.to_string(), - }; + let txid = ctx.tx.txid; + let vin_count = ctx.tx.vin.len(); + let vout_count = ctx.tx.vout.len(); - SERVICES.transaction.vin_by_id.put(&tx_id, &trx_vin)?; - } + let mut total_vout_value = 0f64; + let mut vouts = Vec::with_capacity(vout_count); // Index transaction vout - for (vout_idx, vout) in tx.output.iter().enumerate() { - let trx_vout = TransactionVout { - id: format!("{}-{}", tx_id, vout_idx), - txid: tx_id.to_string(), - n: vout_idx as i32, - value: vout.value.to_string(), + for (vout_idx, vout) in ctx.tx.vout.into_iter().enumerate() { + let tx_vout = TransactionVout { + txid: txid, + n: vout_idx, + value: vout.value, token_id: 0, script: TransactionVoutScript { - hex: vout.script_pubkey.to_string(), - r#type: "pubkey".to_string(), + hex: vout.script_pub_key.hex, + r#type: vout.script_pub_key.r#type, }, }; - SERVICES.transaction.vout_by_id.put(&tx_id, &trx_vout)?; - // .put(&format!("{}-{}", tx_id, vout_idx), &trx_vout)?; //need + services + .transaction + .vout_by_id + .put(&(txid, vout_idx), &tx_vout)?; + + total_vout_value += vout.value; + vouts.push(tx_vout); + } + + // Indexing transaction vin + for vin in ctx.tx.vin.into_iter() { + if is_evm { + continue; + } + + let vin = TransactionVin::from_vin_and_txid(vin, txid, &vouts); + services.transaction.vin_by_id.put(&vin.id, &vin)?; } + let tx = TransactionMapper { + id: txid, + order: idx, + hash: ctx.tx.hash.clone(), + block: ctx.block.clone(), + version: ctx.tx.version, + size: ctx.tx.size, + v_size: ctx.tx.vsize, + weight: ctx.tx.weight, + total_vout_value, + lock_time: ctx.tx.locktime, + vin_count, + vout_count, + }; + // Index transaction + services.transaction.by_id.put(&txid, &tx)?; + Ok(()) } -pub fn invalidate_transaction(ctx: &BlockContext, tx: Txid, idx: usize) -> Result<()> { - debug!("[invalidate_transaction] Invalidating..."); - SERVICES.transaction.by_id.delete(&tx)?; - Ok(()) +fn check_if_evm_tx(txn: &Transaction) -> bool { + txn.vin.len() == 2 + && txn.vin.iter().all(|vin| match vin { + Vin::Coinbase(_) => true, + Vin::Standard(tx) => tx.txid == Txid::all_zeros(), + }) + && txn.vout.len() == 1 + && txn.vout[0] + .script_pub_key + .asm + .starts_with("OP_RETURN 4466547839") + && txn.vout[0].value == 0f64 } diff --git a/lib/ain-ocean/src/indexer/tx_result.rs b/lib/ain-ocean/src/indexer/tx_result.rs index 1f86843af52..2b3b3e5711f 100644 --- a/lib/ain-ocean/src/indexer/tx_result.rs +++ b/lib/ain-ocean/src/indexer/tx_result.rs @@ -1,15 +1,20 @@ +use std::sync::Arc; + use bitcoin::{hashes::Hash, Txid}; -use crate::{model::TxResult, repository::RepositoryOps, Result, SERVICES}; +use crate::{model::TxResult, repository::RepositoryOps, Result, Services}; -pub fn index(tx_type: u8, tx_hash: [u8; 32], result_ptr: usize) -> Result<()> { +pub fn index( + services: &Arc, + tx_type: u8, + tx_hash: [u8; 32], + result_ptr: usize, +) -> Result<()> { let txid = Txid::from_byte_array(tx_hash); let result = TxResult::from((tx_type, result_ptr)); - println!("txid : {:?}", txid); - println!("result : {:?}", result); - SERVICES.result.put(&txid, &result) + services.result.put(&txid, &result) } -pub fn invalidate(txid: &Txid) -> Result<()> { - SERVICES.result.delete(txid) +pub fn invalidate(services: &Arc, txid: &Txid) -> Result<()> { + services.result.delete(txid) } diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 46c8f3067e5..dde891a6527 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -6,11 +6,7 @@ use std::{path::PathBuf, sync::Arc}; pub use api::ocean_router; use error::OceanError; -pub use indexer::{ - index_block, invalidate_block, - transaction::{index_transaction, invalidate_transaction}, - tx_result, BlockV2Info, -}; +pub use indexer::{index_block, invalidate_block, transaction::index_transaction, tx_result}; use repository::{ AuctionHistoryByHeightRepository, AuctionHistoryRepository, BlockByHeightRepository, BlockRepository, MasternodeByHeightRepository, MasternodeRepository, MasternodeStatsRepository, @@ -29,21 +25,34 @@ pub type Result = std::result::Result; lazy_static::lazy_static! { // Global services exposed by the library - pub static ref SERVICES: Services = { - Services::new().expect("Error initialization Ocean services") + pub static ref SERVICES: Arc = { + let services = || { + let datadir = ain_cpp_imports::get_datadir(); + let store = Arc::new(OceanStore::new(&PathBuf::from(datadir))?); + + let (user, pass) = ain_cpp_imports::get_rpc_auth()?; + let client = Arc::new(Client::new( + &format!("localhost:{}", ain_cpp_imports::get_rpc_port()), + Auth::UserPass(user, pass), + )?); + + Services::new(client, store) + }; + + Arc::new(services().expect("Error initialization Ocean services")) }; } pub struct MasternodeService { - by_id: MasternodeRepository, - by_height: MasternodeByHeightRepository, - stats: MasternodeStatsRepository, + pub by_id: MasternodeRepository, + pub by_height: MasternodeByHeightRepository, + pub stats: MasternodeStatsRepository, } pub struct BlockService { - raw: RawBlockRepository, - by_id: BlockRepository, - by_height: BlockByHeightRepository, + pub raw: RawBlockRepository, + pub by_id: BlockRepository, + pub by_height: BlockByHeightRepository, } pub struct AuctionService { @@ -62,26 +71,17 @@ pub struct TransactionService { } pub struct Services { - masternode: MasternodeService, - block: BlockService, - auction: AuctionService, - result: TxResultRepository, - pool: PoolService, - client: Arc, - transaction: TransactionService, + pub masternode: MasternodeService, + pub block: BlockService, + pub auction: AuctionService, + pub result: TxResultRepository, + pub pool: PoolService, + pub client: Arc, + pub transaction: TransactionService, } impl Services { - fn new() -> Result { - let datadir = ain_cpp_imports::get_datadir(); - let store = Arc::new(OceanStore::new(&PathBuf::from(datadir))?); - - let (user, pass) = ain_cpp_imports::get_rpc_auth()?; - let client = Arc::new(Client::new( - &format!("localhost:{}", ain_cpp_imports::get_rpc_port()), - Auth::UserPass(user, pass), - )?); - + pub fn new(client: Arc, store: Arc) -> Result { Ok(Self { masternode: MasternodeService { by_id: MasternodeRepository::new(Arc::clone(&store)), diff --git a/lib/ain-ocean/src/model/block.rs b/lib/ain-ocean/src/model/block.rs index 273c89d9cc4..8a4ca76c9be 100644 --- a/lib/ain-ocean/src/model/block.rs +++ b/lib/ain-ocean/src/model/block.rs @@ -1,26 +1,25 @@ use bitcoin::BlockHash; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Block { - pub id: String, - pub hash: String, - pub previous_hash: String, + pub hash: BlockHash, + pub previous_hash: Option, pub height: u32, pub version: i32, - pub time: u32, + pub time: i64, pub median_time: i64, pub transaction_count: usize, - pub difficulty: u32, - pub masternode: String, - pub minter: String, + pub difficulty: f64, + pub masternode: Option, + pub minter: Option, pub minter_block_count: u64, pub stake_modifier: String, pub merkleroot: String, - pub size: usize, - pub size_stripped: usize, - pub weight: i64, + pub size: u64, + pub size_stripped: u64, + pub weight: u64, } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -28,6 +27,6 @@ pub struct Block { pub struct BlockContext { pub hash: BlockHash, pub height: u32, - pub time: u64, - pub median_time: u64, + pub time: i64, + pub median_time: i64, } diff --git a/lib/ain-ocean/src/model/masternode.rs b/lib/ain-ocean/src/model/masternode.rs index 41a1715db54..e4a410840af 100644 --- a/lib/ain-ocean/src/model/masternode.rs +++ b/lib/ain-ocean/src/model/masternode.rs @@ -1,4 +1,4 @@ -use bitcoin::{ScriptBuf, Txid}; +use bitcoin::Txid; use serde::{Deserialize, Serialize}; use super::BlockContext; @@ -7,14 +7,14 @@ use super::BlockContext; pub struct Masternode { pub id: Txid, // Keep for backward compatibility pub sort: String, // Keep for backward compatibility - pub owner_address: ScriptBuf, - pub operator_address: ScriptBuf, + pub owner_address: String, + pub operator_address: String, pub creation_height: u32, pub resign_height: Option, pub resign_tx: Option, pub minted_blocks: i32, pub timelock: u16, - pub collateral: String, + pub collateral: f64, pub block: BlockContext, pub history: Vec, } @@ -22,6 +22,6 @@ pub struct Masternode { #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct HistoryItem { - pub owner_address: ScriptBuf, - pub operator_address: ScriptBuf, + pub owner_address: String, + pub operator_address: String, } diff --git a/lib/ain-ocean/src/model/transaction.rs b/lib/ain-ocean/src/model/transaction.rs index 7cbeb26c9ab..c98f45e919d 100644 --- a/lib/ain-ocean/src/model/transaction.rs +++ b/lib/ain-ocean/src/model/transaction.rs @@ -9,13 +9,13 @@ pub struct Transaction { pub id: Txid, pub order: usize, pub block: BlockContext, - pub hash: BlockHash, - pub version: i32, - pub size: usize, - pub v_size: usize, + pub hash: String, + pub version: u32, + pub size: u64, + pub v_size: u64, pub weight: u64, - pub total_vout_value: u64, - pub lock_time: u32, + pub total_vout_value: f64, + pub lock_time: u64, pub vin_count: usize, pub vout_count: usize, } diff --git a/lib/ain-ocean/src/model/transaction_vin.rs b/lib/ain-ocean/src/model/transaction_vin.rs index 6694ab21c72..8626cfc0731 100644 --- a/lib/ain-ocean/src/model/transaction_vin.rs +++ b/lib/ain-ocean/src/model/transaction_vin.rs @@ -1,32 +1,59 @@ use bitcoin::Txid; +use defichain_rpc::json::blockchain::Vin; use serde::{Deserialize, Serialize}; + +use super::TransactionVout; + #[derive(Debug, Serialize, Deserialize)] pub struct TransactionVin { pub id: String, pub txid: Txid, - pub coinbase: String, - pub vout: TransactionVinVout, - pub script: TransactionVinScript, - pub tx_in_witness: Vec, - pub sequence: String, + pub coinbase: Option, + pub vout: Option, + pub script: Option, + pub tx_in_witness: Option>, + pub sequence: i64, +} + +impl TransactionVin { + pub fn from_vin_and_txid(vin: Vin, txid: Txid, vouts: &Vec) -> Self { + match vin { + Vin::Coinbase(v) => Self { + id: format!("{}00", txid), + txid: txid, + coinbase: Some(v.coinbase), + sequence: v.sequence, + vout: None, + script: None, + tx_in_witness: None, + }, + Vin::Standard(v) => { + let vout = vouts.get(v.vout as usize).map(|vout| TransactionVinVout { + txid: vout.txid, + value: vout.value, + n: vout.n, + token_id: vout.token_id, + script: vout.script.hex.to_owned(), + }); + Self { + id: format!("{}{}{:x}", txid, v.txid, v.vout), + txid: txid, + sequence: v.sequence, + vout, + script: v.script_sig.hex, + tx_in_witness: v.txinwitness, + coinbase: None, + } + } + } + } } #[derive(Debug, Serialize, Deserialize)] pub struct TransactionVinVout { - pub id: String, pub txid: Txid, - pub n: i32, - pub value: String, - pub token_id: i32, - pub script: TransactionVinVoutScript, -} - -#[derive(Debug, Default, Serialize, Deserialize)] -pub struct TransactionVinScript { - pub hex: String, -} - -#[derive(Debug, Default, Serialize, Deserialize)] -pub struct TransactionVinVoutScript { - pub hex: String, + pub n: usize, + pub value: f64, + pub token_id: u8, + pub script: String, } diff --git a/lib/ain-ocean/src/model/transaction_vout.rs b/lib/ain-ocean/src/model/transaction_vout.rs index 6e91cf07abd..461b3ae2ed3 100644 --- a/lib/ain-ocean/src/model/transaction_vout.rs +++ b/lib/ain-ocean/src/model/transaction_vout.rs @@ -1,11 +1,14 @@ +use bitcoin::Txid; use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, Serialize, Deserialize)] + +pub type TransactionVoutKey = (Txid, usize); + +#[derive(Debug, Serialize, Deserialize)] pub struct TransactionVout { - pub id: String, - pub txid: String, - pub n: i32, - pub value: String, - pub token_id: i32, + pub txid: Txid, + pub n: usize, + pub value: f64, + pub token_id: u8, pub script: TransactionVoutScript, } diff --git a/lib/ain-ocean/src/repository/transaction_vin.rs b/lib/ain-ocean/src/repository/transaction_vin.rs index 7d2c2ff3755..f1731ef135a 100644 --- a/lib/ain-ocean/src/repository/transaction_vin.rs +++ b/lib/ain-ocean/src/repository/transaction_vin.rs @@ -2,7 +2,6 @@ use std::sync::Arc; use ain_db::LedgerColumn; use ain_macros::Repository; -use bitcoin::Txid; use super::RepositoryOps; use crate::{ @@ -12,7 +11,7 @@ use crate::{ }; #[derive(Repository)] -#[repository(K = "Txid", V = "TransactionVin")] +#[repository(K = "String", V = "TransactionVin")] pub struct TransactionVinRepository { pub store: Arc, col: LedgerColumn, diff --git a/lib/ain-ocean/src/repository/transaction_vout.rs b/lib/ain-ocean/src/repository/transaction_vout.rs index 1bbd8cc6a27..72549b7785a 100644 --- a/lib/ain-ocean/src/repository/transaction_vout.rs +++ b/lib/ain-ocean/src/repository/transaction_vout.rs @@ -2,17 +2,16 @@ use std::sync::Arc; use ain_db::LedgerColumn; use ain_macros::Repository; -use bitcoin::Txid; use super::RepositoryOps; use crate::{ - model::TransactionVout, + model::{TransactionVout, TransactionVoutKey}, storage::{columns, ocean_store::OceanStore}, Result, }; #[derive(Repository)] -#[repository(K = "Txid", V = "TransactionVout")] +#[repository(K = "TransactionVoutKey", V = "TransactionVout")] pub struct TransactionVoutRepository { pub store: Arc, col: LedgerColumn, diff --git a/lib/ain-ocean/src/storage/columns/block.rs b/lib/ain-ocean/src/storage/columns/block.rs index 488a2aad218..448916c89fc 100644 --- a/lib/ain-ocean/src/storage/columns/block.rs +++ b/lib/ain-ocean/src/storage/columns/block.rs @@ -1,4 +1,5 @@ -use ain_db::{Column, ColumnName, TypedColumn}; +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; use bitcoin::BlockHash; use crate::model; @@ -28,6 +29,19 @@ impl ColumnName for BlockByHeight { impl Column for BlockByHeight { type Index = u32; + + fn key(index: &Self::Index) -> Result, DBError> { + Ok(index.to_be_bytes().to_vec()) + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + if raw_key.len() != 4 { + return Err(format_err!("Length of the slice is not 4").into()); + } + let mut array = [0u8; 4]; + array.copy_from_slice(&raw_key); + Ok(u32::from_be_bytes(array)) + } } impl TypedColumn for BlockByHeight { diff --git a/lib/ain-ocean/src/storage/columns/transaction_vin.rs b/lib/ain-ocean/src/storage/columns/transaction_vin.rs index bbe2fa4b513..f8d6116a966 100644 --- a/lib/ain-ocean/src/storage/columns/transaction_vin.rs +++ b/lib/ain-ocean/src/storage/columns/transaction_vin.rs @@ -1,5 +1,4 @@ use ain_db::{Column, ColumnName, TypedColumn}; -use bitcoin::Txid; use crate::model; @@ -11,7 +10,7 @@ impl ColumnName for TransactionVin { } impl Column for TransactionVin { - type Index = Txid; + type Index = String; } impl TypedColumn for TransactionVin { diff --git a/lib/ain-ocean/src/storage/columns/transaction_vout.rs b/lib/ain-ocean/src/storage/columns/transaction_vout.rs index 3af1bd48da6..c79d29d91a9 100644 --- a/lib/ain-ocean/src/storage/columns/transaction_vout.rs +++ b/lib/ain-ocean/src/storage/columns/transaction_vout.rs @@ -1,5 +1,4 @@ use ain_db::{Column, ColumnName, TypedColumn}; -use bitcoin::Txid; use crate::model; #[derive(Debug)] @@ -10,7 +9,7 @@ impl ColumnName for TransactionVout { } impl Column for TransactionVout { - type Index = Txid; + type Index = model::TransactionVoutKey; } impl TypedColumn for TransactionVout { diff --git a/lib/ain-rs-exports/Cargo.toml b/lib/ain-rs-exports/Cargo.toml index 30a88ff7c35..1f6ab201780 100644 --- a/lib/ain-rs-exports/Cargo.toml +++ b/lib/ain-rs-exports/Cargo.toml @@ -25,6 +25,7 @@ hex.workspace = true serde_json.workspace = true anyhow.workspace = true ethabi.workspace = true +defichain-rpc.workspace = true # Build cxx.workspace = true diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index 40de0bac01d..fc73f628ce9 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -55,21 +55,6 @@ pub mod ffi { fn ain_rs_stop_network_services(result: &mut CrossBoundaryResult); } - #[derive(Default)] - pub struct BlockV2Info { - pub height: u32, - pub difficulty: u32, - pub version: i32, - pub median_time: i64, - pub minter_block_count: u64, - pub size: usize, - pub size_stripped: usize, - pub weight: i64, - pub stake_modifier: String, - pub minter: String, - pub masternode: String, - } - // ========== Block ========== #[derive(Default)] pub struct EVMBlockHeader { @@ -361,12 +346,8 @@ pub mod ffi { fn evm_try_flush_db(result: &mut CrossBoundaryResult); - fn ocean_index_block(result: &mut CrossBoundaryResult, block: String, info: &BlockV2Info); - fn ocean_invalidate_block( - result: &mut CrossBoundaryResult, - block: String, - info: &BlockV2Info, - ); + fn ocean_index_block(result: &mut CrossBoundaryResult, block_str: String); + fn ocean_invalidate_block(result: &mut CrossBoundaryResult, block: String); fn ocean_try_set_tx_result( result: &mut CrossBoundaryResult, diff --git a/lib/ain-rs-exports/src/ocean.rs b/lib/ain-rs-exports/src/ocean.rs index 619e93547b8..585326c6466 100644 --- a/lib/ain-rs-exports/src/ocean.rs +++ b/lib/ain-rs-exports/src/ocean.rs @@ -1,40 +1,25 @@ use ain_macros::ffi_fallible; -use ain_ocean::{BlockV2Info, Result}; +use ain_ocean::Result; +use defichain_rpc::json::blockchain::{Block, Transaction}; use crate::{ ffi, - ffi::BlockV2Info as BlockV2InfoFFI, prelude::{cross_boundary_error_return, cross_boundary_success_return}, }; -// manually convert since BlockV2InfoFFI is belongs to CPP which can't impl From -> Into -pub fn convert(b: &BlockV2InfoFFI) -> BlockV2Info { - BlockV2Info { - height: b.height, - difficulty: b.difficulty, - version: b.version, - median_time: b.median_time, - minter_block_count: b.minter_block_count, - size: b.size, - size_stripped: b.size_stripped, - weight: b.weight, - stake_modifier: b.stake_modifier.to_owned(), - minter: b.minter.to_owned(), - masternode: b.masternode.to_owned(), - } -} - #[ffi_fallible] -pub fn ocean_index_block(block: String, b: &BlockV2InfoFFI) -> Result<()> { - ain_ocean::index_block(block, &convert(b)) +pub fn ocean_index_block(block_str: String) -> Result<()> { + let block: Block = serde_json::from_str(&block_str)?; + ain_ocean::index_block(&*ain_ocean::SERVICES, block) } #[ffi_fallible] -pub fn ocean_invalidate_block(block: String, b: &BlockV2InfoFFI) -> Result<()> { - ain_ocean::invalidate_block(block, &convert(b)) +pub fn ocean_invalidate_block(block_str: String) -> Result<()> { + let block: Block = serde_json::from_str(&block_str)?; + ain_ocean::invalidate_block(block) } #[ffi_fallible] fn ocean_try_set_tx_result(tx_type: u8, tx_hash: [u8; 32], result_ptr: usize) -> Result<()> { - ain_ocean::tx_result::index(tx_type, tx_hash, result_ptr) + ain_ocean::tx_result::index(&*ain_ocean::SERVICES, tx_type, tx_hash, result_ptr) } diff --git a/src/dfi/validation.cpp b/src/dfi/validation.cpp index 54a6710d053..9299671ab26 100644 --- a/src/dfi/validation.cpp +++ b/src/dfi/validation.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -2792,45 +2793,13 @@ Res ProcessDeFiEventFallible(const CBlock &block, // Ocean archive if (gArgs.GetBoolArg("-oceanarchive", DEFAULT_OCEAN_ARCHIVE_ENABLED)) { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << block; - - // Convert the serialized data to a string - std::string serializedData = HexStr(ss.begin(), ss.end()); + const UniValue b = blockToJSON(block, ::ChainActive().Tip(), pindex, true, 2); CrossBoundaryResult result; - BlockV2Info info; - info.height = pindex->nHeight; - info.difficulty = pindex->nBits; - info.version = pindex->nVersion; - info.median_time = (int64_t)pindex->GetMedianTimePast(); - info.minter_block_count = pindex->mintedBlocks; - info.size = GetSerializeSize(block, PROTOCOL_VERSION); - info.size_stripped = GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS); - info.weight = GetBlockWeight(block); - info.stake_modifier = pindex->stakeModifier.ToString(); - info.minter = ""; // mn operator address - info.masternode = ""; // mn owner address - - // minter info - CKeyID minter; - block.ExtractMinterKey(minter); - - auto id = mnview.GetMasternodeIdByOperator(minter); - if (id) { - info.masternode = id->ToString(); - auto mn = mnview.GetMasternode(*id); - if (mn) { - auto dest = - mn->operatorType == 1 ? CTxDestination(PKHash(minter)) : CTxDestination(WitnessV0KeyHash(minter)); - info.minter = EncodeDestination(dest); - } - } - - ocean_index_block(result, serializedData, info); - // if (!result.ok) { - // return Res::Err(result.reason.c_str()); - // } + ocean_index_block(result, b.write()); + if (!result.ok) { + return Res::Err(result.reason.c_str()); + } } return Res::Ok(); diff --git a/src/init.cpp b/src/init.cpp index c85eb6070be..6a606c88135 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2464,7 +2464,33 @@ bool AppInitMain(InitInterfaces& interfaces) spv::pspv->Connect(); } - // ********************************************************* Step 15: start minter thread + + // ********************************************************* Step 15: start genesis ocean indexing + if(gArgs.GetBoolArg("-oceanarchive", DEFAULT_OCEAN_ARCHIVE_ENABLED)) { + const CBlock &block = chainparams.GenesisBlock(); + + const CBlockIndex* pblockindex; + const CBlockIndex* tip; + { + LOCK(cs_main); + + pblockindex = LookupBlockIndex(block.GetHash()); + assert(pblockindex); + + tip = ::ChainActive().Tip(); + } + + const UniValue b = blockToJSON(block, tip, pblockindex, true, 2); + + CrossBoundaryResult result; + ocean_index_block(result, b.write()); + if (!result.ok) { + LogPrintf("Error indexing genesis block: %s\n", result.reason); + return false; + } + } + + // ********************************************************* Step 16: start minter thread if(gArgs.GetBoolArg("-gen", DEFAULT_GENERATE)) { LOCK(cs_main); @@ -2565,50 +2591,5 @@ bool AppInitMain(InitInterfaces& interfaces) }); } - // ********************************************************* Step 16: start genesis ocean indexing - if(gArgs.GetBoolArg("-oceanarchive", DEFAULT_OCEAN_ARCHIVE_ENABLED)) { - const CBlock &block = chainparams.GenesisBlock(); - - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << block; - CBlockIndex* pindex = ::ChainActive().Tip(); - - // Convert the serialized data to a string - std::string serializedData = HexStr(ss.begin(), ss.end()); - - CrossBoundaryResult result; - BlockV2Info info; - info.height = pindex->nHeight; - info.difficulty = pindex->nBits; - info.version = pindex->nVersion; - info.median_time = (int64_t)pindex->GetMedianTimePast(); - info.minter_block_count = pindex->mintedBlocks; - info.size = GetSerializeSize(block, PROTOCOL_VERSION); - info.size_stripped = GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS); - info.weight = GetBlockWeight(block); - info.stake_modifier = pindex->stakeModifier.ToString(); - info.minter = ""; // mn operator address - info.masternode = ""; // mn owner address - - // minter info - CKeyID minter; - block.ExtractMinterKey(minter); - - auto id = pcustomcsview->GetMasternodeIdByOperator(minter); - if (id) { - info.masternode = id->ToString(); - auto mn = pcustomcsview->GetMasternode(*id); - if (mn) { - auto dest = mn->operatorType == 1 ? CTxDestination(PKHash(minter)) : CTxDestination(WitnessV0KeyHash(minter)); - info.minter = EncodeDestination(dest); - } - } - - ocean_index_block(result, serializedData, info); - // if (!result.ok) { - // return Res::Err(result.reason.c_str()); - // } - } - return true; } From 20a283fc19a08a722c2fe9bcec7dbf7291b94a68 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Fri, 2 Feb 2024 04:35:22 +0800 Subject: [PATCH 041/185] Fix: Ocean resp get (#2811) * fix resp get * rm unuse ci --- .github/workflows/tests-ocean.yml | 8 -------- lib/ain-ocean/src/api/block.rs | 10 +++++----- lib/ain-ocean/src/api/fee.rs | 4 ++-- lib/ain-ocean/src/api/governance.rs | 4 ++-- lib/ain-ocean/src/api/tokens.rs | 4 ++-- 5 files changed, 11 insertions(+), 19 deletions(-) diff --git a/.github/workflows/tests-ocean.yml b/.github/workflows/tests-ocean.yml index 6f46822c403..4235d785373 100644 --- a/.github/workflows/tests-ocean.yml +++ b/.github/workflows/tests-ocean.yml @@ -77,14 +77,6 @@ jobs: with: node-version: '18' - - uses: actions/checkout@v4 - with: - path: defichain - ref: 'feature/ocean-archive' - - - name: Populate environment - run: cd defichain && ./make.sh ci-export-vars - - name: Run tests run: | npm ci diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 93973f13c36..5b6ae039f62 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -5,7 +5,7 @@ use axum::{extract::Path, routing::get, Extension, Router}; use bitcoin::BlockHash; use serde::{Deserialize, Deserializer}; -use super::response::ApiPagedResponse; +use super::response::{ApiPagedResponse, Response}; use crate::{ api_query::{PaginationQuery, Query}, error::ApiError, @@ -66,7 +66,7 @@ async fn list_blocks( async fn get_block( Path(id): Path, Extension(services): Extension>, -) -> Result> { +) -> Result>> { let block = if let Some(id) = match id { HashOrHeight::Height(n) => services.block.by_height.get(&n)?, HashOrHeight::Id(id) => Some(id), @@ -76,7 +76,7 @@ async fn get_block( None }; - Ok(block) + Ok(Response::new(block)) } async fn get_transactions( @@ -88,10 +88,10 @@ async fn get_transactions( // Get highest indexed block #[ocean_endpoint] -async fn get_highest(Extension(services): Extension>) -> Result> { +async fn get_highest(Extension(services): Extension>) -> Result>> { let block = services.block.by_height.get_highest()?; - Ok(block) + Ok(Response::new(block)) } pub fn router(services: Arc) -> Router { diff --git a/lib/ain-ocean/src/api/fee.rs b/lib/ain-ocean/src/api/fee.rs index ab0a8f2c8d5..3abbd75058b 100644 --- a/lib/ain-ocean/src/api/fee.rs +++ b/lib/ain-ocean/src/api/fee.rs @@ -20,13 +20,13 @@ async fn estimate_fee( confirmation_target, }): Query, Extension(services): Extension>, -) -> Result { +) -> Result> { let estimation: SmartFeeEstimation = services.client.call( "estimatesmartfee", &[confirmation_target.into(), "CONSERVATIVE".into()], )?; - Ok(estimation.feerate.unwrap_or(0.00005000)) + Ok(Response::new(estimation.feerate.unwrap_or(0.00005000))) } pub fn router(services: Arc) -> Router { diff --git a/lib/ain-ocean/src/api/governance.rs b/lib/ain-ocean/src/api/governance.rs index cd12ac23dca..8b224db759a 100644 --- a/lib/ain-ocean/src/api/governance.rs +++ b/lib/ain-ocean/src/api/governance.rs @@ -54,13 +54,13 @@ async fn list_gov_proposals( async fn get_gov_proposal( Path(proposal_id): Path, Extension(services): Extension>, -) -> Result { +) -> Result> { let txid: Txid = proposal_id .parse() .map_err(|_| OceanError::NotFound(NotFoundKind::Proposal))?; let proposal = services.client.get_gov_proposal(txid)?; - Ok(proposal) + Ok(Response::new(proposal)) } #[ocean_endpoint] diff --git a/lib/ain-ocean/src/api/tokens.rs b/lib/ain-ocean/src/api/tokens.rs index e423a9c84ec..26494970f5b 100644 --- a/lib/ain-ocean/src/api/tokens.rs +++ b/lib/ain-ocean/src/api/tokens.rs @@ -116,7 +116,7 @@ async fn list_tokens( async fn get_token( Path(id): Path, Extension(services): Extension>, -) -> Result> { +) -> Result>> { let mut v: TokenResult = services.client.call("gettoken", &[id.into()])?; let res = if let Some(token) = v.0.remove(&id) { @@ -125,7 +125,7 @@ async fn get_token( None }; - Ok(res) + Ok(Response::new(res)) } pub fn router(services: Arc) -> Router { From 4da19825e18163bb9d25061406ede6d580adb709 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Tue, 6 Feb 2024 09:14:50 +0100 Subject: [PATCH 042/185] Fix RPC port (#2815) --- src/ffi/ffiexports.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ffi/ffiexports.cpp b/src/ffi/ffiexports.cpp index c66d42e51b0..175ee8d8e02 100644 --- a/src/ffi/ffiexports.cpp +++ b/src/ffi/ffiexports.cpp @@ -24,7 +24,7 @@ uint64_t getChainId() { } int getRPCPort() { - return BaseParams().RPCPort(); + return gArgs.GetArg("-rpcport", BaseParams().RPCPort()); } rust::string getRPCAuth() { From 24a9275e857b5a6528be77332e8a63aa5178527d Mon Sep 17 00:00:00 2001 From: canonbrother Date: Tue, 6 Feb 2024 14:31:07 +0800 Subject: [PATCH 043/185] pagination size serde_with displayfromstr --- lib/Cargo.lock | 1 + lib/ain-ocean/Cargo.toml | 1 + lib/ain-ocean/src/api_query.rs | 3 +++ 3 files changed, 5 insertions(+) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index bdfe2dd9ad0..498a278f527 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -251,6 +251,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "serde_with", "structopt", "tarpc", "tempdir", diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index 1e1424c328a..eae49713bb8 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -17,6 +17,7 @@ hyper.workspace = true keccak-hash.workspace = true log.workspace = true serde.workspace = true +serde_with.workspace = true thiserror.workspace = true hex.workspace = true dftx-rs.workspace = true diff --git a/lib/ain-ocean/src/api_query.rs b/lib/ain-ocean/src/api_query.rs index 21d41e12407..2357a1b1003 100644 --- a/lib/ain-ocean/src/api_query.rs +++ b/lib/ain-ocean/src/api_query.rs @@ -4,6 +4,7 @@ use axum::{ http::{request::Parts, StatusCode}, }; use serde::{de::DeserializeOwned, Deserialize}; +use serde_with::{serde_as, DisplayFromStr}; use crate::error::ApiError; @@ -11,8 +12,10 @@ pub fn default_pagination_size() -> usize { 30 } +#[serde_as] #[derive(Deserialize, Default, Debug)] pub struct PaginationQuery { + #[serde_as(as = "DisplayFromStr")] #[serde(default = "default_pagination_size")] pub size: usize, pub next: Option, From 62ddeb18a97997e46cb77bc3bd67c3e9f5f556c6 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Wed, 7 Feb 2024 14:53:55 +0800 Subject: [PATCH 044/185] deserialize undefined to none --- lib/ain-ocean/src/api_query.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/ain-ocean/src/api_query.rs b/lib/ain-ocean/src/api_query.rs index 2357a1b1003..d5cfcdebae5 100644 --- a/lib/ain-ocean/src/api_query.rs +++ b/lib/ain-ocean/src/api_query.rs @@ -3,7 +3,10 @@ use axum::{ extract::FromRequestParts, http::{request::Parts, StatusCode}, }; -use serde::{de::DeserializeOwned, Deserialize}; +use serde::{ + de::{DeserializeOwned, Deserializer}, + Deserialize, +}; use serde_with::{serde_as, DisplayFromStr}; use crate::error::ApiError; @@ -18,9 +21,25 @@ pub struct PaginationQuery { #[serde_as(as = "DisplayFromStr")] #[serde(default = "default_pagination_size")] pub size: usize, + #[serde(deserialize_with = "undefined_to_none")] pub next: Option, } +fn undefined_to_none<'de, D>(d: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let v: Option = Deserialize::deserialize(d)?; + match v { + Some(v) => if v.as_str() == "undefined" { + Ok(None) + } else { + Ok(Some(v)) + }, + None => Ok(None) + } +} + pub struct Query(pub T); #[async_trait] From e204056666b2fe6bee4bffb805eb7c18185d22f3 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Wed, 7 Feb 2024 22:35:53 +0100 Subject: [PATCH 045/185] Ocean: async RPC client (#2817) --- lib/Cargo.lock | 276 ++++++++++++++------------ lib/ain-grpc/src/lib.rs | 39 ++-- lib/ain-ocean/Cargo.toml | 4 +- lib/ain-ocean/src/api/address.rs | 2 +- lib/ain-ocean/src/api/block.rs | 33 +-- lib/ain-ocean/src/api/fee.rs | 19 +- lib/ain-ocean/src/api/governance.rs | 21 +- lib/ain-ocean/src/api/loan.rs | 2 +- lib/ain-ocean/src/api/masternode.rs | 2 +- lib/ain-ocean/src/api/mod.rs | 54 +++-- lib/ain-ocean/src/api/oracle.rs | 2 +- lib/ain-ocean/src/api/poolpairs.rs | 2 +- lib/ain-ocean/src/api/prices.rs | 2 +- lib/ain-ocean/src/api/rawtx.rs | 2 +- lib/ain-ocean/src/api/tokens.rs | 15 +- lib/ain-ocean/src/api/transactions.rs | 2 +- lib/ain-ocean/src/api_query.rs | 8 +- lib/ain-ocean/src/error.rs | 4 +- lib/ain-ocean/src/lib.rs | 25 +-- 19 files changed, 276 insertions(+), 238 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 498a278f527..74265fd7286 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -242,7 +242,7 @@ dependencies = [ "hex", "hyper 0.14.28", "json", - "jsonrpc", + "jsonrpc-async", "jsonrpsee 0.16.3", "keccak-hash", "lazy_static", @@ -418,14 +418,13 @@ dependencies = [ [[package]] name = "auto_impl" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" +checksum = "823b8bb275161044e2ac7a25879cb3e2480cb403e3943022c7c769c599b756aa" dependencies = [ - "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.48", ] [[package]] @@ -580,6 +579,15 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64-compat" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a8d4d2746f89841e49230dd26917df1876050f95abafafbe34f47cb534b88d7" +dependencies = [ + "byteorder", +] + [[package]] name = "base64ct" version = "1.6.0" @@ -667,7 +675,7 @@ dependencies = [ "bitcoin_hashes 0.13.0", "hex-conservative", "hex_lit", - "secp256k1 0.28.1", + "secp256k1 0.28.2", "serde", ] @@ -863,9 +871,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "bytemuck" -version = "1.14.0" +version = "1.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +checksum = "ea31d69bda4949c1c1562c1e6f042a1caefac98cdc8a298260a2ff41c1e2d42b" [[package]] name = "byteorder" @@ -963,9 +971,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.32" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41daef31d7a747c5c847246f36de49ced6f7403b4cdabc807a97b5cc184cda7a" +checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1024,9 +1032,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5104de16b218eddf8e34ffe2f86f74bfa4e61e95a1b89732fccf6325efd0557" +checksum = "18d59688ad0945eaf6b84cb44fedbe93484c81b48970e98f09db8a22832d7961" dependencies = [ "cfg-if", "cpufeatures", @@ -1291,12 +1299,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.3" +version = "0.20.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +checksum = "fc5d6b04b3fd0ba9926f945895de7d806260a2d7431ba82e7edaecb043c4c6b8" dependencies = [ - "darling_core 0.20.3", - "darling_macro 0.20.3", + "darling_core 0.20.5", + "darling_macro 0.20.5", ] [[package]] @@ -1315,9 +1323,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.3" +version = "0.20.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +checksum = "04e48a959bcd5c761246f5d090ebc2fbf7b9cd527a492b07a67510c108f1e7e3" dependencies = [ "fnv", "ident_case", @@ -1340,11 +1348,11 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.3" +version = "0.20.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +checksum = "1d1545d67a2149e1d93b7e5c7752dce5a7426eb5d1357ddcfd89336b94444f77" dependencies = [ - "darling_core 0.20.3", + "darling_core 0.20.5", "quote", "syn 2.0.48", ] @@ -1352,10 +1360,11 @@ dependencies = [ [[package]] name = "defichain-rpc" version = "0.18.0" -source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#261421ae27f89953015643e25943bd558c8432e9" +source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#179363a23efe48170196016b41f823c3f7644337" dependencies = [ + "async-trait", "defichain-rpc-json", - "jsonrpc", + "jsonrpc-async", "log", "serde", "serde_json", @@ -1364,7 +1373,7 @@ dependencies = [ [[package]] name = "defichain-rpc-json" version = "0.18.0" -source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#261421ae27f89953015643e25943bd558c8432e9" +source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#179363a23efe48170196016b41f823c3f7644337" dependencies = [ "bitcoin", "serde", @@ -1747,9 +1756,9 @@ dependencies = [ [[package]] name = "ethers-core" -version = "2.0.12" +version = "2.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "918b1a9ba585ea61022647def2f27c29ba19f6d2a4a4c8f68a9ae97fd5769737" +checksum = "aab3cef6cc1c9fd7f787043c81ad3052eff2b96a3878ef1526aa446311bdbfc9" dependencies = [ "arrayvec 0.7.4", "bytes", @@ -1774,9 +1783,9 @@ dependencies = [ [[package]] name = "ethers-solc" -version = "2.0.12" +version = "2.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2e46e3ec8ef0c986145901fa9864205dc4dcee701f9846be2d56112d34bdea" +checksum = "d21df08582e0a43005018a858cc9b465c5fff9cf4056651be64f844e57d1f55f" dependencies = [ "cfg-if", "const-hex", @@ -2148,7 +2157,7 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.4", + "regex-automata 0.4.5", "regex-syntax 0.8.2", ] @@ -2175,7 +2184,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.11", - "indexmap 2.1.0", + "indexmap 2.2.2", "slab", "tokio", "tokio-util", @@ -2194,7 +2203,7 @@ dependencies = [ "futures-sink", "futures-util", "http 1.0.0", - "indexmap 2.1.0", + "indexmap 2.2.2", "slab", "tokio", "tokio-util", @@ -2276,9 +2285,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" +checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" [[package]] name = "hex" @@ -2507,12 +2516,11 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdea9aac0dbe5a9240d68cfd9501e2db94222c6dc06843e06640b9e07f0fdc67" +checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" dependencies = [ "bytes", - "futures-channel", "futures-util", "http 1.0.0", "http-body 1.0.0", @@ -2520,14 +2528,13 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", - "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.59" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2613,9 +2620,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -2646,7 +2653,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.4", + "hermit-abi 0.3.5", "libc", "windows-sys 0.48.0", ] @@ -2673,8 +2680,8 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" dependencies = [ - "hermit-abi 0.3.4", - "rustix 0.38.30", + "hermit-abi 0.3.5", + "rustix 0.38.31", "windows-sys 0.52.0", ] @@ -2713,9 +2720,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" dependencies = [ "wasm-bindgen", ] @@ -2727,14 +2734,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" [[package]] -name = "jsonrpc" -version = "0.14.1" +name = "jsonrpc-async" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8128f36b47411cd3f044be8c1f5cc0c9e24d1d1bfdc45f0a57897b32513053f2" +checksum = "a20e8e4ed08ee58717113cbf277b1ecef5cd9554d3e48c114de338289727d466" dependencies = [ - "base64 0.13.1", + "async-trait", + "base64-compat", "serde", + "serde_derive", "serde_json", + "tokio", ] [[package]] @@ -3017,9 +3027,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.152" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libloading" @@ -3114,9 +3124,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.14" +version = "1.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "295c17e837573c8c821dbaeb3cceb3d745ad082f7572191409e69cbc1b3fd050" +checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6" dependencies = [ "cc", "pkg-config", @@ -3162,9 +3172,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "lru" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2994eeba8ed550fd9b47a0b38f0242bc3344e496483c6180b69139cc2fa5d1d7" +checksum = "db2c024b41519440580066ba82aab04092b333e09066a5eb86c7c4890df31f22" dependencies = [ "hashbrown 0.14.3", ] @@ -3235,7 +3245,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix 0.38.30", + "rustix 0.38.31", ] [[package]] @@ -3307,9 +3317,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] @@ -3420,13 +3430,19 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-format" version = "0.4.4" @@ -3486,7 +3502,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.4", + "hermit-abi 0.3.5", "libc", ] @@ -3505,7 +3521,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate 2.0.1", + "proc-macro-crate 2.0.2", "proc-macro2", "quote", "syn 2.0.48", @@ -3651,7 +3667,7 @@ version = "3.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" dependencies = [ - "proc-macro-crate 2.0.1", + "proc-macro-crate 2.0.2", "proc-macro2", "quote", "syn 1.0.109", @@ -3743,7 +3759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.1.0", + "indexmap 2.2.2", ] [[package]] @@ -3799,18 +3815,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" dependencies = [ "proc-macro2", "quote", @@ -3909,9 +3925,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" dependencies = [ "toml_datetime", "toml_edit 0.20.2", @@ -4245,7 +4261,7 @@ checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.4", + "regex-automata 0.4.5", "regex-syntax 0.8.2", ] @@ -4260,9 +4276,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", @@ -4298,9 +4314,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.23" +version = "0.11.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" dependencies = [ "base64 0.21.7", "bytes", @@ -4324,6 +4340,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", "system-configuration", "tokio", "tokio-rustls", @@ -4464,9 +4481,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.30" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ "bitflags 2.4.2", "errno", @@ -4659,9 +4676,9 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.28.1" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f622567e3b4b38154fb8190bcf6b160d7a4301d70595a49195b48c116007a27" +checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" dependencies = [ "bitcoin_hashes 0.13.0", "rand 0.8.5", @@ -4745,18 +4762,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.195" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", @@ -4765,9 +4782,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" dependencies = [ "itoa", "ryu", @@ -4798,15 +4815,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.5.1" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5c9fdb6b00a489875b22efd4b78fe2b363b72265cc5f6eb2e2b9ee270e6140c" +checksum = "1b0ed1662c5a68664f45b76d18deb0e234aff37207086803165c961eb695e981" dependencies = [ "base64 0.21.7", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.1.0", + "indexmap 2.2.2", "serde", "serde_json", "serde_with_macros", @@ -4815,11 +4832,11 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.5.1" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbff351eb4b33600a2e138dfa0b10b65a238ea8ff8fb2387c422c5022a3e8298" +checksum = "568577ff0ef47b879f736cd66740e022f3672788cdf002a05a4e609ea5a6fb15" dependencies = [ - "darling 0.20.3", + "darling 0.20.5", "proc-macro2", "quote", "syn 2.0.48", @@ -5437,9 +5454,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "svm-rs" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ce290b5536ab2a42a61c9c6f22d6bfa8f26339c602aa62db4c978c95d1afc47" +checksum = "11297baafe5fa0c99d5722458eac6a5e25c01eb1b8e5cd137f54079093daa7a4" dependencies = [ "dirs", "fs2", @@ -5563,14 +5580,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.9.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", - "rustix 0.38.30", + "rustix 0.38.31", "windows-sys 0.52.0", ] @@ -5644,12 +5660,13 @@ dependencies = [ [[package]] name = "time" -version = "0.3.31" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ "deranged", "itoa", + "num-conv", "powerfmt", "serde", "time-core", @@ -5664,10 +5681,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" dependencies = [ + "num-conv", "time-core", ] @@ -5716,9 +5734,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.1" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ "backtrace", "bytes", @@ -5815,7 +5833,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.2", "toml_datetime", "winnow", ] @@ -5826,7 +5844,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.2", "toml_datetime", "winnow", ] @@ -6140,9 +6158,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" @@ -6310,9 +6328,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -6320,9 +6338,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" dependencies = [ "bumpalo", "log", @@ -6335,9 +6353,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" +checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" dependencies = [ "cfg-if", "js-sys", @@ -6347,9 +6365,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6357,9 +6375,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", @@ -6370,9 +6388,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" [[package]] name = "wasmparser" @@ -6518,9 +6536,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" +checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" dependencies = [ "js-sys", "wasm-bindgen", @@ -6528,9 +6546,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.3" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "which" @@ -6541,14 +6559,14 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.30", + "rustix 0.38.31", ] [[package]] name = "wide" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b31891d644eba1789fb6715f27fbc322e4bdf2ecdc412ede1993246159271613" +checksum = "89beec544f246e679fc25490e3f8e08003bc4bf612068f325120dad4cea02c1c" dependencies = [ "bytemuck", "safe_arch", @@ -6794,9 +6812,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.34" +version = "0.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +checksum = "5389a154b01683d28c77f8f68f49dea75f0a4da32557a58f68ee51ebba472d29" dependencies = [ "memchr", ] diff --git a/lib/ain-grpc/src/lib.rs b/lib/ain-grpc/src/lib.rs index cbe8c44131d..474e0f5c31b 100644 --- a/lib/ain-grpc/src/lib.rs +++ b/lib/ain-grpc/src/lib.rs @@ -29,6 +29,7 @@ use std::{ }; use ain_evm::services::{IS_SERVICES_INIT_CALL, SERVICES}; +use ain_ocean::SERVICES as OCEAN_SERVICES; use anyhow::{format_err, Result}; use hyper::{header::HeaderValue, Method}; use jsonrpsee::core::server::rpc_module::Methods; @@ -112,6 +113,27 @@ pub fn init_network_json_rpc_service(addr: String) -> Result<()> { Ok(()) } +pub async fn init_ocean_server(addr: String) -> Result<()> { + let addr = addr.parse::()?; + let runtime = &SERVICES; + + let listener = tokio::net::TcpListener::bind(addr).await?; + let ocean_router = ain_ocean::ocean_router(&*OCEAN_SERVICES).await?; + + let server_handle = runtime.tokio_runtime.spawn(async move { + if let Err(e) = axum::serve(listener, ocean_router).await { + log::error!("Server encountered an error: {}", e); + } + }); + *runtime.ocean_handle.lock() = Some(server_handle); + Ok(()) +} + +pub fn init_network_rest_ocean(addr: String) -> Result<()> { + info!("Starting REST Ocean server at {}", addr); + SERVICES.tokio_runtime.block_on(init_ocean_server(addr)) +} + pub fn init_network_grpc_service(_addr: String) -> Result<()> { // log::info!("Starting gRPC server at {}", addr); // Commented out for now as nothing to serve @@ -122,23 +144,6 @@ pub fn init_network_grpc_service(_addr: String) -> Result<()> { Ok(()) } -pub fn init_network_rest_ocean(addr: String) -> Result<()> { - info!("Starting REST Ocean server at {}", addr); - let addr = addr.as_str().parse::()?; - let runtime = &SERVICES; - - let listener = runtime - .tokio_runtime - .block_on(tokio::net::TcpListener::bind(addr))?; - let ocean_router = ain_ocean::ocean_router()?; - let server_handle = runtime.tokio_runtime.spawn(async move { - axum::serve(listener, ocean_router).await.unwrap(); - }); - *runtime.ocean_handle.lock() = Some(server_handle); - - Ok(()) -} - pub fn init_network_subscriptions_service(addr: String) -> Result<()> { info!("Starting WebSockets server at {}", addr); let addr = addr.as_str().parse::()?; diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index eae49713bb8..d27bf0cd5cc 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -41,5 +41,5 @@ cached.workspace = true lazy_static.workspace = true bincode.workspace = true defichain-rpc.workspace = true -jsonrpc = "0.14.1" -serde_urlencoded = { version = "0.7" } +jsonrpc-async = "2.0.2" +serde_urlencoded = "0.7" diff --git a/lib/ain-ocean/src/api/address.rs b/lib/ain-ocean/src/api/address.rs index 296055c0116..9bce516afb3 100644 --- a/lib/ain-ocean/src/api/address.rs +++ b/lib/ain-ocean/src/api/address.rs @@ -57,7 +57,7 @@ async fn list_transaction_unspent(Path(Address { address }): Path
) -> S format!("List unspent transactions for address {}", address) } -pub fn router(services: Arc) -> Router { +pub fn router(ctx: Arc) -> Router { Router::new().nest( "/:address", Router::new() diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 5b6ae039f62..c9c2c4cc713 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -5,13 +5,16 @@ use axum::{extract::Path, routing::get, Extension, Router}; use bitcoin::BlockHash; use serde::{Deserialize, Deserializer}; -use super::response::{ApiPagedResponse, Response}; +use super::{ + response::{ApiPagedResponse, Response}, + AppContext, +}; use crate::{ api_query::{PaginationQuery, Query}, error::ApiError, model::Block, repository::RepositoryOps, - Result, Services, + Result, }; pub enum HashOrHeight { @@ -38,16 +41,18 @@ impl<'de> Deserialize<'de> for HashOrHeight { #[ocean_endpoint] async fn list_blocks( Query(query): Query, - Extension(services): Extension>, + Extension(ctx): Extension>, ) -> Result> { - let blocks = services + let blocks = ctx + .services .block .by_height .list(None)? .take(query.size) .map(|item| { let (_, id) = item?; - let b = services + let b = ctx + .services .block .by_id .get(&id)? @@ -65,13 +70,13 @@ async fn list_blocks( #[ocean_endpoint] async fn get_block( Path(id): Path, - Extension(services): Extension>, + Extension(ctx): Extension>, ) -> Result>> { let block = if let Some(id) = match id { - HashOrHeight::Height(n) => services.block.by_height.get(&n)?, + HashOrHeight::Height(n) => ctx.services.block.by_height.get(&n)?, HashOrHeight::Id(id) => Some(id), } { - services.block.by_id.get(&id)? + ctx.services.block.by_id.get(&id)? } else { None }; @@ -81,24 +86,26 @@ async fn get_block( async fn get_transactions( Path(hash): Path, - Extension(services): Extension>, + Extension(ctx): Extension>, ) -> String { format!("Transactions for block with hash {}", hash) } // Get highest indexed block #[ocean_endpoint] -async fn get_highest(Extension(services): Extension>) -> Result>> { - let block = services.block.by_height.get_highest()?; +async fn get_highest( + Extension(ctx): Extension>, +) -> Result>> { + let block = ctx.services.block.by_height.get_highest()?; Ok(Response::new(block)) } -pub fn router(services: Arc) -> Router { +pub fn router(ctx: Arc) -> Router { Router::new() .route("/", get(list_blocks)) .route("/highest", get(get_highest)) .route("/:id", get(get_block)) .route("/:hash/transactions", get(get_transactions)) - .layer(Extension(services)) + .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/api/fee.rs b/lib/ain-ocean/src/api/fee.rs index 3abbd75058b..93fd17b7f27 100644 --- a/lib/ain-ocean/src/api/fee.rs +++ b/lib/ain-ocean/src/api/fee.rs @@ -5,7 +5,7 @@ use axum::{routing::get, Extension, Router}; use defichain_rpc::{json::mining::SmartFeeEstimation, Client, RpcApi}; use serde::Deserialize; -use super::response::Response; +use super::{response::Response, AppContext}; use crate::{api_query::Query, error::ApiError, Result, Services}; #[derive(Deserialize, Default)] @@ -19,18 +19,21 @@ async fn estimate_fee( Query(EstimateQuery { confirmation_target, }): Query, - Extension(services): Extension>, + Extension(ctx): Extension>, ) -> Result> { - let estimation: SmartFeeEstimation = services.client.call( - "estimatesmartfee", - &[confirmation_target.into(), "CONSERVATIVE".into()], - )?; + let estimation: SmartFeeEstimation = ctx + .client + .call( + "estimatesmartfee", + &[confirmation_target.into(), "CONSERVATIVE".into()], + ) + .await?; Ok(Response::new(estimation.feerate.unwrap_or(0.00005000))) } -pub fn router(services: Arc) -> Router { +pub fn router(ctx: Arc) -> Router { Router::new() .route("/estimate", get(estimate_fee)) - .layer(Extension(services)) + .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/api/governance.rs b/lib/ain-ocean/src/api/governance.rs index 8b224db759a..2b94ef18315 100644 --- a/lib/ain-ocean/src/api/governance.rs +++ b/lib/ain-ocean/src/api/governance.rs @@ -6,7 +6,10 @@ use bitcoin::Txid; use defichain_rpc::{json::governance::*, GovernanceRPC}; use serde::Deserialize; -use super::response::{ApiPagedResponse, Response}; +use super::{ + response::{ApiPagedResponse, Response}, + AppContext, +}; use crate::{ api_query::{PaginationQuery, Query}, error::{ApiError, NotFoundKind, OceanError}, @@ -27,7 +30,7 @@ pub struct GovernanceQuery { #[ocean_endpoint] async fn list_gov_proposals( Query(query): Query, - Extension(services): Extension>, + Extension(ctx): Extension>, ) -> Result> { let size = match query.all { Some(true) => 0, @@ -43,7 +46,7 @@ async fn list_gov_proposals( r#type: query.r#type, cycle: query.cycle, }; - let proposals = services.client.list_gov_proposals(Some(opts))?; + let proposals = ctx.client.list_gov_proposals(Some(opts)).await?; Ok(ApiPagedResponse::of(proposals, size, |proposal| { proposal.proposal_id.to_string() @@ -53,13 +56,13 @@ async fn list_gov_proposals( #[ocean_endpoint] async fn get_gov_proposal( Path(proposal_id): Path, - Extension(services): Extension>, + Extension(ctx): Extension>, ) -> Result> { let txid: Txid = proposal_id .parse() .map_err(|_| OceanError::NotFound(NotFoundKind::Proposal))?; - let proposal = services.client.get_gov_proposal(txid)?; + let proposal = ctx.client.get_gov_proposal(txid).await?; Ok(Response::new(proposal)) } @@ -67,7 +70,7 @@ async fn get_gov_proposal( async fn list_gov_proposal_votes( Path(proposal_id): Path, Query(query): Query, - Extension(services): Extension>, + Extension(ctx): Extension>, ) -> Result> { let proposal_id: Txid = proposal_id .parse() @@ -96,7 +99,7 @@ async fn list_gov_proposal_votes( aggregate: None, valid: None, }; - let votes = services.client.list_gov_proposal_votes(Some(opts))?; + let votes = ctx.client.list_gov_proposal_votes(Some(opts)).await?; let len = votes.len(); Ok(ApiPagedResponse::of(votes, size, |_| { if let Some(next) = start { @@ -107,10 +110,10 @@ async fn list_gov_proposal_votes( })) } -pub fn router(services: Arc) -> Router { +pub fn router(ctx: Arc) -> Router { Router::new() .route("/proposals", get(list_gov_proposals)) .route("/proposals/:id", get(get_gov_proposal)) .route("/proposals/:id/votes", get(list_gov_proposal_votes)) - .layer(Extension(services)) + .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index 0a3bd11538c..936abc40432 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -107,7 +107,7 @@ async fn list_auction() -> String { "List of auctions".to_string() } -pub fn router(services: Arc) -> Router { +pub fn router(ctx: Arc) -> Router { Router::new() .route("/schemes", get(list_scheme)) .route("/schemes/:id", get(get_scheme)) diff --git a/lib/ain-ocean/src/api/masternode.rs b/lib/ain-ocean/src/api/masternode.rs index f00994c5b72..3af053cdf11 100644 --- a/lib/ain-ocean/src/api/masternode.rs +++ b/lib/ain-ocean/src/api/masternode.rs @@ -142,7 +142,7 @@ async fn get_masternode(Path(masternode_id): Path) -> Result) -> Router { +pub fn router(ctx: Arc) -> Router { Router::new() .route("/", get(list_masternodes)) .route("/:id", get(get_masternode)) diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index 1aff6f7f50b..d2be5ebb068 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -18,9 +18,10 @@ mod response; mod tokens; // mod transactions; use axum::routing::get; +use defichain_rpc::{Auth, Client}; use serde::{Deserialize, Serialize}; -use crate::{Result, SERVICES}; +use crate::{Result, Services}; async fn ocean_not_activated() -> impl IntoResponse { (StatusCode::FORBIDDEN, "Ocean is not activated") @@ -49,26 +50,41 @@ async fn not_found(req: Request) -> impl IntoResponse { ) } -pub fn ocean_router() -> Result { - if !ain_cpp_imports::is_ocean_rest_enabled() { - return Ok(Router::new().route("/*path", get(ocean_not_activated))); - } +pub struct AppContext { + services: Arc, + client: Client, +} + +pub async fn ocean_router(services: &Arc) -> Result { + // if !ain_cpp_imports::is_ocean_rest_enabled() { + // return Ok(Router::new().route("/*path", get(ocean_not_activated))); + // } + + let (user, pass) = ain_cpp_imports::get_rpc_auth()?; + let client = Client::new( + &format!("localhost:{}", ain_cpp_imports::get_rpc_port()), + Auth::UserPass(user, pass), + ) + .await?; - let services = &SERVICES; + let context = Arc::new(AppContext { + client, + services: services.clone(), + }); Ok(Router::new() - // .nest("/address", address::router(Arc::clone(services))) - .nest("/governance", governance::router(Arc::clone(services))) - // .nest("/loans", loan::router(Arc::clone(services))) - .nest("/fee", fee::router(Arc::clone(services))) - // .nest("/masternodes", masternode::router(Arc::clone(services))) - // .nest("/oracles", oracle::router(Arc::clone(services))) - // .nest("/poolpairs", poolpairs::router(Arc::clone(services))) - // .nest("/prices", prices::router(Arc::clone(services))) - // .nest("/rawtx", rawtx::router(Arc::clone(services))) - // .nest("/stats", stats::router(Arc::clone(services))) - .nest("/tokens", tokens::router(Arc::clone(services))) - // .nest("/transactions", transactions::router(Arc::clone(services))) - .nest("/blocks", block::router(Arc::clone(services))) + // .nest("/address", address::router(Arc::clone(&context))) + .nest("/governance", governance::router(Arc::clone(&context))) + // .nest("/loans", loan::router(Arc::clone(&context))) + .nest("/fee", fee::router(Arc::clone(&context))) + // .nest("/masternodes", masternode::router(Arc::clone(&context))) + // .nest("/oracles", oracle::router(Arc::clone(&context))) + // .nest("/poolpairs", poolpairs::router(Arc::clone(&context))) + // .nest("/prices", prices::router(Arc::clone(&context))) + // .nest("/rawtx", rawtx::router(Arc::clone(&context))) + // .nest("/stats", stats::router(Arc::clone(&context))) + .nest("/tokens", tokens::router(Arc::clone(&context))) + // .nest("/transactions", transactions::router(Arc::clone(&context))) + .nest("/blocks", block::router(Arc::clone(&context))) .fallback(not_found)) } diff --git a/lib/ain-ocean/src/api/oracle.rs b/lib/ain-ocean/src/api/oracle.rs index 902d221314f..95655d6f74e 100644 --- a/lib/ain-ocean/src/api/oracle.rs +++ b/lib/ain-ocean/src/api/oracle.rs @@ -15,7 +15,7 @@ async fn get_oracle_by_address(Path(address): Path) -> String { format!("Oracle details for address {}", address) } -pub fn router(services: Arc) -> Router { +pub fn router(ctx: Arc) -> Router { Router::new() .route("/", get(list_oracles)) .route("/:oracleId/:key/feed", get(get_price_feed)) diff --git a/lib/ain-ocean/src/api/poolpairs.rs b/lib/ain-ocean/src/api/poolpairs.rs index be0e514921c..89a42372034 100644 --- a/lib/ain-ocean/src/api/poolpairs.rs +++ b/lib/ain-ocean/src/api/poolpairs.rs @@ -195,7 +195,7 @@ async fn list_dex_prices(Query(DexPrices { denomination }): Query) -> format!("List of DEX prices with denomination {:?}", denomination) } -pub fn router(services: Arc) -> Router { +pub fn router(ctx: Arc) -> Router { Router::new() .route("/", get(list_poolpairs)) .route("/:id", get(get_poolpair)) diff --git a/lib/ain-ocean/src/api/prices.rs b/lib/ain-ocean/src/api/prices.rs index 4739886898f..b38aaf43de4 100644 --- a/lib/ain-ocean/src/api/prices.rs +++ b/lib/ain-ocean/src/api/prices.rs @@ -41,7 +41,7 @@ async fn get_oracles(Path(PriceKey { key }): Path) -> String { format!("Oracles for price with key {}", key) } -pub fn router(services: Arc) -> Router { +pub fn router(ctx: Arc) -> Router { Router::new() .route("/", get(list_prices)) .route("/:key", get(get_price)) diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index 954afd7f398..1902d46c2e8 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -19,7 +19,7 @@ async fn get_rawtx(Path(txid): Path) -> String { format!("Details of raw transaction with txid {}", txid) } -pub fn router(services: Arc) -> Router { +pub fn router(ctx: Arc) -> Router { Router::new() .route("/send", post(send_rawtx)) .route("/test", get(test_rawtx)) diff --git a/lib/ain-ocean/src/api/tokens.rs b/lib/ain-ocean/src/api/tokens.rs index 26494970f5b..7504e13a3ca 100644 --- a/lib/ain-ocean/src/api/tokens.rs +++ b/lib/ain-ocean/src/api/tokens.rs @@ -12,6 +12,7 @@ use serde_json::json; use super::{ common::parse_display_symbol, response::{ApiPagedResponse, Response}, + AppContext, }; use crate::{ api_query::{PaginationQuery, Query}, @@ -90,9 +91,9 @@ impl TokenData { #[ocean_endpoint] async fn list_tokens( Query(query): Query, - Extension(services): Extension>, + Extension(ctx): Extension>, ) -> Result> { - let tokens: TokenResult = services.client.call( + let tokens: TokenResult = ctx.client.call( "listtokens", &[ json!({ @@ -102,7 +103,7 @@ async fn list_tokens( }), true.into(), ], - )?; + ).await?; let res = tokens .0 @@ -115,9 +116,9 @@ async fn list_tokens( #[ocean_endpoint] async fn get_token( Path(id): Path, - Extension(services): Extension>, + Extension(ctx): Extension>, ) -> Result>> { - let mut v: TokenResult = services.client.call("gettoken", &[id.into()])?; + let mut v: TokenResult = ctx.client.call("gettoken", &[id.into()]).await?; let res = if let Some(token) = v.0.remove(&id) { Some(TokenData::from_with_id(id, token)) @@ -128,9 +129,9 @@ async fn get_token( Ok(Response::new(res)) } -pub fn router(services: Arc) -> Router { +pub fn router(ctx: Arc) -> Router { Router::new() .route("/", get(list_tokens)) .route("/:id", get(get_token)) - .layer(Extension(services)) + .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/api/transactions.rs b/lib/ain-ocean/src/api/transactions.rs index 2380d963740..4f566813c1c 100644 --- a/lib/ain-ocean/src/api/transactions.rs +++ b/lib/ain-ocean/src/api/transactions.rs @@ -82,7 +82,7 @@ async fn get_vouts( ))) } -pub fn router(services: Arc) -> Router { +pub fn router(ctx: Arc) -> Router { Router::new() .route("/:id", get(get_transaction)) .route("/:id/vins", get(get_vins)) diff --git a/lib/ain-ocean/src/api_query.rs b/lib/ain-ocean/src/api_query.rs index d5cfcdebae5..5fff3e73c94 100644 --- a/lib/ain-ocean/src/api_query.rs +++ b/lib/ain-ocean/src/api_query.rs @@ -31,12 +31,8 @@ where { let v: Option = Deserialize::deserialize(d)?; match v { - Some(v) => if v.as_str() == "undefined" { - Ok(None) - } else { - Ok(Some(v)) - }, - None => Ok(None) + Some(v) if v.as_str() != "undefined" => Ok(Some(v)), + _ => Ok(None), } } diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 44fcb2c80e7..5e3fea18750 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -104,7 +104,9 @@ impl IntoResponse for ApiError { impl OceanError { pub fn into_code_and_message(self) -> (StatusCode, String) { let (code, reason) = match self { - OceanError::RpcError(defichain_rpc::Error::JsonRpc(jsonrpc::error::Error::Rpc(e))) => { + OceanError::RpcError(defichain_rpc::Error::JsonRpc( + jsonrpc_async::error::Error::Rpc(e), + )) => { debug!("e : {:?}", e); (StatusCode::NOT_FOUND, format!("{}", e.message)) diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index dde891a6527..0320f718172 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -17,7 +17,6 @@ pub mod api; mod model; mod repository; pub mod storage; -use defichain_rpc::{Auth, Client}; use crate::storage::ocean_store::OceanStore; @@ -26,20 +25,10 @@ pub type Result = std::result::Result; lazy_static::lazy_static! { // Global services exposed by the library pub static ref SERVICES: Arc = { - let services = || { - let datadir = ain_cpp_imports::get_datadir(); - let store = Arc::new(OceanStore::new(&PathBuf::from(datadir))?); + let datadir = ain_cpp_imports::get_datadir(); + let store = Arc::new(OceanStore::new(&PathBuf::from(datadir)).expect("Error initialization Ocean services")); - let (user, pass) = ain_cpp_imports::get_rpc_auth()?; - let client = Arc::new(Client::new( - &format!("localhost:{}", ain_cpp_imports::get_rpc_port()), - Auth::UserPass(user, pass), - )?); - - Services::new(client, store) - }; - - Arc::new(services().expect("Error initialization Ocean services")) + Arc::new(Services::new(store)) }; } @@ -76,13 +65,12 @@ pub struct Services { pub auction: AuctionService, pub result: TxResultRepository, pub pool: PoolService, - pub client: Arc, pub transaction: TransactionService, } impl Services { - pub fn new(client: Arc, store: Arc) -> Result { - Ok(Self { + pub fn new(store: Arc) -> Self { + Self { masternode: MasternodeService { by_id: MasternodeRepository::new(Arc::clone(&store)), by_height: MasternodeByHeightRepository::new(Arc::clone(&store)), @@ -106,7 +94,6 @@ impl Services { vin_by_id: TransactionVinRepository::new(Arc::clone(&store)), vout_by_id: TransactionVoutRepository::new(Arc::clone(&store)), }, - client, - }) + } } } From 27578f6aa930610aade1f5b7591f4366b4ab5099 Mon Sep 17 00:00:00 2001 From: jouzo Date: Thu, 8 Feb 2024 09:13:32 +0100 Subject: [PATCH 046/185] Format rs --- lib/ain-evm/src/subscription.rs | 3 ++- lib/ain-rs-exports/src/core.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/ain-evm/src/subscription.rs b/lib/ain-evm/src/subscription.rs index 859ab4994ac..a34cad1acdb 100644 --- a/lib/ain-evm/src/subscription.rs +++ b/lib/ain-evm/src/subscription.rs @@ -1,7 +1,8 @@ -use crate::Result; use ethereum_types::H256; use tokio::sync::broadcast::{self, Sender}; +use crate::Result; + pub const NOTIFICATION_CHANNEL_BUFFER_SIZE: usize = 10_000; #[derive(Clone)] diff --git a/lib/ain-rs-exports/src/core.rs b/lib/ain-rs-exports/src/core.rs index 91209548ec5..e5b78e61bea 100644 --- a/lib/ain-rs-exports/src/core.rs +++ b/lib/ain-rs-exports/src/core.rs @@ -1,7 +1,8 @@ -use crate::{ffi, prelude::*}; use ain_macros::ffi_fallible; use anyhow::Result; +use crate::{ffi, prelude::*}; + #[ffi_fallible] pub fn ain_rs_preinit() -> Result<()> { ain_grpc::preinit(); From 2c3cf357cef667f9f70950c9613596c8d266fdd0 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Fri, 9 Feb 2024 09:26:48 +0100 Subject: [PATCH 047/185] Stats API initial impl (#2819) --- lib/Cargo.lock | 312 ++++++++++-------- lib/Cargo.toml | 2 +- lib/ain-cpp-imports/src/lib.rs | 5 +- lib/ain-grpc/Cargo.toml | 1 + lib/ain-grpc/src/lib.rs | 14 +- lib/ain-ocean/Cargo.toml | 9 +- lib/ain-ocean/src/api/common.rs | 39 +++ lib/ain-ocean/src/api/governance.rs | 6 +- lib/ain-ocean/src/api/mod.rs | 23 +- lib/ain-ocean/src/api/stats.rs | 28 -- lib/ain-ocean/src/api/stats/distribution.rs | 44 +++ lib/ain-ocean/src/api/stats/mod.rs | 192 +++++++++++ lib/ain-ocean/src/api/stats/stats.rs | 298 +++++++++++++++++ lib/ain-ocean/src/api/stats/subsidy.rs | 133 ++++++++ lib/ain-ocean/src/error.rs | 22 +- lib/ain-ocean/src/indexer/masternode.rs | 47 ++- lib/ain-ocean/src/lib.rs | 4 +- lib/ain-ocean/src/model/masternode.rs | 3 +- lib/ain-ocean/src/model/masternode_stats.rs | 19 +- .../src/repository/masternode_stats.rs | 12 +- .../src/storage/columns/masternode_stats.rs | 19 +- 21 files changed, 1002 insertions(+), 230 deletions(-) delete mode 100644 lib/ain-ocean/src/api/stats.rs create mode 100644 lib/ain-ocean/src/api/stats/distribution.rs create mode 100644 lib/ain-ocean/src/api/stats/mod.rs create mode 100644 lib/ain-ocean/src/api/stats/stats.rs create mode 100644 lib/ain-ocean/src/api/stats/subsidy.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 74265fd7286..b14769c20fe 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -177,6 +177,7 @@ dependencies = [ "async-trait", "axum 0.7.4", "cxx", + "defichain-rpc", "env_logger", "ethereum", "ethereum-types", @@ -235,7 +236,6 @@ dependencies = [ "bitcoin_hashes 0.12.0", "cached", "chrono", - "ctrlc", "defichain-rpc", "dftx-rs", "futures", @@ -248,12 +248,12 @@ dependencies = [ "lazy_static", "log", "rocksdb", + "rust_decimal", + "rust_decimal_macros", "serde", "serde_json", "serde_urlencoded", "serde_with", - "structopt", - "tarpc", "tempdir", "tempfile", "thiserror", @@ -802,6 +802,30 @@ dependencies = [ "byte-tools", ] +[[package]] +name = "borsh" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d4d6dafc1a3bb54687538972158f07b2c948bc57d5890df22c0739098b3028" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4918709cc4dd777ad2b6303ed03cb37f3ca0ccede8c1b0d28ac6db8f4710e0" +dependencies = [ + "once_cell", + "proc-macro-crate 2.0.2", + "proc-macro2", + "quote", + "syn 2.0.48", + "syn_derive", +] + [[package]] name = "bounded-collections" version = "0.1.9" @@ -869,6 +893,28 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "bytemuck" version = "1.14.2" @@ -913,24 +959,27 @@ dependencies = [ [[package]] name = "cached" -version = "0.46.1" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c8c50262271cdf5abc979a5f76515c234e764fa025d1ba4862c0f0bcda0e95" +checksum = "355face540df58778b96814c48abb3c2ed67c4878a8087ab1819c1fedeec505f" dependencies = [ "ahash 0.8.7", + "async-trait", "cached_proc_macro", "cached_proc_macro_types", + "futures", "hashbrown 0.14.3", "instant", "once_cell", "thiserror", + "tokio", ] [[package]] name = "cached_proc_macro" -version = "0.18.1" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c878c71c2821aa2058722038a59a67583a4240524687c6028571c9b395ded61f" +checksum = "9d52f526f7cbc875b296856ca8c964a9f6290556922c303a8a3883e3c676e6a1" dependencies = [ "darling 0.14.4", "proc-macro2", @@ -969,6 +1018,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "chrono" version = "0.4.33" @@ -1113,15 +1168,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -1195,16 +1241,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ctrlc" -version = "3.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b" -dependencies = [ - "nix", - "windows-sys 0.52.0", -] - [[package]] name = "curve25519-dalek" version = "2.1.3" @@ -3376,17 +3412,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" -[[package]] -name = "nix" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" -dependencies = [ - "bitflags 2.4.2", - "cfg-if", - "libc", -] - [[package]] name = "nohash-hasher" version = "0.2.0" @@ -3597,49 +3622,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" -[[package]] -name = "opentelemetry" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d6c3d7288a106c0a363e4b0e8d308058d56902adefb16f4936f417ffef086e" -dependencies = [ - "opentelemetry_api", - "opentelemetry_sdk", -] - -[[package]] -name = "opentelemetry_api" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c24f96e21e7acc813c7a8394ee94978929db2bcc46cf6b5014fc612bf7760c22" -dependencies = [ - "futures-channel", - "futures-util", - "indexmap 1.9.3", - "js-sys", - "once_cell", - "pin-project-lite", - "thiserror", -] - -[[package]] -name = "opentelemetry_sdk" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca41c4933371b61c2a2f214bf16931499af4ec90543604ec828f7a625c09113" -dependencies = [ - "async-trait", - "crossbeam-channel", - "futures-channel", - "futures-executor", - "futures-util", - "once_cell", - "opentelemetry_api", - "percent-encoding", - "rand 0.8.5", - "thiserror", -] - [[package]] name = "option-ext" version = "0.2.0" @@ -4045,6 +4027,26 @@ dependencies = [ "cc", ] +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "quote" version = "1.0.35" @@ -4312,6 +4314,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + [[package]] name = "reqwest" version = "0.11.24" @@ -4386,6 +4397,35 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "rkyv" +version = "0.7.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "rlp" version = "0.5.2" @@ -4428,6 +4468,32 @@ dependencies = [ "time", ] +[[package]] +name = "rust_decimal" +version = "1.34.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "755392e1a2f77afd95580d3f0d0e94ac83eeeb7167552c9b5bca549e61a94d83" +dependencies = [ + "arrayvec 0.7.4", + "borsh", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", +] + +[[package]] +name = "rust_decimal_macros" +version = "1.34.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e418701588729bef95e7a655f2b483ad64bb97c46e8e79fde83efd92aaab6d82" +dependencies = [ + "quote", + "rust_decimal", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -4651,6 +4717,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + [[package]] name = "sec1" version = "0.7.3" @@ -4965,6 +5037,12 @@ dependencies = [ "wide", ] +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + [[package]] name = "siphasher" version = "0.3.11" @@ -5243,7 +5321,7 @@ dependencies = [ "sp-std", "tracing", "tracing-core", - "tracing-subscriber 0.2.25", + "tracing-subscriber", ] [[package]] @@ -5494,6 +5572,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "sync_wrapper" version = "0.1.2" @@ -5533,41 +5623,6 @@ version = "0.12.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae" -[[package]] -name = "tarpc" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f41bce44d290df0598ae4b9cd6ea7f58f651fd3aa4af1b26060c4fa32b08af7" -dependencies = [ - "anyhow", - "fnv", - "futures", - "humantime", - "opentelemetry", - "pin-project", - "rand 0.8.5", - "serde", - "static_assertions", - "tarpc-plugins", - "thiserror", - "tokio", - "tokio-serde", - "tokio-util", - "tracing", - "tracing-opentelemetry", -] - -[[package]] -name = "tarpc-plugins" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee42b4e559f17bce0385ebf511a7beb67d5cc33c12c96b7f4e9789919d9c10f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "tempdir" version = "0.3.7" @@ -5816,7 +5871,6 @@ dependencies = [ "futures-io", "futures-sink", "pin-project-lite", - "slab", "tokio", "tracing", ] @@ -5996,19 +6050,6 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-opentelemetry" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21ebb87a95ea13271332df069020513ab70bdb5637ca42d6e492dc3bbbad48de" -dependencies = [ - "once_cell", - "opentelemetry", - "tracing", - "tracing-core", - "tracing-subscriber 0.3.18", -] - [[package]] name = "tracing-serde" version = "0.1.3" @@ -6041,17 +6082,6 @@ dependencies = [ "tracing-serde", ] -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "sharded-slab", - "thread_local", - "tracing-core", -] - [[package]] name = "trie-db" version = "0.27.1" diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 77e20409002..2da7c1c154d 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -121,7 +121,7 @@ substrate-bn = "0.6" #### Ocean dependencies dftx-rs = { git = "https://github.com/Jouzo/dftx-rs.git" } bitcoin = "0.31" -cached = "0.46" +cached = { version = "0.48", features = ["async"] } defichain-rpc = { version = "0.18.0", git = "https://github.com/Jouzo/rust-defichain-rpc.git" } ### Local crates diff --git a/lib/ain-cpp-imports/src/lib.rs b/lib/ain-cpp-imports/src/lib.rs index a5550a7fbaf..1540d80127c 100644 --- a/lib/ain-cpp-imports/src/lib.rs +++ b/lib/ain-cpp-imports/src/lib.rs @@ -157,10 +157,7 @@ pub fn get_rpc_auth() -> Result<(String, String), Box> { .as_slice() { [user, pass] => Ok((user.clone(), pass.clone())), - yo => { - println!("yo : {:?}", yo); - Err("Error getting user and password".into()) - } + _ => Err("Error getting user and password".into()), } } diff --git a/lib/ain-grpc/Cargo.toml b/lib/ain-grpc/Cargo.toml index 87bf61c0ede..ecf2874bae4 100644 --- a/lib/ain-grpc/Cargo.toml +++ b/lib/ain-grpc/Cargo.toml @@ -37,6 +37,7 @@ tower.workspace = true hyper.workspace = true rand.workspace = true axum.workspace = true +defichain-rpc.workspace = true [build-dependencies] heck.workspace = true diff --git a/lib/ain-grpc/src/lib.rs b/lib/ain-grpc/src/lib.rs index 474e0f5c31b..9c2ce3c16f6 100644 --- a/lib/ain-grpc/src/lib.rs +++ b/lib/ain-grpc/src/lib.rs @@ -19,6 +19,8 @@ mod utils; mod subscription; +use defichain_rpc::{Auth, Client}; + #[cfg(test)] mod tests; @@ -118,7 +120,17 @@ pub async fn init_ocean_server(addr: String) -> Result<()> { let runtime = &SERVICES; let listener = tokio::net::TcpListener::bind(addr).await?; - let ocean_router = ain_ocean::ocean_router(&*OCEAN_SERVICES).await?; + + let (user, pass) = ain_cpp_imports::get_rpc_auth().map_err(|e| format_err!("{e}"))?; + let client = Arc::new( + Client::new( + &format!("localhost:{}", ain_cpp_imports::get_rpc_port()), + Auth::UserPass(user, pass), + ) + .await?, + ); + + let ocean_router = ain_ocean::ocean_router(&*OCEAN_SERVICES, client).await?; let server_handle = runtime.tokio_runtime.spawn(async move { if let Err(e) = axum::serve(listener, ocean_router).await { diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index d27bf0cd5cc..3298ce925a0 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -22,18 +22,15 @@ thiserror.workspace = true hex.workspace = true dftx-rs.workspace = true bitcoin = { workspace = true, features = ["serde"] } -tarpc = { version = "0.33", features = ["tokio1", "serde1", "serde-transport","tcp"] } tokio = { version = "1", features = ["full"] } serde_json = "1.0" json = "0.12.4" -tokio-serde = {version="0.8.0"} +tokio-serde = { version="0.8.0"} futures = "0.3.29" -jsonrpsee = { workspace = true, features = ["server", "macros", "http-client", "jsonrpsee-server"] } +jsonrpsee.workspace = true rocksdb = "0.21.0" -ctrlc = "3.1.9" tempdir = "0.3.7" bitcoin_hashes = "0.12.0" -structopt = { version = "0.3", default-features = false } tempfile = "3.8.1" anyhow.workspace = true chrono = "0.4.31" @@ -43,3 +40,5 @@ bincode.workspace = true defichain-rpc.workspace = true jsonrpc-async = "2.0.2" serde_urlencoded = "0.7" +rust_decimal = { version = "1.34", features = ["serde-float"] } +rust_decimal_macros = "1.34" diff --git a/lib/ain-ocean/src/api/common.rs b/lib/ain-ocean/src/api/common.rs index 9b822f49bbf..5e8c9be819e 100644 --- a/lib/ain-ocean/src/api/common.rs +++ b/lib/ain-ocean/src/api/common.rs @@ -1,4 +1,5 @@ use defichain_rpc::json::token::TokenInfo; +use rust_decimal::Decimal; pub fn parse_display_symbol(token_info: &TokenInfo) -> String { if token_info.is_lps { @@ -26,3 +27,41 @@ fn parse_dat_symbol(symbol: &str) -> String { format!("d{}", symbol) } } + +/// Finds the balance of a specified token symbol within a list of token strings. +/// +/// This function iterates through a vector of token strings, where each string +/// represents an amount followed by a token symbol in the format "amount@symbol". +/// It searches for the specified token symbol and returns the corresponding balance. +/// If the token symbol is not found or if there are any parsing errors, it returns 0. +/// +/// # Arguments +/// +/// * `tokens` - A vector of strings representing token amounts with their symbols. +/// * `symbol` - A reference to a string representing the token symbol to find the balance for. +/// +/// # Examples +/// +/// ``` +/// let tokens = vec![ +/// "557.35080849@DFI".to_string(), +/// "9.98000000@BTC".to_string(), +/// "421.46947098@DUSD".to_string() +/// ]; +/// let balance = find_token_balance(tokens, "DFI"); +/// assert_eq!(balance, 557.35080849); +/// ``` +/// +/// # Returns +/// +/// The balance of the specified token symbol if found; otherwise, returns 0. +pub fn find_token_balance(tokens: Vec, symbol: &str) -> Decimal { + tokens + .iter() + .find_map(|t| { + t.ends_with(symbol) + .then(|| t.split("@").next().and_then(|v| v.parse::().ok())) + .flatten() + }) + .unwrap_or_default() +} diff --git a/lib/ain-ocean/src/api/governance.rs b/lib/ain-ocean/src/api/governance.rs index 2b94ef18315..d09e1163d74 100644 --- a/lib/ain-ocean/src/api/governance.rs +++ b/lib/ain-ocean/src/api/governance.rs @@ -12,7 +12,7 @@ use super::{ }; use crate::{ api_query::{PaginationQuery, Query}, - error::{ApiError, NotFoundKind, OceanError}, + error::{ApiError, Error, NotFoundKind}, Result, Services, }; @@ -60,7 +60,7 @@ async fn get_gov_proposal( ) -> Result> { let txid: Txid = proposal_id .parse() - .map_err(|_| OceanError::NotFound(NotFoundKind::Proposal))?; + .map_err(|_| Error::NotFound(NotFoundKind::Proposal))?; let proposal = ctx.client.get_gov_proposal(txid).await?; Ok(Response::new(proposal)) @@ -74,7 +74,7 @@ async fn list_gov_proposal_votes( ) -> Result> { let proposal_id: Txid = proposal_id .parse() - .map_err(|_| OceanError::NotFound(NotFoundKind::Proposal))?; + .map_err(|_| Error::NotFound(NotFoundKind::Proposal))?; let size = match query.all { Some(true) => 0, diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index d2be5ebb068..54b200e7295 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -12,13 +12,13 @@ mod governance; // mod poolpairs; // mod prices; // mod rawtx; -// mod stats; mod common; mod response; +mod stats; mod tokens; // mod transactions; -use axum::routing::get; -use defichain_rpc::{Auth, Client}; + +use defichain_rpc::Client; use serde::{Deserialize, Serialize}; use crate::{Result, Services}; @@ -52,21 +52,10 @@ async fn not_found(req: Request) -> impl IntoResponse { pub struct AppContext { services: Arc, - client: Client, + client: Arc, } -pub async fn ocean_router(services: &Arc) -> Result { - // if !ain_cpp_imports::is_ocean_rest_enabled() { - // return Ok(Router::new().route("/*path", get(ocean_not_activated))); - // } - - let (user, pass) = ain_cpp_imports::get_rpc_auth()?; - let client = Client::new( - &format!("localhost:{}", ain_cpp_imports::get_rpc_port()), - Auth::UserPass(user, pass), - ) - .await?; - +pub async fn ocean_router(services: &Arc, client: Arc) -> Result { let context = Arc::new(AppContext { client, services: services.clone(), @@ -82,7 +71,7 @@ pub async fn ocean_router(services: &Arc) -> Result { // .nest("/poolpairs", poolpairs::router(Arc::clone(&context))) // .nest("/prices", prices::router(Arc::clone(&context))) // .nest("/rawtx", rawtx::router(Arc::clone(&context))) - // .nest("/stats", stats::router(Arc::clone(&context))) + .nest("/stats", stats::router(Arc::clone(&context))) .nest("/tokens", tokens::router(Arc::clone(&context))) // .nest("/transactions", transactions::router(Arc::clone(&context))) .nest("/blocks", block::router(Arc::clone(&context))) diff --git a/lib/ain-ocean/src/api/stats.rs b/lib/ain-ocean/src/api/stats.rs deleted file mode 100644 index e7c8194e116..00000000000 --- a/lib/ain-ocean/src/api/stats.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::sync::Arc; - -use axum::{routing::get, Router}; -use defichain_rpc::{Client, RpcApi}; - -async fn get_stats() -> String { - "General stats".to_string() -} - -async fn get_reward_distribution() -> String { - "Reward distribution stats".to_string() -} - -async fn get_supply() -> String { - "Supply stats".to_string() -} - -async fn get_burn() -> String { - "Burn stats".to_string() -} - -pub fn router(services: Arc) -> Router { - Router::new() - .route("/", get(get_stats)) - .route("/rewards/distribution", get(get_reward_distribution)) - .route("/supply", get(get_supply)) - .route("/burn", get(get_burn)) -} diff --git a/lib/ain-ocean/src/api/stats/distribution.rs b/lib/ain-ocean/src/api/stats/distribution.rs new file mode 100644 index 00000000000..580e731b3bd --- /dev/null +++ b/lib/ain-ocean/src/api/stats/distribution.rs @@ -0,0 +1,44 @@ +use rust_decimal::Decimal; +use rust_decimal_macros::dec; + +use crate::api::stats::COIN; + +#[derive(Debug)] +pub struct BlockRewardDistribution { + pub masternode: Decimal, + pub community: Decimal, + pub anchor: Decimal, + pub liquidity: Decimal, + pub loan: Decimal, + pub options: Decimal, + pub unallocated: Decimal, +} + +pub const BLOCK_REWARD_DISTRIBUTION_PERCENTAGE: BlockRewardDistribution = BlockRewardDistribution { + masternode: dec!(3333), + community: dec!(491), + anchor: dec!(2), + liquidity: dec!(2545), + loan: dec!(2468), + options: dec!(988), + unallocated: dec!(173), +}; + +/** + * Get block reward distribution from block base subsidy + */ +pub fn get_block_reward_distribution(subsidy: Decimal) -> BlockRewardDistribution { + BlockRewardDistribution { + masternode: calculate_reward(subsidy, BLOCK_REWARD_DISTRIBUTION_PERCENTAGE.masternode), + community: calculate_reward(subsidy, BLOCK_REWARD_DISTRIBUTION_PERCENTAGE.community), + anchor: calculate_reward(subsidy, BLOCK_REWARD_DISTRIBUTION_PERCENTAGE.anchor), + liquidity: calculate_reward(subsidy, BLOCK_REWARD_DISTRIBUTION_PERCENTAGE.liquidity), + loan: calculate_reward(subsidy, BLOCK_REWARD_DISTRIBUTION_PERCENTAGE.loan), + options: calculate_reward(subsidy, BLOCK_REWARD_DISTRIBUTION_PERCENTAGE.options), + unallocated: calculate_reward(subsidy, BLOCK_REWARD_DISTRIBUTION_PERCENTAGE.unallocated), + } +} + +fn calculate_reward(amount: Decimal, percent: Decimal) -> Decimal { + (amount * percent) / dec!(10000) / COIN +} diff --git a/lib/ain-ocean/src/api/stats/mod.rs b/lib/ain-ocean/src/api/stats/mod.rs new file mode 100644 index 00000000000..6b03851143d --- /dev/null +++ b/lib/ain-ocean/src/api/stats/mod.rs @@ -0,0 +1,192 @@ +mod distribution; +mod stats; +mod subsidy; + +use std::sync::Arc; + +use ain_macros::ocean_endpoint; +use axum::{routing::get, Extension, Router}; +use defichain_rpc::{ + defichain_rpc_json::{account::BurnInfo, GetNetworkInfoResult}, + AccountRPC, RpcApi, +}; +use rust_decimal::{prelude::FromPrimitive, Decimal}; +use rust_decimal_macros::dec; +use serde::{Deserialize, Serialize}; + +use self::{ + distribution::get_block_reward_distribution, + stats::{ + get_burned, get_count, get_emission, get_loan, get_masternodes, get_tvl, Burned, Count, + Emission, Loan, Masternodes, Tvl, + }, +}; +use super::{response::Response, AppContext}; +use crate::{ + api::stats::{stats::get_burned_total, subsidy::BLOCK_SUBSIDY}, + error::{ApiError, Error}, + Result, +}; + +const COIN: Decimal = dec!(100_000_000); + +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct StatsData { + pub count: Count, + pub tvl: Tvl, + pub burned: Burned, + pub price: Price, + pub masternodes: Masternodes, + pub emission: Emission, + pub loan: Loan, + pub blockchain: Blockchain, + pub net: Net, +} + +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct Price { + pub usd: f64, + #[deprecated(note = "use USD instead of aggregation over multiple pairs")] + pub usdt: f64, +} + +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct Blockchain { + pub difficulty: f64, +} + +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct Net { + pub version: u64, + pub subversion: String, + pub protocolversion: u64, +} + +#[ocean_endpoint] +async fn get_stats(Extension(ctx): Extension>) -> Result> { + let (height, difficulty) = ctx + .services + .block + .by_height + .get_highest()? + .map(|b| (b.height, b.difficulty)) + .unwrap_or_default(); // Default to genesis block + + let GetNetworkInfoResult { + version, + subversion, + protocol_version, + .. + } = ctx.client.get_network_info().await?; + + let stats = StatsData { + burned: get_burned(&ctx.client).await?, + net: Net { + version: version as u64, + protocolversion: protocol_version as u64, + subversion, + }, + count: Count { + blocks: height, + ..get_count(&ctx).await? + }, + emission: get_emission(height)?, + blockchain: Blockchain { difficulty }, + loan: get_loan(&ctx.client).await?, + // price: todo!(), + masternodes: get_masternodes(&ctx.services)?, + tvl: get_tvl(&ctx).await?, + ..Default::default() + }; + Ok(Response::new(stats)) +} + +#[derive(Debug, Serialize, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct RewardDistributionData { + anchor: Decimal, + community: Decimal, + liquidity: Decimal, + loan: Decimal, + masternode: Decimal, + options: Decimal, + unallocated: Decimal, +} + +#[ocean_endpoint] +async fn get_reward_distribution( + Extension(ctx): Extension>, +) -> Result> { + let height = ctx + .services + .block + .by_height + .get_highest()? + .map(|b| b.height) + .unwrap_or_default(); // Default to genesis block + + let subsidy = + Decimal::from_u64(BLOCK_SUBSIDY.get_block_subsidy(height)).ok_or(Error::DecimalError)?; + let distribution = get_block_reward_distribution(subsidy); + + let distribution = RewardDistributionData { + masternode: distribution.masternode.trunc_with_scale(8), + anchor: distribution.anchor.trunc_with_scale(8), + community: distribution.community.trunc_with_scale(8), + liquidity: distribution.liquidity.trunc_with_scale(8), + loan: distribution.loan.trunc_with_scale(8), + options: distribution.options.trunc_with_scale(8), + unallocated: distribution.unallocated.trunc_with_scale(8), + }; + Ok(Response::new(distribution)) +} + +#[derive(Debug, Serialize, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct SupplyData { + max: u32, + total: Decimal, + burned: Decimal, + circulating: Decimal, +} + +#[ocean_endpoint] +async fn get_supply(Extension(ctx): Extension>) -> Result> { + static MAX: u32 = 1_200_000_000; + let height = ctx + .services + .block + .by_height + .get_highest()? + .map(|b| b.height) + .unwrap_or_default(); // Default to genesis block + + let total = + Decimal::from_u64(BLOCK_SUBSIDY.get_supply(height)).ok_or(Error::DecimalError)? / COIN; + + let burned = get_burned_total(&ctx.client).await?; + let circulating = total - burned; + + let supply = SupplyData { + max: MAX, + total, + burned, + circulating, + }; + Ok(Response::new(supply)) +} + +#[ocean_endpoint] +async fn get_burn(Extension(ctx): Extension>) -> Result> { + let burn_info = ctx.client.get_burn_info().await?; + Ok(Response::new(burn_info)) +} + +pub fn router(ctx: Arc) -> Router { + Router::new() + .route("/", get(get_stats)) + .route("/rewards/distribution", get(get_reward_distribution)) + .route("/supply", get(get_supply)) + .route("/burn", get(get_burn)) + .layer(Extension(ctx)) +} diff --git a/lib/ain-ocean/src/api/stats/stats.rs b/lib/ain-ocean/src/api/stats/stats.rs new file mode 100644 index 00000000000..4eded439fc6 --- /dev/null +++ b/lib/ain-ocean/src/api/stats/stats.rs @@ -0,0 +1,298 @@ +use std::sync::Arc; + +use cached::proc_macro::cached; +use defichain_rpc::{ + defichain_rpc_json::{poolpair::PoolPairPagination, token::TokenPagination}, + AccountRPC, Client, LoanRPC, PoolPairRPC, TokenRPC, +}; +use rust_decimal::{ + prelude::{FromPrimitive, Zero}, + Decimal, +}; +use rust_decimal_macros::dec; +use serde::{Deserialize, Serialize}; + +use super::{subsidy::BLOCK_SUBSIDY, COIN}; +use crate::{ + api::{common::find_token_balance, stats::get_block_reward_distribution, AppContext}, + model::MasternodeStatsData, + Error, Result, Services, +}; + +#[derive(Debug, Serialize, Deserialize, Clone, Default)] +pub struct Burned { + pub address: Decimal, + pub fee: Decimal, + pub auction: Decimal, + pub payback: Decimal, + pub emission: Decimal, + pub total: Decimal, +} + +#[cached( + result = true, + time = 1800, + key = "String", + convert = r#"{ format!("burned") }"# +)] +pub async fn get_burned(client: &Client) -> Result { + let burn_info = client.get_burn_info().await?; + + let utxo = Decimal::from_f64(burn_info.amount).ok_or(Error::DecimalError)?; + let emission = Decimal::from_f64(burn_info.emissionburn).ok_or(Error::DecimalError)?; + let fee = Decimal::from_f64(burn_info.feeburn).ok_or(Error::DecimalError)?; + let auction = Decimal::from_f64(burn_info.auctionburn).ok_or(Error::DecimalError)?; + + let account = find_token_balance(burn_info.tokens, "DFI"); + let address = utxo + account; + let payback = find_token_balance(burn_info.paybackburn, "DFI"); + + let burned = Burned { + address, + emission, + fee, + payback, + auction, + total: address + fee + auction + payback + emission, + }; + Ok(burned) +} + +#[derive(Debug, Serialize, Deserialize, Clone, Default)] +pub struct Count { + pub blocks: u32, + pub tokens: usize, + pub prices: u64, + pub masternodes: u32, +} + +#[cached( + result = true, + time = 1800, + key = "String", + convert = r#"{ format!("count") }"# +)] +pub async fn get_count(ctx: &Arc) -> Result { + let tokens = ctx + .client + .list_tokens( + Some(TokenPagination { + limit: 1000, + ..Default::default() + }), + Some(true), + ) + .await?; + + let masternodes = ctx + .services + .masternode + .stats + .get_latest()? + .map_or(0, |mn| mn.stats.count); + + Ok(Count { + tokens: tokens.0.len(), + masternodes, + // TODO handle prices + // prices: + ..Default::default() + }) +} + +#[cached( + result = true, + time = 1800, + key = "String", + convert = r#"{ format!("burned_total") }"# +)] +pub async fn get_burned_total(client: &Client) -> Result { + static ADDRESS: &'static str = "76a914f7874e8821097615ec345f74c7e5bcf61b12e2ee88ac"; + let mut tokens = client.get_account(ADDRESS, None, Some(true)).await?; + let burn_info = client.get_burn_info().await?; + + let utxo = Decimal::from_f64(burn_info.amount).ok_or(Error::DecimalError)?; + let emission = Decimal::from_f64(burn_info.emissionburn).ok_or(Error::DecimalError)?; + let fee = Decimal::from_f64(burn_info.feeburn).ok_or(Error::DecimalError)?; + let account_balance = tokens + .0 + .remove("0") + .map_or(dec!(0), |v| Decimal::from_f64(v).unwrap_or_default()); + + Ok(utxo + account_balance + emission + fee) +} + +#[derive(Debug, Serialize, Deserialize, Default, Clone)] +pub struct Emission { + pub masternode: Decimal, + pub dex: Decimal, + pub community: Decimal, + pub anchor: Decimal, + pub burned: Decimal, + pub total: Decimal, +} + +#[cached( + result = true, + time = 1800, + key = "String", + convert = r#"{ format!("emission") }"# +)] +pub fn get_emission(height: u32) -> Result { + let subsidy = + Decimal::from_u64(BLOCK_SUBSIDY.get_block_subsidy(height)).ok_or(Error::DecimalError)?; + let distribution = get_block_reward_distribution(subsidy); + + let masternode = distribution.masternode.trunc_with_scale(8); + let dex = distribution.liquidity.trunc_with_scale(8); + let community = distribution.community.trunc_with_scale(8); + let anchor = distribution.anchor.trunc_with_scale(8); + let total = subsidy / COIN; + let burned = total - (masternode + dex + community + anchor); + + Ok(Emission { + masternode, + dex, + community, + anchor, + burned, + total, + }) +} + +#[derive(Debug, Serialize, Deserialize, Default, Clone)] +pub struct LoanCount { + pub schemes: u64, + pub loan_tokens: u64, + pub collateral_tokens: u64, + pub open_vaults: u64, + pub open_auctions: u64, +} + +#[derive(Debug, Serialize, Deserialize, Default, Clone)] +pub struct LoanValue { + pub collateral: f64, + pub loan: f64, +} + +#[derive(Debug, Serialize, Deserialize, Default, Clone)] +pub struct Loan { + pub count: LoanCount, + pub value: LoanValue, +} + +#[cached( + result = true, + time = 1800, + key = "String", + convert = r#"{ format!("loan") }"# +)] +pub async fn get_loan(client: &Client) -> Result { + let info = client.get_loan_info().await?; + + Ok(Loan { + count: LoanCount { + collateral_tokens: info.totals.collateral_tokens, + loan_tokens: info.totals.loan_tokens, + open_auctions: info.totals.open_auctions, + open_vaults: info.totals.open_vaults, + schemes: info.totals.schemes, + }, + value: LoanValue { + collateral: info.totals.collateral_value, + loan: info.totals.loan_value, + }, + }) +} + +#[derive(Debug, Serialize, Deserialize, Default, Clone)] +pub struct Locked { + pub weeks: u16, + pub tvl: Decimal, + pub count: u32, +} + +#[derive(Debug, Serialize, Deserialize, Default, Clone)] +pub struct Masternodes { + pub locked: Vec, +} + +#[cached( + result = true, + time = 1800, + key = "String", + convert = r#"{ format!("masternodes") }"# +)] +pub fn get_masternodes(services: &Services) -> Result { + let stats = services + .masternode + .stats + .get_latest()? + .map_or(MasternodeStatsData::default(), |mn| mn.stats); + + // TODO Tvl * DUSD value + Ok(Masternodes { + locked: stats + .locked + .into_iter() + .map(|(k, v)| Locked { + weeks: k, + tvl: v.tvl, + count: v.count, + }) + .collect(), + }) +} + +#[derive(Debug, Serialize, Deserialize, Default, Clone)] +pub struct Tvl { + pub total: Decimal, + pub dex: Decimal, + pub loan: f64, + pub masternodes: Decimal, +} + +#[cached( + result = true, + time = 300, + key = "String", + convert = r#"{ format!("tvl") }"# +)] +pub async fn get_tvl(ctx: &Arc) -> Result { + let mut dex = 0f64; + let pairs = ctx + .client + .list_pool_pairs( + Some(PoolPairPagination { + including_start: true, + start: 0, + limit: 1000, + }), + Some(true), + ) + .await; + + let loan = get_loan(&ctx.client).await?; + + // TODO value in DUSD + let masternodes = ctx + .services + .masternode + .stats + .get_latest()? + .map_or(Decimal::zero(), |mn| mn.stats.tvl); + + // return { + // dex: dex.toNumber(), + // masternodes: masternodeTvlUSD, + // loan: loan.value.collateral, + // total: dex.toNumber() + masternodeTvlUSD + loan.value.collateral + // } + Ok(Tvl { + loan: loan.value.collateral, + masternodes, + // TODO dex + // TODO total + ..Default::default() + }) +} diff --git a/lib/ain-ocean/src/api/stats/subsidy.rs b/lib/ain-ocean/src/api/stats/subsidy.rs new file mode 100644 index 00000000000..57c3121351b --- /dev/null +++ b/lib/ain-ocean/src/api/stats/subsidy.rs @@ -0,0 +1,133 @@ +use serde::{Deserialize, Serialize}; + +lazy_static::lazy_static! { + // TODO handle networks + // Global service caching all block subsidy reductions + pub static ref BLOCK_SUBSIDY: BlockSubsidy = BlockSubsidy::new(TEST_NET_COINBASE_SUBSIDY_OPTIONS); +} + +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] +pub struct CoinbaseSubsidyOptions { + eunos_height: u64, + genesis_block_subsidy: u64, + pre_eunos_block_subsidy: u64, + eunos_base_block_subsidy: u64, + eunos_foundation_burn: u64, + emission_reduction: u64, + emission_reduction_interval: u64, +} + +pub static MAIN_NET_COINBASE_SUBSIDY_OPTIONS: CoinbaseSubsidyOptions = CoinbaseSubsidyOptions { + eunos_height: 894000, + genesis_block_subsidy: 59100003000000000, + pre_eunos_block_subsidy: 20000000000, + eunos_base_block_subsidy: 40504000000, + eunos_foundation_burn: 26859289307829046, + emission_reduction: 1658, + emission_reduction_interval: 32690, +}; + +pub static TEST_NET_COINBASE_SUBSIDY_OPTIONS: CoinbaseSubsidyOptions = CoinbaseSubsidyOptions { + eunos_height: 354950, + genesis_block_subsidy: 30400004000000000, + pre_eunos_block_subsidy: 20000000000, + eunos_base_block_subsidy: 40504000000, + eunos_foundation_burn: 0, + emission_reduction: 1658, + emission_reduction_interval: 32690, +}; + +pub struct BlockSubsidy { + reduction_block_subsidies: Vec, + reduction_supply_milestones: Vec, + options: CoinbaseSubsidyOptions, +} + +impl BlockSubsidy { + pub fn new(options: CoinbaseSubsidyOptions) -> Self { + let reduction_block_subsidies = BlockSubsidy::compute_block_reduction_subsidies(&options); + let reduction_supply_milestones = + BlockSubsidy::compute_reduction_supply_milestones(&reduction_block_subsidies, &options); + BlockSubsidy { + reduction_block_subsidies, + reduction_supply_milestones, + options, + } + } + + pub fn get_supply(&self, height: u32) -> u64 { + let height = u64::from(height); + if height < self.options.eunos_height { + self.get_pre_eunos_supply(height) + } else { + self.get_post_eunos_supply(height) + } + } + + pub fn get_block_subsidy(&self, height: u32) -> u64 { + let height = u64::from(height); + if height == 0 { + return self.options.genesis_block_subsidy; + } + + if height < self.options.eunos_height { + return self.options.pre_eunos_block_subsidy; + } + + let reduction_count = + (height - self.options.eunos_height) / self.options.emission_reduction_interval; + if reduction_count < self.reduction_block_subsidies.len() as u64 { + return self.reduction_block_subsidies[reduction_count as usize]; + } + + 0 + } + + fn get_pre_eunos_supply(&self, height: u64) -> u64 { + self.options.genesis_block_subsidy + self.options.pre_eunos_block_subsidy * height + } + + fn get_post_eunos_supply(&self, height: u64) -> u64 { + let post_eunos_diff = height - (self.options.eunos_height - 1); + let reduction_count = post_eunos_diff / self.options.emission_reduction_interval; + let reduction_remainder = post_eunos_diff % self.options.emission_reduction_interval; + + if reduction_count >= self.reduction_supply_milestones.len() as u64 { + *self.reduction_supply_milestones.last().unwrap() + } else { + self.reduction_supply_milestones[reduction_count as usize] + + self.reduction_block_subsidies[reduction_count as usize] * reduction_remainder + } + } + + fn compute_reduction_supply_milestones( + reduction_block_subsidies: &[u64], + options: &CoinbaseSubsidyOptions, + ) -> Vec { + let mut supply_milestones = vec![ + options.genesis_block_subsidy + + options.pre_eunos_block_subsidy * (options.eunos_height - 1) + - options.eunos_foundation_burn, + ]; + for i in 1..reduction_block_subsidies.len() { + let previous_milestone = supply_milestones[i - 1]; + supply_milestones.push( + previous_milestone + + reduction_block_subsidies[i - 1] * options.emission_reduction_interval, + ); + } + supply_milestones + } + + fn compute_block_reduction_subsidies(options: &CoinbaseSubsidyOptions) -> Vec { + let mut subsidy_reductions: Vec = vec![options.eunos_base_block_subsidy]; + while let Some(&last_subsidy) = subsidy_reductions.last() { + let amount = last_subsidy * options.emission_reduction / 100000; + if amount == 0 { + break; + } + subsidy_reductions.push(last_subsidy - amount); + } + subsidy_reductions + } +} diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 5e3fea18750..d852ebc41ac 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -19,7 +19,7 @@ pub enum NotFoundKind { } #[derive(Error, Debug)] -pub enum OceanError { +pub enum Error { #[error("Ocean: HexToArrayError error: {0:?}")] HexToArrayError(#[from] HexToArrayError), #[error("Ocean: ParseIntError error: {0:?}")] @@ -40,6 +40,8 @@ pub enum OceanError { RpcError(#[from] defichain_rpc::Error), #[error("Unable to find {0:}")] NotFound(NotFoundKind), + #[error("Decimal conversion error")] + DecimalError, #[error(transparent)] Other(#[from] anyhow::Error), } @@ -101,31 +103,29 @@ impl IntoResponse for ApiError { } } -impl OceanError { +impl Error { pub fn into_code_and_message(self) -> (StatusCode, String) { let (code, reason) = match self { - OceanError::RpcError(defichain_rpc::Error::JsonRpc( - jsonrpc_async::error::Error::Rpc(e), - )) => { + Error::RpcError(defichain_rpc::Error::JsonRpc(jsonrpc_async::error::Error::Rpc(e))) => { debug!("e : {:?}", e); (StatusCode::NOT_FOUND, format!("{}", e.message)) } - OceanError::NotFound(reason) => (StatusCode::NOT_FOUND, format!("{reason}")), + Error::NotFound(reason) => (StatusCode::NOT_FOUND, format!("{reason}")), _ => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()), }; (code, reason) } } -impl From> for OceanError { - fn from(err: Box) -> OceanError { - OceanError::Other(format_err!("{err}")) +impl From> for Error { + fn from(err: Box) -> Error { + Error::Other(format_err!("{err}")) } } -impl From<&str> for OceanError { +impl From<&str> for Error { fn from(s: &str) -> Self { - OceanError::Other(format_err!("{s}")) + Error::Other(format_err!("{s}")) } } diff --git a/lib/ain-ocean/src/indexer/masternode.rs b/lib/ain-ocean/src/indexer/masternode.rs index eaf02bc947d..c61733146b3 100644 --- a/lib/ain-ocean/src/indexer/masternode.rs +++ b/lib/ain-ocean/src/indexer/masternode.rs @@ -3,11 +3,13 @@ use std::sync::Arc; use bitcoin::{hashes::Hash, PubkeyHash, ScriptBuf, WPubkeyHash}; use dftx_rs::masternode::*; use log::debug; +use rust_decimal::{prelude::FromPrimitive, Decimal}; use super::Context; use crate::{ + error::Error, indexer::{Index, Result}, - model::{HistoryItem, Masternode}, + model::{HistoryItem, Masternode, MasternodeStats, MasternodeStatsData, TimelockStats}, repository::RepositoryOps, Services, }; @@ -29,6 +31,7 @@ impl Index for CreateMasternode { let Some(ref addresses) = ctx.tx.vout[1].script_pub_key.addresses else { return Err("Missing owner address".into()); }; + let collateral = Decimal::from_f64(ctx.tx.vout[1].value).ok_or(Error::DecimalError)?; let masternode = Masternode { id: txid, @@ -42,7 +45,7 @@ impl Index for CreateMasternode { minted_blocks: 0, timelock: self.timelock.0.unwrap_or_default(), block: ctx.block.clone(), - collateral: ctx.tx.vout[1].value, + collateral, history: Vec::new(), }; @@ -50,7 +53,9 @@ impl Index for CreateMasternode { services .masternode .by_height - .put(&(ctx.block.height, ctx.tx_idx), &txid) + .put(&(ctx.block.height, ctx.tx_idx), &txid)?; + + index_stats(&self, services, ctx, collateral) } fn invalidate(&self, services: &Arc, ctx: &Context) -> Result<()> { @@ -63,6 +68,42 @@ impl Index for CreateMasternode { } } +fn index_stats( + data: &CreateMasternode, + services: &Arc, + ctx: &Context, + collateral: Decimal, +) -> Result<()> { + let mut stats = services + .masternode + .stats + .get_latest()? + .map_or(MasternodeStatsData::default(), |mn| mn.stats); + + let count = stats.count + 1; + let tvl = stats.tvl + collateral; + let locked = stats + .locked + .entry(data.timelock.0.unwrap_or_default()) + .or_insert_with(TimelockStats::default); + + locked.count += 1; + locked.tvl += collateral; + + services.masternode.stats.put( + &ctx.block.height, + &MasternodeStats { + stats: MasternodeStatsData { + count, + tvl, + locked: stats.locked, + }, + block: ctx.block.clone(), + }, + )?; + Ok(()) +} + impl Index for UpdateMasternode { fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[UpdateMasternode] Indexing..."); diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 0320f718172..69447a302cc 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -5,7 +5,7 @@ mod indexer; use std::{path::PathBuf, sync::Arc}; pub use api::ocean_router; -use error::OceanError; +use error::Error; pub use indexer::{index_block, invalidate_block, transaction::index_transaction, tx_result}; use repository::{ AuctionHistoryByHeightRepository, AuctionHistoryRepository, BlockByHeightRepository, @@ -20,7 +20,7 @@ pub mod storage; use crate::storage::ocean_store::OceanStore; -pub type Result = std::result::Result; +pub type Result = std::result::Result; lazy_static::lazy_static! { // Global services exposed by the library diff --git a/lib/ain-ocean/src/model/masternode.rs b/lib/ain-ocean/src/model/masternode.rs index e4a410840af..c6b0e32ea24 100644 --- a/lib/ain-ocean/src/model/masternode.rs +++ b/lib/ain-ocean/src/model/masternode.rs @@ -1,4 +1,5 @@ use bitcoin::Txid; +use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; use super::BlockContext; @@ -14,7 +15,7 @@ pub struct Masternode { pub resign_tx: Option, pub minted_blocks: i32, pub timelock: u16, - pub collateral: f64, + pub collateral: Decimal, pub block: BlockContext, pub history: Vec, } diff --git a/lib/ain-ocean/src/model/masternode_stats.rs b/lib/ain-ocean/src/model/masternode_stats.rs index 44325fbd392..6128ca5035f 100644 --- a/lib/ain-ocean/src/model/masternode_stats.rs +++ b/lib/ain-ocean/src/model/masternode_stats.rs @@ -1,3 +1,6 @@ +use std::collections::HashMap; + +use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; use super::BlockContext; @@ -5,23 +8,21 @@ use super::BlockContext; #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct MasternodeStats { - pub id: String, pub block: BlockContext, - pub stats: MasternodeStatsStats, + pub stats: MasternodeStatsData, } #[derive(Serialize, Deserialize, Debug, Default)] #[serde(rename_all = "camelCase")] pub struct TimelockStats { - pub weeks: i32, - pub tvl: String, - pub count: i32, + pub tvl: Decimal, + pub count: u32, } #[derive(Serialize, Deserialize, Debug, Default)] #[serde(rename_all = "camelCase")] -pub struct MasternodeStatsStats { - pub count: i32, - pub tvl: String, - pub locked: Vec, +pub struct MasternodeStatsData { + pub count: u32, + pub tvl: Decimal, + pub locked: HashMap, } diff --git a/lib/ain-ocean/src/repository/masternode_stats.rs b/lib/ain-ocean/src/repository/masternode_stats.rs index e6b9cdb593c..66e26fa3dbd 100644 --- a/lib/ain-ocean/src/repository/masternode_stats.rs +++ b/lib/ain-ocean/src/repository/masternode_stats.rs @@ -12,7 +12,7 @@ use crate::{ }; #[derive(Repository)] -#[repository(K = "Txid", V = "MasternodeStats")] +#[repository(K = "u32", V = "MasternodeStats")] pub struct MasternodeStatsRepository { pub store: Arc, col: LedgerColumn, @@ -26,3 +26,13 @@ impl MasternodeStatsRepository { } } } + +impl MasternodeStatsRepository { + pub fn get_latest(&self) -> Result> { + match self.col.iter(None)?.next() { + None => Ok(None), + Some(Ok((_, id))) => Ok(Some(id)), + Some(Err(e)) => Err(e.into()), + } + } +} diff --git a/lib/ain-ocean/src/storage/columns/masternode_stats.rs b/lib/ain-ocean/src/storage/columns/masternode_stats.rs index 5e77802b89a..2171c659263 100644 --- a/lib/ain-ocean/src/storage/columns/masternode_stats.rs +++ b/lib/ain-ocean/src/storage/columns/masternode_stats.rs @@ -1,5 +1,5 @@ -use ain_db::{Column, ColumnName, TypedColumn}; -use bitcoin::Txid; +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; use crate::model; @@ -11,7 +11,20 @@ impl ColumnName for MasternodeStats { } impl Column for MasternodeStats { - type Index = Txid; + type Index = u32; + + fn key(index: &Self::Index) -> Result, DBError> { + Ok(index.to_be_bytes().to_vec()) + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + if raw_key.len() != 4 { + return Err(format_err!("Length of the slice is not 4").into()); + } + let mut array = [0u8; 4]; + array.copy_from_slice(&raw_key); + Ok(u32::from_be_bytes(array)) + } } impl TypedColumn for MasternodeStats { From 6d98c23a173c1950157b8ad845e7bf6ac83df4b7 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Sun, 11 Feb 2024 12:23:02 +0100 Subject: [PATCH 048/185] Ocean: Masternode API (#2820) * Fix masternode API * fix api page test --------- Co-authored-by: canonbrother --- lib/Cargo.lock | 61 +++++++--------- lib/ain-db/src/lib.rs | 4 +- lib/ain-ocean/Cargo.toml | 3 +- lib/ain-ocean/src/api/masternode.rs | 72 ++++++++++++------- lib/ain-ocean/src/api/mod.rs | 4 +- lib/ain-ocean/src/api/response.rs | 24 +++---- lib/ain-ocean/src/error.rs | 7 +- lib/ain-ocean/src/indexer/masternode.rs | 10 ++- lib/ain-ocean/src/indexer/mod.rs | 3 +- lib/ain-ocean/src/model/masternode.rs | 3 +- lib/ain-ocean/src/model/masternode_stats.rs | 6 +- lib/ain-ocean/src/model/transaction_vin.rs | 2 +- lib/ain-ocean/src/model/transaction_vout.rs | 2 +- lib/ain-ocean/src/repository/masternode.rs | 4 +- .../src/repository/masternode_stats.rs | 1 - .../src/storage/columns/masternode.rs | 4 +- 16 files changed, 108 insertions(+), 102 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index b14769c20fe..76a40121ac8 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -258,7 +258,6 @@ dependencies = [ "tempfile", "thiserror", "tokio", - "tokio-serde", ] [[package]] @@ -667,7 +666,7 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitcoin" version = "0.31.0" -source = "git+https://github.com/Jouzo/rust-bitcoin.git#b0d721708df119a87193ff23910ab5579ce370b7" +source = "git+https://github.com/Jouzo/rust-bitcoin.git#af64fe422669e2d4fc24fca93561566e22cce1df" dependencies = [ "bech32", "bitcoin-internals", @@ -691,7 +690,7 @@ dependencies = [ [[package]] name = "bitcoin-io" version = "0.1.0" -source = "git+https://github.com/Jouzo/rust-bitcoin.git#b0d721708df119a87193ff23910ab5579ce370b7" +source = "git+https://github.com/Jouzo/rust-bitcoin.git#af64fe422669e2d4fc24fca93561566e22cce1df" [[package]] name = "bitcoin-private" @@ -917,9 +916,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.14.2" +version = "1.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea31d69bda4949c1c1562c1e6f042a1caefac98cdc8a298260a2ff41c1e2d42b" +checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f" [[package]] name = "byteorder" @@ -1396,7 +1395,7 @@ dependencies = [ [[package]] name = "defichain-rpc" version = "0.18.0" -source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#179363a23efe48170196016b41f823c3f7644337" +source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#d27915e2b95fda5606bdf2379f0dd3d54c38ab00" dependencies = [ "async-trait", "defichain-rpc-json", @@ -1409,7 +1408,7 @@ dependencies = [ [[package]] name = "defichain-rpc-json" version = "0.18.0" -source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#179363a23efe48170196016b41f823c3f7644337" +source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#d27915e2b95fda5606bdf2379f0dd3d54c38ab00" dependencies = [ "bitcoin", "serde", @@ -1457,7 +1456,7 @@ checksum = "3ae2a35373c5c74340b79ae6780b498b2b183915ec5dacf263aac5a099bf485a" [[package]] name = "dftx-macro" version = "0.1.0" -source = "git+https://github.com/Jouzo/dftx-rs.git#e10dea303487f3c0bf5f851669c939a027b8e034" +source = "git+https://github.com/Jouzo/dftx-rs.git#c6ff7772f6bfe8a6d0804c40b2f53f3de69e295e" dependencies = [ "proc-macro2", "quote", @@ -1467,7 +1466,7 @@ dependencies = [ [[package]] name = "dftx-rs" version = "0.1.0" -source = "git+https://github.com/Jouzo/dftx-rs.git#e10dea303487f3c0bf5f851669c939a027b8e034" +source = "git+https://github.com/Jouzo/dftx-rs.git#c6ff7772f6bfe8a6d0804c40b2f53f3de69e295e" dependencies = [ "anyhow", "bitcoin", @@ -2712,12 +2711,12 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" +checksum = "fe8f25ce1159c7740ff0b9b2f5cdf4a8428742ba7c112b9f20f22cd5219c7dab" dependencies = [ "hermit-abi 0.3.5", - "rustix 0.38.31", + "libc", "windows-sys 0.52.0", ] @@ -2747,9 +2746,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "jobserver" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" dependencies = [ "libc", ] @@ -3480,19 +3479,18 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" dependencies = [ "autocfg", "num-integer", @@ -3513,9 +3511,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", "libm", @@ -4887,9 +4885,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.6.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b0ed1662c5a68664f45b76d18deb0e234aff37207086803165c961eb695e981" +checksum = "15d167997bd841ec232f5b2b8e0e26606df2e7caa4c31b95ea9ca52b200bd270" dependencies = [ "base64 0.21.7", "chrono", @@ -4897,6 +4895,7 @@ dependencies = [ "indexmap 1.9.3", "indexmap 2.2.2", "serde", + "serde_derive", "serde_json", "serde_with_macros", "time", @@ -4904,9 +4903,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.6.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568577ff0ef47b879f736cd66740e022f3672788cdf002a05a4e609ea5a6fb15" +checksum = "865f9743393e638991566a8b7a479043c2c8da94a33e0a31f18214c9cae0a64d" dependencies = [ "darling 0.20.5", "proc-macro2", @@ -5837,18 +5836,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-serde" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "911a61637386b789af998ee23f50aa30d5fd7edcec8d6d3dedae5e5815205466" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project", -] - [[package]] name = "tokio-stream" version = "0.1.14" diff --git a/lib/ain-db/src/lib.rs b/lib/ain-db/src/lib.rs index 3bf3a0a4aef..bf69f1c6b84 100644 --- a/lib/ain-db/src/lib.rs +++ b/lib/ain-db/src/lib.rs @@ -182,6 +182,7 @@ where &self, from: Option, ) -> Result> + '_> { + let skip = if from.as_ref().is_some() { 1 } else { 0 }; let index = from .as_ref() .map(|i| C::key(i)) @@ -198,7 +199,8 @@ where let value = bincode::deserialize(&value)?; let key = C::get_key(key)?; Ok((key, value)) - })) + }) + .skip(skip)) } } diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index 3298ce925a0..abb82d315ce 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -25,7 +25,6 @@ bitcoin = { workspace = true, features = ["serde"] } tokio = { version = "1", features = ["full"] } serde_json = "1.0" json = "0.12.4" -tokio-serde = { version="0.8.0"} futures = "0.3.29" jsonrpsee.workspace = true rocksdb = "0.21.0" @@ -40,5 +39,5 @@ bincode.workspace = true defichain-rpc.workspace = true jsonrpc-async = "2.0.2" serde_urlencoded = "0.7" -rust_decimal = { version = "1.34", features = ["serde-float"] } +rust_decimal = { version = "1.34", features = ["serde", "serde-str"] } rust_decimal_macros = "1.34" diff --git a/lib/ain-ocean/src/api/masternode.rs b/lib/ain-ocean/src/api/masternode.rs index 3af053cdf11..ec3522bf2b3 100644 --- a/lib/ain-ocean/src/api/masternode.rs +++ b/lib/ain-ocean/src/api/masternode.rs @@ -1,17 +1,25 @@ use std::sync::Arc; +use ain_macros::ocean_endpoint; +use anyhow::format_err; use axum::{ extract::{Path, Query}, routing::get, - Json, Router, + Extension, Router, }; use bitcoin::Txid; -use defichain_rpc::{Client, RpcApi}; use serde::{Deserialize, Serialize}; +use super::{ + response::{ApiPagedResponse, Response}, + AppContext, +}; use crate::{ - api_paged_response::ApiPagedResponse, api_query::PaginationQuery, model::Masternode, - repository::RepositoryOps, services, Result, + api_query::PaginationQuery, + error::{ApiError, Error, NotFoundKind}, + model::Masternode, + repository::RepositoryOps, + Result, }; #[derive(Serialize, Deserialize, Debug, Default, Clone)] @@ -66,14 +74,14 @@ impl From for MasternodeData { fn from(v: Masternode) -> Self { MasternodeData { id: v.id.to_string(), - sort: v.sort, + sort: format!("{:08x}{}", v.block.height, v.id), state: MasternodeState::default(), // TODO Handle mn state minted_blocks: v.minted_blocks, owner: MasternodeOwner { - address: v.owner_address.to_hex_string(), + address: v.owner_address, }, operator: MasternodeOperator { - address: v.operator_address.to_hex_string(), + address: v.operator_address, }, creation: MasternodeCreation { height: v.creation_height, @@ -90,32 +98,35 @@ impl From for MasternodeData { } } +#[ocean_endpoint] async fn list_masternodes( Query(query): Query, -) -> Result>> { + Extension(ctx): Extension>, +) -> Result> { let next = query .next .map(|q| { - let parts = q.split('-').collect::>(); - if parts.len() != 2 { - return Err("Invalid query format"); - } - - let height = parts[0].parse::().map_err(|_| "Invalid height")?; - let txno = parts[1].parse::().map_err(|_| "Invalid txno")?; - - Ok((height, txno)) + let height = q[0..8] + .parse::() + .map_err(|_| format_err!("Invalid height"))?; + let txid = q[8..] + .parse::() + .map_err(|_| format_err!("Invalid txid"))?; + + Ok::<(u32, bitcoin::Txid), Error>((height, txid)) }) .transpose()?; - let masternodes = services + let masternodes = ctx + .services .masternode .by_height .list(next)? .take(query.size) .map(|item| { - let (_, id) = item?; - let mn = services + let ((_, id), _) = item?; + let mn = ctx + .services .masternode .by_id .get(&id)? @@ -125,25 +136,32 @@ async fn list_masternodes( }) .collect::>>()?; - Ok(Json(ApiPagedResponse::of( + Ok(ApiPagedResponse::of( masternodes, query.size, - |masternode| masternode.clone().sort, - ))) + |masternode| masternode.sort.to_string(), + )) } -async fn get_masternode(Path(masternode_id): Path) -> Result>> { - let mn = services +#[ocean_endpoint] +async fn get_masternode( + Path(masternode_id): Path, + Extension(ctx): Extension>, +) -> Result> { + let mn = ctx + .services .masternode .by_id .get(&masternode_id)? - .map(Into::into); + .map(Into::into) + .ok_or(Error::NotFound(NotFoundKind::Masternode))?; - Ok(Json(mn)) + Ok(Response::new(mn)) } pub fn router(ctx: Arc) -> Router { Router::new() .route("/", get(list_masternodes)) .route("/:id", get(get_masternode)) + .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index 54b200e7295..576a38c1228 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -7,7 +7,7 @@ mod block; mod fee; mod governance; // mod loan; -// mod masternode; +mod masternode; // mod oracle; // mod poolpairs; // mod prices; @@ -66,7 +66,7 @@ pub async fn ocean_router(services: &Arc, client: Arc) -> Resu .nest("/governance", governance::router(Arc::clone(&context))) // .nest("/loans", loan::router(Arc::clone(&context))) .nest("/fee", fee::router(Arc::clone(&context))) - // .nest("/masternodes", masternode::router(Arc::clone(&context))) + .nest("/masternodes", masternode::router(Arc::clone(&context))) // .nest("/oracles", oracle::router(Arc::clone(&context))) // .nest("/poolpairs", poolpairs::router(Arc::clone(&context))) // .nest("/prices", prices::router(Arc::clone(&context))) diff --git a/lib/ain-ocean/src/api/response.rs b/lib/ain-ocean/src/api/response.rs index ddb86e31892..76341239fcb 100644 --- a/lib/ain-ocean/src/api/response.rs +++ b/lib/ain-ocean/src/api/response.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use serde_with::skip_serializing_none; #[derive(Debug, Serialize)] pub struct Response { @@ -60,22 +61,23 @@ impl Response { /// Answer: Blocks sorted by height in descending order, that's your sorted list and your slice window. /// : <- Latest | [100] [99] [98] [97] [...] | Oldest -> /// +#[skip_serializing_none] #[derive(Debug, Serialize, PartialEq)] pub struct ApiPagedResponse { data: Vec, - page: ApiPage, + page: Option, } #[derive(Debug, Serialize, PartialEq)] struct ApiPage { - next: Option, + next: String, } impl ApiPagedResponse { pub fn new(data: Vec, next: Option) -> Self { Self { data, - page: ApiPage { next }, + page: next.map(|next| ApiPage { next }), } // Option<&str> -> Option } @@ -91,10 +93,6 @@ impl ApiPagedResponse { Self::next(data, None) } } - - pub fn empty() -> Self { - Self::new(Vec::new(), None) - } } #[cfg(test)] @@ -120,8 +118,8 @@ mod tests { fn should_next_with_none() { let items: Vec = vec![Item::new("0", "a"), Item::new("1", "b")]; - let next = ApiPagedResponse::next(items, None).page.next; - assert_eq!(next, None); + let page = ApiPagedResponse::next(items, None).page; + assert_eq!(page, None); } #[test] @@ -130,8 +128,9 @@ mod tests { let next = ApiPagedResponse::next(items, Some("b".to_string())) .page + .unwrap() .next; - assert_eq!(next, Some("b".into())); + assert_eq!(next, "b".to_string()); } #[test] @@ -144,8 +143,9 @@ mod tests { let next = ApiPagedResponse::of(items, 3, |item| item.clone().sort) .page + .unwrap() .next; - assert_eq!(next, Some("c".into())) + assert_eq!(next, "c".to_string()) } #[test] @@ -153,6 +153,6 @@ mod tests { let items: Vec = vec![Item::new("0", "a"), Item::new("1", "b")]; let page = ApiPagedResponse::of(items, 3, |item| item.clone().sort).page; - assert_eq!(page, ApiPage { next: None }) + assert_eq!(page, None) } } diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index d852ebc41ac..71dea60f60c 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -8,6 +8,7 @@ use axum::{ Json, }; use bitcoin::hex::HexToArrayError; +use hyper::client; use log::debug; use serde::Serialize; use thiserror::Error; @@ -16,6 +17,8 @@ use thiserror::Error; pub enum NotFoundKind { #[error("proposal")] Proposal, + #[error("masternode")] + Masternode, } #[derive(Error, Debug)] @@ -105,13 +108,13 @@ impl IntoResponse for ApiError { impl Error { pub fn into_code_and_message(self) -> (StatusCode, String) { - let (code, reason) = match self { + let (code, reason) = match &self { Error::RpcError(defichain_rpc::Error::JsonRpc(jsonrpc_async::error::Error::Rpc(e))) => { debug!("e : {:?}", e); (StatusCode::NOT_FOUND, format!("{}", e.message)) } - Error::NotFound(reason) => (StatusCode::NOT_FOUND, format!("{reason}")), + Error::NotFound(_) => (StatusCode::NOT_FOUND, format!("{}", self)), _ => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()), }; (code, reason) diff --git a/lib/ain-ocean/src/indexer/masternode.rs b/lib/ain-ocean/src/indexer/masternode.rs index c61733146b3..950b0620535 100644 --- a/lib/ain-ocean/src/indexer/masternode.rs +++ b/lib/ain-ocean/src/indexer/masternode.rs @@ -35,7 +35,6 @@ impl Index for CreateMasternode { let masternode = Masternode { id: txid, - sort: format!("{}-{}", ctx.block.height, ctx.tx_idx), owner_address: addresses[0].clone(), operator_address: get_operator_script(&self.operator_pub_key_hash, self.operator_type)? .to_hex_string(), @@ -53,7 +52,7 @@ impl Index for CreateMasternode { services .masternode .by_height - .put(&(ctx.block.height, ctx.tx_idx), &txid)?; + .put(&(ctx.block.height, txid), &0)?; index_stats(&self, services, ctx, collateral) } @@ -64,7 +63,7 @@ impl Index for CreateMasternode { services .masternode .by_height - .delete(&(ctx.block.height, ctx.tx_idx)) + .delete(&(ctx.block.height, ctx.tx.txid)) } } @@ -96,12 +95,11 @@ fn index_stats( stats: MasternodeStatsData { count, tvl, - locked: stats.locked, + locked: stats.clone().locked, }, block: ctx.block.clone(), }, - )?; - Ok(()) + ) } impl Index for UpdateMasternode { diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index f687fbccd7f..de37977f284 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -80,7 +80,8 @@ pub fn index_block(services: &Arc, block: Block) -> Resul tx, tx_idx, }; - let bytes = ctx.tx.vout[0].script_pub_key.hex.as_bytes(); + + let bytes = &ctx.tx.vout[0].script_pub_key.hex; if bytes.len() > 2 && bytes[0] == 0x6a && bytes[1] <= 0x4e { let offset = 1 + match bytes[1] { 0x4c => 2, diff --git a/lib/ain-ocean/src/model/masternode.rs b/lib/ain-ocean/src/model/masternode.rs index c6b0e32ea24..58083131100 100644 --- a/lib/ain-ocean/src/model/masternode.rs +++ b/lib/ain-ocean/src/model/masternode.rs @@ -6,8 +6,7 @@ use super::BlockContext; #[derive(Debug, Serialize, Deserialize)] pub struct Masternode { - pub id: Txid, // Keep for backward compatibility - pub sort: String, // Keep for backward compatibility + pub id: Txid, // Keep for backward compatibility pub owner_address: String, pub operator_address: String, pub creation_height: u32, diff --git a/lib/ain-ocean/src/model/masternode_stats.rs b/lib/ain-ocean/src/model/masternode_stats.rs index 6128ca5035f..a2def3b4d74 100644 --- a/lib/ain-ocean/src/model/masternode_stats.rs +++ b/lib/ain-ocean/src/model/masternode_stats.rs @@ -5,21 +5,21 @@ use serde::{Deserialize, Serialize}; use super::BlockContext; -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct MasternodeStats { pub block: BlockContext, pub stats: MasternodeStatsData, } -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct TimelockStats { pub tvl: Decimal, pub count: u32, } -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct MasternodeStatsData { pub count: u32, diff --git a/lib/ain-ocean/src/model/transaction_vin.rs b/lib/ain-ocean/src/model/transaction_vin.rs index 8626cfc0731..9ee25d4c85d 100644 --- a/lib/ain-ocean/src/model/transaction_vin.rs +++ b/lib/ain-ocean/src/model/transaction_vin.rs @@ -55,5 +55,5 @@ pub struct TransactionVinVout { pub n: usize, pub value: f64, pub token_id: u8, - pub script: String, + pub script: Vec, } diff --git a/lib/ain-ocean/src/model/transaction_vout.rs b/lib/ain-ocean/src/model/transaction_vout.rs index 461b3ae2ed3..8116abfc466 100644 --- a/lib/ain-ocean/src/model/transaction_vout.rs +++ b/lib/ain-ocean/src/model/transaction_vout.rs @@ -14,6 +14,6 @@ pub struct TransactionVout { #[derive(Debug, Default, Serialize, Deserialize)] pub struct TransactionVoutScript { - pub hex: String, + pub hex: Vec, pub r#type: String, } diff --git a/lib/ain-ocean/src/repository/masternode.rs b/lib/ain-ocean/src/repository/masternode.rs index 5a64a0112fd..13975bdbe91 100644 --- a/lib/ain-ocean/src/repository/masternode.rs +++ b/lib/ain-ocean/src/repository/masternode.rs @@ -27,10 +27,10 @@ impl MasternodeRepository { } } -type MasternodeByHeightKey = (u32, usize); +type MasternodeByHeightKey = (u32, Txid); #[derive(Repository)] -#[repository(K = "MasternodeByHeightKey", V = "Txid")] +#[repository(K = "MasternodeByHeightKey", V = "u8")] pub struct MasternodeByHeightRepository { pub store: Arc, col: LedgerColumn, diff --git a/lib/ain-ocean/src/repository/masternode_stats.rs b/lib/ain-ocean/src/repository/masternode_stats.rs index 66e26fa3dbd..c7fe6340abc 100644 --- a/lib/ain-ocean/src/repository/masternode_stats.rs +++ b/lib/ain-ocean/src/repository/masternode_stats.rs @@ -2,7 +2,6 @@ use std::sync::Arc; use ain_db::LedgerColumn; use ain_macros::Repository; -use bitcoin::Txid; use super::RepositoryOps; use crate::{ diff --git a/lib/ain-ocean/src/storage/columns/masternode.rs b/lib/ain-ocean/src/storage/columns/masternode.rs index d4a3e1b1fdc..eda0112c568 100644 --- a/lib/ain-ocean/src/storage/columns/masternode.rs +++ b/lib/ain-ocean/src/storage/columns/masternode.rs @@ -27,9 +27,9 @@ impl ColumnName for MasternodeByHeight { } impl Column for MasternodeByHeight { - type Index = (u32, usize); + type Index = (u32, Txid); } impl TypedColumn for MasternodeByHeight { - type Type = Txid; + type Type = u8; } From 5337d8cc5d97568ed0f7fb7a0cc3d50a0dfafd21 Mon Sep 17 00:00:00 2001 From: jouzo Date: Sun, 11 Feb 2024 20:58:24 +0100 Subject: [PATCH 049/185] Correct API Decimal float serialization --- lib/ain-ocean/Cargo.toml | 2 +- lib/ain-ocean/src/api/common.rs | 1 + lib/ain-ocean/src/api/stats/stats.rs | 16 ++++++++-------- lib/ain-ocean/src/model/masternode.rs | 1 + lib/ain-ocean/src/model/masternode_stats.rs | 2 ++ 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index abb82d315ce..8cbd797d0a9 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -39,5 +39,5 @@ bincode.workspace = true defichain-rpc.workspace = true jsonrpc-async = "2.0.2" serde_urlencoded = "0.7" -rust_decimal = { version = "1.34", features = ["serde", "serde-str"] } +rust_decimal = { version = "1.34", features = ["serde", "serde-float", "serde-with-str"] } rust_decimal_macros = "1.34" diff --git a/lib/ain-ocean/src/api/common.rs b/lib/ain-ocean/src/api/common.rs index 5e8c9be819e..0c0b7cfaeaa 100644 --- a/lib/ain-ocean/src/api/common.rs +++ b/lib/ain-ocean/src/api/common.rs @@ -1,5 +1,6 @@ use defichain_rpc::json::token::TokenInfo; use rust_decimal::Decimal; +use serde::{Deserialize, Serialize}; pub fn parse_display_symbol(token_info: &TokenInfo) -> String { if token_info.is_lps { diff --git a/lib/ain-ocean/src/api/stats/stats.rs b/lib/ain-ocean/src/api/stats/stats.rs index 4eded439fc6..1078cf066c0 100644 --- a/lib/ain-ocean/src/api/stats/stats.rs +++ b/lib/ain-ocean/src/api/stats/stats.rs @@ -143,18 +143,18 @@ pub fn get_emission(height: u32) -> Result { Decimal::from_u64(BLOCK_SUBSIDY.get_block_subsidy(height)).ok_or(Error::DecimalError)?; let distribution = get_block_reward_distribution(subsidy); - let masternode = distribution.masternode.trunc_with_scale(8); - let dex = distribution.liquidity.trunc_with_scale(8); - let community = distribution.community.trunc_with_scale(8); - let anchor = distribution.anchor.trunc_with_scale(8); + let masternode = distribution.masternode; + let dex = distribution.liquidity; + let community = distribution.community; + let anchor = distribution.anchor; let total = subsidy / COIN; let burned = total - (masternode + dex + community + anchor); Ok(Emission { - masternode, - dex, - community, - anchor, + masternode: masternode.trunc_with_scale(8), + dex: dex.trunc_with_scale(8), + community: community.trunc_with_scale(8), + anchor: anchor.trunc_with_scale(8), burned, total, }) diff --git a/lib/ain-ocean/src/model/masternode.rs b/lib/ain-ocean/src/model/masternode.rs index 58083131100..a16f9c10f1c 100644 --- a/lib/ain-ocean/src/model/masternode.rs +++ b/lib/ain-ocean/src/model/masternode.rs @@ -14,6 +14,7 @@ pub struct Masternode { pub resign_tx: Option, pub minted_blocks: i32, pub timelock: u16, + #[serde(with = "rust_decimal::serde::str")] pub collateral: Decimal, pub block: BlockContext, pub history: Vec, diff --git a/lib/ain-ocean/src/model/masternode_stats.rs b/lib/ain-ocean/src/model/masternode_stats.rs index a2def3b4d74..05af765251d 100644 --- a/lib/ain-ocean/src/model/masternode_stats.rs +++ b/lib/ain-ocean/src/model/masternode_stats.rs @@ -15,6 +15,7 @@ pub struct MasternodeStats { #[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct TimelockStats { + #[serde(with = "rust_decimal::serde::str")] pub tvl: Decimal, pub count: u32, } @@ -23,6 +24,7 @@ pub struct TimelockStats { #[serde(rename_all = "camelCase")] pub struct MasternodeStatsData { pub count: u32, + #[serde(with = "rust_decimal::serde::str")] pub tvl: Decimal, pub locked: HashMap, } From 280c9f1e0b0307b153fab51ef0dd39815482e508 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Mon, 19 Feb 2024 06:51:08 +0100 Subject: [PATCH 050/185] Ocean: Ocean loan API initial impl (#2823) * Update PaginationQuery default * Loan API partial impl --- lib/Cargo.lock | 130 ++++----- lib/ain-ocean/src/api/block.rs | 9 +- lib/ain-ocean/src/api/cache.rs | 25 ++ lib/ain-ocean/src/api/common.rs | 72 +++++ lib/ain-ocean/src/api/fee.rs | 6 +- lib/ain-ocean/src/api/governance.rs | 2 +- lib/ain-ocean/src/api/loan.rs | 260 +++++++++++++++--- lib/ain-ocean/src/api/masternode.rs | 2 +- lib/ain-ocean/src/api/mod.rs | 10 +- .../src/{api_query.rs => api/query.rs} | 19 +- lib/ain-ocean/src/api/tokens.rs | 19 +- lib/ain-ocean/src/error.rs | 17 +- lib/ain-ocean/src/lib.rs | 1 - 13 files changed, 431 insertions(+), 141 deletions(-) create mode 100644 lib/ain-ocean/src/api/cache.rs rename lib/ain-ocean/src/{api_query.rs => api/query.rs} (80%) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 76a40121ac8..e623ed664fd 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -38,9 +38,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aes" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", @@ -49,9 +49,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom 0.2.12", "once_cell", @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff" dependencies = [ "cfg-if", "getrandom 0.2.12", @@ -962,7 +962,7 @@ version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "355face540df58778b96814c48abb3c2ed67c4878a8087ab1819c1fedeec505f" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.8", "async-trait", "cached_proc_macro", "cached_proc_macro_types", @@ -1025,9 +1025,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chrono" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" +checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1160,9 +1160,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] @@ -1268,9 +1268,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.115" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de00f15a6fa069c99b88c5c78c4541d0e7899a33b86f7480e23df2431fce0bc" +checksum = "8aff472b83efd22bfc0176aa8ba34617dd5c17364670eb201a5f06d339b8abf7" dependencies = [ "cc", "cxxbridge-flags", @@ -1280,9 +1280,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.115" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a71e1e631fa2f2f5f92e8b0d860a00c198c6771623a6cefcc863e3554f0d8d6" +checksum = "bcf6e7a52c19013a9a0ec421c7d9c2d1125faf333551227e0a017288d71b47c3" dependencies = [ "cc", "codespan-reporting", @@ -1295,9 +1295,9 @@ dependencies = [ [[package]] name = "cxx-gen" -version = "0.7.115" +version = "0.7.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65428c17c352f476b40ac6f497c86f9cb365bff3d35d18af68705d6630546849" +checksum = "8a2a39f7064dacffa9bf2d33d8dcc7777b60c789a95e1cd62d5fbeb1161428f2" dependencies = [ "codespan-reporting", "proc-macro2", @@ -1307,15 +1307,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.115" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f3fed61d56ba497c4efef9144dfdbaa25aa58f2f6b3a7cf441d4591c583745c" +checksum = "589e83d02fc1d4fb78f5ad56ca08835341e23499d086d2821315869426d618dc" [[package]] name = "cxxbridge-macro" -version = "1.0.115" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8908e380a8efd42150c017b0cfa31509fc49b6d47f7cb6b33e93ffb8f4e3661e" +checksum = "e2cb1fd8ffae4230c7cfbbaf3698dbeaf750fa8c5dadf7ed897df581b9b572a5" dependencies = [ "proc-macro2", "quote", @@ -1334,12 +1334,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.5" +version = "0.20.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc5d6b04b3fd0ba9926f945895de7d806260a2d7431ba82e7edaecb043c4c6b8" +checksum = "c376d08ea6aa96aafe61237c7200d1241cb177b7d3a542d791f2d118e9cbb955" dependencies = [ - "darling_core 0.20.5", - "darling_macro 0.20.5", + "darling_core 0.20.6", + "darling_macro 0.20.6", ] [[package]] @@ -1358,9 +1358,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.5" +version = "0.20.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e48a959bcd5c761246f5d090ebc2fbf7b9cd527a492b07a67510c108f1e7e3" +checksum = "33043dcd19068b8192064c704b3f83eb464f91f1ff527b44a4e2b08d9cdb8855" dependencies = [ "fnv", "ident_case", @@ -1383,11 +1383,11 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.5" +version = "0.20.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1545d67a2149e1d93b7e5c7752dce5a7426eb5d1357ddcfd89336b94444f77" +checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be" dependencies = [ - "darling_core 0.20.5", + "darling_core 0.20.6", "quote", "syn 2.0.48", ] @@ -1395,7 +1395,7 @@ dependencies = [ [[package]] name = "defichain-rpc" version = "0.18.0" -source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#d27915e2b95fda5606bdf2379f0dd3d54c38ab00" +source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#324f8cf4bf0973be34ae1bb6da26de21b29f03fd" dependencies = [ "async-trait", "defichain-rpc-json", @@ -1408,7 +1408,7 @@ dependencies = [ [[package]] name = "defichain-rpc-json" version = "0.18.0" -source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#d27915e2b95fda5606bdf2379f0dd3d54c38ab00" +source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#324f8cf4bf0973be34ae1bb6da26de21b29f03fd" dependencies = [ "bitcoin", "serde", @@ -1637,9 +1637,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "elliptic-curve" @@ -2219,7 +2219,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.11", - "indexmap 2.2.2", + "indexmap 2.2.3", "slab", "tokio", "tokio-util", @@ -2238,7 +2238,7 @@ dependencies = [ "futures-sink", "futures-util", "http 1.0.0", - "indexmap 2.2.2", + "indexmap 2.2.3", "slab", "tokio", "tokio-util", @@ -2272,7 +2272,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.7", + "ahash 0.7.8", ] [[package]] @@ -2281,7 +2281,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.8", ] [[package]] @@ -2290,7 +2290,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.8", "allocator-api2", ] @@ -2320,9 +2320,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" +checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" [[package]] name = "hex" @@ -2655,9 +2655,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -2688,7 +2688,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.5", + "hermit-abi 0.3.6", "libc", "windows-sys 0.48.0", ] @@ -2711,11 +2711,11 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe8f25ce1159c7740ff0b9b2f5cdf4a8428742ba7c112b9f20f22cd5219c7dab" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi 0.3.5", + "hermit-abi 0.3.6", "libc", "windows-sys 0.52.0", ] @@ -3525,7 +3525,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.5", + "hermit-abi 0.3.6", "libc", ] @@ -3739,7 +3739,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.2.2", + "indexmap 2.2.3", ] [[package]] @@ -3837,9 +3837,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "powerfmt" @@ -4468,9 +4468,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.34.2" +version = "1.34.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755392e1a2f77afd95580d3f0d0e94ac83eeeb7167552c9b5bca549e61a94d83" +checksum = "b39449a79f45e8da28c57c341891b69a183044b29518bb8f86dbac9df60bb7df" dependencies = [ "arrayvec 0.7.4", "borsh", @@ -4670,7 +4670,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.8", "cfg-if", "hashbrown 0.13.2", ] @@ -4893,7 +4893,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.2", + "indexmap 2.2.3", "serde", "serde_derive", "serde_json", @@ -4907,7 +4907,7 @@ version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "865f9743393e638991566a8b7a479043c2c8da94a33e0a31f18214c9cae0a64d" dependencies = [ - "darling 0.20.5", + "darling 0.20.6", "proc-macro2", "quote", "syn 2.0.48", @@ -5329,7 +5329,7 @@ version = "23.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf63ea90ffb5d61048d8fb2fac669114dac198fc2739e913e615f0fd2c36c3e7" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.8", "hash-db 0.16.0", "hashbrown 0.13.2", "lazy_static", @@ -5675,18 +5675,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", @@ -5874,7 +5874,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.2.2", + "indexmap 2.2.3", "toml_datetime", "winnow", ] @@ -5885,7 +5885,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.2.2", + "indexmap 2.2.3", "toml_datetime", "winnow", ] @@ -6829,9 +6829,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.39" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5389a154b01683d28c77f8f68f49dea75f0a4da32557a58f68ee51ebba472d29" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index c9c2c4cc713..0bf31b6c63c 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -6,16 +6,11 @@ use bitcoin::BlockHash; use serde::{Deserialize, Deserializer}; use super::{ + query::{PaginationQuery, Query}, response::{ApiPagedResponse, Response}, AppContext, }; -use crate::{ - api_query::{PaginationQuery, Query}, - error::ApiError, - model::Block, - repository::RepositoryOps, - Result, -}; +use crate::{error::ApiError, model::Block, repository::RepositoryOps, Result}; pub enum HashOrHeight { Height(u32), diff --git a/lib/ain-ocean/src/api/cache.rs b/lib/ain-ocean/src/api/cache.rs new file mode 100644 index 00000000000..96b95ac08bf --- /dev/null +++ b/lib/ain-ocean/src/api/cache.rs @@ -0,0 +1,25 @@ +use std::sync::Arc; + +use anyhow::format_err; +use cached::proc_macro::cached; +use defichain_rpc::{defichain_rpc_json::token::TokenInfo, TokenRPC}; + +use super::AppContext; +use crate::Result; + +#[cached( + result = true, + key = "String", + convert = r#"{ format!("gettoken{symbol}") }"# +)] +pub async fn get_token_cached(ctx: &Arc, symbol: &str) -> Result<(String, TokenInfo)> { + let token = ctx + .client + .get_token(symbol) + .await? + .0 + .into_iter() + .next() + .ok_or(format_err!("Error getting token info"))?; + Ok(token) +} diff --git a/lib/ain-ocean/src/api/common.rs b/lib/ain-ocean/src/api/common.rs index 0c0b7cfaeaa..b4a6c60ee24 100644 --- a/lib/ain-ocean/src/api/common.rs +++ b/lib/ain-ocean/src/api/common.rs @@ -2,6 +2,8 @@ use defichain_rpc::json::token::TokenInfo; use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; +use super::query::PaginationQuery; + pub fn parse_display_symbol(token_info: &TokenInfo) -> String { if token_info.is_lps { let tokens: Vec<&str> = token_info.symbol.split('-').collect(); @@ -66,3 +68,73 @@ pub fn find_token_balance(tokens: Vec, symbol: &str) -> Decimal { }) .unwrap_or_default() } + +/// Provides a simulated pagination mechanism for iterators where native pagination is not available. +/// +/// This trait extends any Rust iterator to include a `paginate` method, allowing for pseudo-pagination +/// based on custom logic. It's should only be used to query defid list* RPC that don't implement native pagination +/// +/// # Warning +/// +/// This method should be used cautiously, as it involves retrieving all data from the data source +/// before applying pagination. This can lead to significant performance and resource usage issues, +/// especially with large datasets. It is recommended to use this approach only defid does not accept +/// any pagination parameter. +/// +/// # Parameters +/// +/// - `query`: A reference to `PaginationQuery` +/// - `skip_while`: A closure that determines the starting point of data to consider, mimicking the +/// 'start' parameter in traditional pagination. Once an item fails this condition, pagination starts. +/// +/// # Example +/// +/// ```rust +/// use crate::Paginate; +/// +/// let query = { +/// next: Some(1) +/// limit: 3 +/// }; +/// +/// let skip_while = |el: &LoanSchemeResult| match &query.next { +/// None => false, +/// Some(v) => v != &el.id, +/// }; + +/// let res: Vec<_> = ctx +/// .client +/// .list_loan_schemes() +/// .await? +/// .into_iter() +/// .paginate(&query, skip_while) +/// .collect(); +/// +/// assert!(res.len() <= query.size, "The result should not contain more items than the specified limit"); +/// assert!(res[0].id > query.next.unwrap(), "The result should start after the requested start id"); +/// ``` +pub trait Paginate<'a, T>: Iterator + Sized { + fn paginate( + self, + query: &PaginationQuery, + skip_while: F, + ) -> Box + 'a> + where + F: FnMut(&T) -> bool + 'a; +} + +impl<'a, T, I> Paginate<'a, T> for I +where + I: Iterator + 'a, +{ + fn paginate(self, query: &PaginationQuery, skip_while: F) -> Box + 'a> + where + F: FnMut(&T) -> bool + 'a, + { + Box::new( + self.skip_while(skip_while) + .skip(query.next.is_some() as usize) + .take(query.size), + ) + } +} diff --git a/lib/ain-ocean/src/api/fee.rs b/lib/ain-ocean/src/api/fee.rs index 93fd17b7f27..78efa57ff59 100644 --- a/lib/ain-ocean/src/api/fee.rs +++ b/lib/ain-ocean/src/api/fee.rs @@ -2,11 +2,11 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; use axum::{routing::get, Extension, Router}; -use defichain_rpc::{json::mining::SmartFeeEstimation, Client, RpcApi}; +use defichain_rpc::{json::mining::SmartFeeEstimation, RpcApi}; use serde::Deserialize; -use super::{response::Response, AppContext}; -use crate::{api_query::Query, error::ApiError, Result, Services}; +use super::{query::Query, response::Response, AppContext}; +use crate::{error::ApiError, Result}; #[derive(Deserialize, Default)] #[serde(rename_all = "camelCase")] diff --git a/lib/ain-ocean/src/api/governance.rs b/lib/ain-ocean/src/api/governance.rs index d09e1163d74..36e04abaece 100644 --- a/lib/ain-ocean/src/api/governance.rs +++ b/lib/ain-ocean/src/api/governance.rs @@ -7,11 +7,11 @@ use defichain_rpc::{json::governance::*, GovernanceRPC}; use serde::Deserialize; use super::{ + query::{PaginationQuery, Query}, response::{ApiPagedResponse, Response}, AppContext, }; use crate::{ - api_query::{PaginationQuery, Query}, error::{ApiError, Error, NotFoundKind}, Result, Services, }; diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index 936abc40432..42970172701 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -1,55 +1,236 @@ use std::sync::Arc; -use axum::{ - extract::{Path, Query}, - routing::get, - Json, Router, -}; +use ain_macros::ocean_endpoint; +use anyhow::format_err; +use axum::{extract::Path, routing::get, Extension, Router}; use bitcoin::Txid; -use defichain_rpc::{Client, RpcApi}; +use defichain_rpc::{ + defichain_rpc_json::{ + loan::{CollateralTokenDetail, LoanSchemeResult, LoanTokenResult}, + token::TokenInfo, + }, + LoanRPC, +}; +use futures::future::try_join_all; use log::debug; +use serde::Serialize; +use super::{ + cache::get_token_cached, + common::Paginate, + query::{PaginationQuery, Query}, + response::{ApiPagedResponse, Response}, + tokens::TokenData, + AppContext, +}; use crate::{ - api_paged_response::ApiPagedResponse, api_query::PaginationQuery, - model::VaultAuctionBatchHistory, repository::RepositoryOps, services, Result, + error::{ApiError, Error, NotFoundKind}, + model::VaultAuctionBatchHistory, + repository::RepositoryOps, + Result, }; -async fn list_scheme() -> String { - "List of loan schemes".to_string() +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct LoanSchemeData { + id: String, + min_col_ratio: String, + interest_rate: String, +} + +impl From for LoanSchemeData { + fn from(value: LoanSchemeResult) -> Self { + Self { + id: value.id, + min_col_ratio: format!("{}", value.mincolratio), + interest_rate: format!("{}", value.interestrate), + } + } } -async fn get_scheme(Path(scheme_id): Path) -> String { - format!("Details of loan scheme with id {}", scheme_id) +#[ocean_endpoint] +async fn list_scheme( + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let skip_while = |el: &LoanSchemeResult| match &query.next { + None => false, + Some(v) => v != &el.id, + }; + + let res = ctx + .client + .list_loan_schemes() + .await? + .into_iter() + .paginate(&query, skip_while) + .map(Into::into) + .collect(); + Ok(ApiPagedResponse::of(res, query.size, |loan_scheme| { + loan_scheme.id.to_owned() + })) } -async fn list_collateral_token() -> String { - "List of collateral tokens".to_string() +#[ocean_endpoint] +async fn get_scheme( + Path(scheme_id): Path, + Extension(ctx): Extension>, +) -> Result> { + println!("[get_scheme]"); + Ok(Response::new( + ctx.client.get_loan_scheme(scheme_id).await?.into(), + )) } -async fn get_collateral_token(Path(token_id): Path) -> String { - format!("Details of collateral token with id {}", token_id) +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CollateralToken { + token_id: String, + token: TokenData, + factor: String, + activate_after_block: u32, + fixed_interval_price_id: String, + // TODO when indexing price + // activePrice?: ActivePrice } -async fn list_loan_token() -> String { - "List of loan tokens".to_string() +impl CollateralToken { + fn from_with_id(id: String, detail: CollateralTokenDetail, info: TokenInfo) -> Self { + Self { + token_id: detail.token_id, + factor: format!("{}", detail.factor), + activate_after_block: 0, + fixed_interval_price_id: detail.fixed_interval_price_id, + token: TokenData::from_with_id(id, info), + } + } +} + +#[ocean_endpoint] +async fn list_collateral_token( + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let skip_while = |el: &CollateralTokenDetail| match &query.next { + None => false, + Some(v) => v != &el.token_id, + }; + + let tokens = ctx.client.list_collateral_tokens().await?; + + let fut = tokens + .into_iter() + .paginate(&query, skip_while) + .map(|v| async { + let (id, info) = get_token_cached(&ctx, &v.token_id).await?; + Ok::(CollateralToken::from_with_id(id, v, info)) + }) + .collect::>(); + + let res = try_join_all(fut).await?; + + Ok(ApiPagedResponse::of(res, query.size, |loan_scheme| { + loan_scheme.token_id.to_owned() + })) } -async fn get_loan_token(Path(token_id): Path) -> String { - format!("Details of loan token with id {}", token_id) +#[ocean_endpoint] +async fn get_collateral_token( + Path(token_id): Path, + Extension(ctx): Extension>, +) -> Result> { + let collateral_token = ctx.client.get_collateral_token(token_id).await?; + let (id, info) = get_token_cached(&ctx, &collateral_token.token_id).await?; + + Ok(Response::new(CollateralToken::from_with_id( + id, + collateral_token, + info, + ))) } -async fn list_vault() -> String { - "List of vaults".to_string() +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct LoanToken { + token_id: String, + token: TokenData, + interest: f64, + // activate_after_block: u32, + // fixed_interval_price_id: String, + // TODO when indexing price + // activePrice?: ActivePrice } -async fn get_vault(Path(vault_id): Path) -> String { - format!("Details of vault with id {}", vault_id) +#[ocean_endpoint] +async fn list_loan_token( + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let tokens = ctx.client.list_loan_tokens().await?; + + struct FlattenToken { + id: String, + data: TokenInfo, + interest: f64, + }; + + let fut = tokens + .into_iter() + .flat_map(|el| { + el.token + .0 + .into_iter() + .next() // Should always get a Hashmap with single entry here. + .map(|(id, data)| FlattenToken { + id, + data, + interest: el.interest, + }) + }) + .paginate(&query, |token| match &query.next { + None => false, + Some(v) => v != &token.id, + }) + .map(|token| async move { + let token = LoanToken { + token_id: token.id.clone(), + token: TokenData::from_with_id(token.id, token.data), + interest: token.interest, + // activate_after_block: todo!(), + // fixed_interval_price_id: todo!(), + }; + Ok::(token) + }) + .collect::>(); + + let res = try_join_all(fut).await?; + + Ok(ApiPagedResponse::of(res, query.size, |loan_scheme| { + loan_scheme.token_id.to_owned() + })) } +// #[ocean_endpoint] +// async fn get_loan_token(Path(token_id): Path) -> String { +// format!("Details of loan token with id {}", token_id) +// } + +// #[ocean_endpoint] +// async fn list_vault() -> String { +// "List of vaults".to_string() +// } + +// #[ocean_endpoint] +// async fn get_vault(Path(vault_id): Path) -> String { +// format!("Details of vault with id {}", vault_id) +// } + +#[ocean_endpoint] async fn list_vault_auction_history( Path((vault_id, height, batch_index)): Path<(Txid, u32, u32)>, Query(query): Query, -) -> Result>> { + Extension(ctx): Extension>, +) -> Result> { debug!( "Auction history for vault id {}, height {}, batch index {}", vault_id, height, batch_index @@ -74,7 +255,8 @@ async fn list_vault_auction_history( let size = if query.size > 0 { query.size } else { 20 }; - let auctions = services + let auctions = ctx + .services .auction .by_height .list(Some((vault_id, batch_index, next.0, next.1)))? @@ -86,7 +268,8 @@ async fn list_vault_auction_history( .map(|item| { let (_, id) = item?; - let auction = services + let auction = ctx + .services .auction .by_id .get(&id)? @@ -96,16 +279,14 @@ async fn list_vault_auction_history( }) .collect::>>()?; - Ok(Json(ApiPagedResponse::of( - auctions, - query.size, - |auction| auction.sort.to_string(), - ))) + Ok(ApiPagedResponse::of(auctions, query.size, |auction| { + auction.sort.to_string() + })) } -async fn list_auction() -> String { - "List of auctions".to_string() -} +// async fn list_auction() -> String { +// "List of auctions".to_string() +// } pub fn router(ctx: Arc) -> Router { Router::new() @@ -114,12 +295,13 @@ pub fn router(ctx: Arc) -> Router { .route("/collaterals", get(list_collateral_token)) .route("/collaterals/:id", get(get_collateral_token)) .route("/tokens", get(list_loan_token)) - .route("/tokens/:id", get(get_loan_token)) - .route("/vaults", get(list_vault)) - .route("/vaults/:id", get(get_vault)) + // .route("/tokens/:id", get(get_loan_token)) + // .route("/vaults", get(list_vault)) + // .route("/vaults/:id", get(get_vault)) .route( "/vaults/:id/auctions/:height/batches/:batchIndex/history", get(list_vault_auction_history), ) - .route("/auctions", get(list_auction)) + // .route("/auctions", get(list_auction)) + .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/api/masternode.rs b/lib/ain-ocean/src/api/masternode.rs index ec3522bf2b3..76b9a1c27d5 100644 --- a/lib/ain-ocean/src/api/masternode.rs +++ b/lib/ain-ocean/src/api/masternode.rs @@ -11,11 +11,11 @@ use bitcoin::Txid; use serde::{Deserialize, Serialize}; use super::{ + query::PaginationQuery, response::{ApiPagedResponse, Response}, AppContext, }; use crate::{ - api_query::PaginationQuery, error::{ApiError, Error, NotFoundKind}, model::Masternode, repository::RepositoryOps, diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index 576a38c1228..861f0d39102 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -6,13 +6,15 @@ use axum::{extract::Request, http::StatusCode, response::IntoResponse, Json, Rou mod block; mod fee; mod governance; -// mod loan; +mod loan; mod masternode; // mod oracle; // mod poolpairs; // mod prices; // mod rawtx; +mod cache; mod common; +mod query; mod response; mod stats; mod tokens; @@ -23,10 +25,6 @@ use serde::{Deserialize, Serialize}; use crate::{Result, Services}; -async fn ocean_not_activated() -> impl IntoResponse { - (StatusCode::FORBIDDEN, "Ocean is not activated") -} - #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] struct NotFound { @@ -64,7 +62,7 @@ pub async fn ocean_router(services: &Arc, client: Arc) -> Resu Ok(Router::new() // .nest("/address", address::router(Arc::clone(&context))) .nest("/governance", governance::router(Arc::clone(&context))) - // .nest("/loans", loan::router(Arc::clone(&context))) + .nest("/loans", loan::router(Arc::clone(&context))) .nest("/fee", fee::router(Arc::clone(&context))) .nest("/masternodes", masternode::router(Arc::clone(&context))) // .nest("/oracles", oracle::router(Arc::clone(&context))) diff --git a/lib/ain-ocean/src/api_query.rs b/lib/ain-ocean/src/api/query.rs similarity index 80% rename from lib/ain-ocean/src/api_query.rs rename to lib/ain-ocean/src/api/query.rs index 5fff3e73c94..0b791910331 100644 --- a/lib/ain-ocean/src/api_query.rs +++ b/lib/ain-ocean/src/api/query.rs @@ -11,12 +11,14 @@ use serde_with::{serde_as, DisplayFromStr}; use crate::error::ApiError; +const DEFAUT_PAGINATION_SIZE: usize = 30; + pub fn default_pagination_size() -> usize { - 30 + DEFAUT_PAGINATION_SIZE } #[serde_as] -#[derive(Deserialize, Default, Debug)] +#[derive(Deserialize, Debug)] pub struct PaginationQuery { #[serde_as(as = "DisplayFromStr")] #[serde(default = "default_pagination_size")] @@ -25,6 +27,15 @@ pub struct PaginationQuery { pub next: Option, } +impl Default for PaginationQuery { + fn default() -> Self { + Self { + size: DEFAUT_PAGINATION_SIZE, + next: None, + } + } +} + fn undefined_to_none<'de, D>(d: D) -> Result, D::Error> where D: Deserializer<'de>, @@ -48,7 +59,9 @@ where async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result { let query = parts.uri.query().unwrap_or_default(); - + if query.is_empty() { + return Ok(Self(T::default())); + } match serde_urlencoded::from_str(query) { Ok(v) => Ok(Query(v)), Err(e) => Err(ApiError::new( diff --git a/lib/ain-ocean/src/api/tokens.rs b/lib/ain-ocean/src/api/tokens.rs index 7504e13a3ca..bb72529eb8b 100644 --- a/lib/ain-ocean/src/api/tokens.rs +++ b/lib/ain-ocean/src/api/tokens.rs @@ -11,14 +11,11 @@ use serde_json::json; use super::{ common::parse_display_symbol, + query::{PaginationQuery, Query}, response::{ApiPagedResponse, Response}, AppContext, }; -use crate::{ - api_query::{PaginationQuery, Query}, - error::ApiError, - Result, Services, -}; +use crate::{error::ApiError, Result}; #[derive(Serialize, Debug, Clone, Default)] pub struct TxHeight { @@ -29,7 +26,7 @@ pub struct TxHeight { #[derive(Serialize, Debug, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct TokenData { - id: u32, + id: String, symbol: String, symbol_key: String, name: String, @@ -52,7 +49,7 @@ pub struct TokenData { } impl TokenData { - fn from_with_id(id: u32, token: TokenInfo) -> Self { + pub fn from_with_id(id: String, token: TokenInfo) -> Self { let display_symbol = parse_display_symbol(&token); Self { id, @@ -110,15 +107,17 @@ async fn list_tokens( .into_iter() .map(|(k, v)| TokenData::from_with_id(k, v)) .collect::>(); - Ok(ApiPagedResponse::of(res, query.size, |token| token.id)) + Ok(ApiPagedResponse::of(res, query.size, |token| { + token.id.clone() + })) } #[ocean_endpoint] async fn get_token( - Path(id): Path, + Path(id): Path, Extension(ctx): Extension>, ) -> Result>> { - let mut v: TokenResult = ctx.client.call("gettoken", &[id.into()]).await?; + let mut v: TokenResult = ctx.client.call("gettoken", &[id.as_str().into()]).await?; let res = if let Some(token) = v.0.remove(&id) { Some(TokenData::from_with_id(id, token)) diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 71dea60f60c..fbc305b4ed8 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -8,7 +8,6 @@ use axum::{ Json, }; use bitcoin::hex::HexToArrayError; -use hyper::client; use log::debug; use serde::Serialize; use thiserror::Error; @@ -19,6 +18,8 @@ pub enum NotFoundKind { Proposal, #[error("masternode")] Masternode, + #[error("scheme")] + Scheme, } #[derive(Error, Debug)] @@ -110,11 +111,17 @@ impl Error { pub fn into_code_and_message(self) -> (StatusCode, String) { let (code, reason) = match &self { Error::RpcError(defichain_rpc::Error::JsonRpc(jsonrpc_async::error::Error::Rpc(e))) => { - debug!("e : {:?}", e); - - (StatusCode::NOT_FOUND, format!("{}", e.message)) + ( + StatusCode::NOT_FOUND, + match e { + e if e.message.contains("Cannot find existing loan scheme") => { + format!("{}", Error::NotFound(NotFoundKind::Scheme)) + } + _ => format!("{}", e.message), + }, + ) } - Error::NotFound(_) => (StatusCode::NOT_FOUND, format!("{}", self)), + Error::NotFound(_) => (StatusCode::NOT_FOUND, format!("{self}")), _ => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()), }; (code, reason) diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 69447a302cc..d9cf152a0bc 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -1,4 +1,3 @@ -pub mod api_query; pub mod error; mod indexer; From 668b8977d413ff2291ff1210cafe71966573763d Mon Sep 17 00:00:00 2001 From: canonbrother Date: Tue, 20 Feb 2024 15:26:24 +0800 Subject: [PATCH 051/185] typo stats/reward/distribution --- lib/ain-ocean/src/api/stats/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ain-ocean/src/api/stats/mod.rs b/lib/ain-ocean/src/api/stats/mod.rs index 6b03851143d..6ad1690ebce 100644 --- a/lib/ain-ocean/src/api/stats/mod.rs +++ b/lib/ain-ocean/src/api/stats/mod.rs @@ -185,7 +185,7 @@ async fn get_burn(Extension(ctx): Extension>) -> Result) -> Router { Router::new() .route("/", get(get_stats)) - .route("/rewards/distribution", get(get_reward_distribution)) + .route("/reward/distribution", get(get_reward_distribution)) .route("/supply", get(get_supply)) .route("/burn", get(get_burn)) .layer(Extension(ctx)) From d2e4d6327f239f02934373d8869181fab4d67058 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Wed, 21 Feb 2024 15:49:31 +0800 Subject: [PATCH 052/185] Fix list block API (#2826) --- lib/ain-ocean/src/api/block.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 0bf31b6c63c..f04de8d9972 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; +use anyhow::format_err; use axum::{extract::Path, routing::get, Extension, Router}; use bitcoin::BlockHash; use serde::{Deserialize, Deserializer}; @@ -10,7 +11,12 @@ use super::{ response::{ApiPagedResponse, Response}, AppContext, }; -use crate::{error::ApiError, model::Block, repository::RepositoryOps, Result}; +use crate::{ + error::{ApiError, Error}, + model::Block, + repository::RepositoryOps, + Result, +}; pub enum HashOrHeight { Height(u32), @@ -38,11 +44,21 @@ async fn list_blocks( Query(query): Query, Extension(ctx): Extension>, ) -> Result> { + let next = query + .next + .map(|q| { + let height = q + .parse::() + .map_err(|_| format_err!("Invalid height"))?; + Ok::(height) + }) + .transpose()?; + let blocks = ctx .services .block .by_height - .list(None)? + .list(next)? .take(query.size) .map(|item| { let (_, id) = item?; @@ -58,7 +74,7 @@ async fn list_blocks( .collect::>>()?; Ok(ApiPagedResponse::of(blocks, query.size, |block| { - block.clone().hash + block.clone().height })) } From dce747f16d705feaf226b311aab6c65082c59668 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Thu, 22 Feb 2024 13:20:31 +0100 Subject: [PATCH 053/185] Ocean: Initial Scan support (#2829) * Fix next not being set * Temporary fix of burn address * Add blocks/:hash/transactions endpoint * Add support for querying list Ascending * handle ocean api network * Don't handle including_start at the iter level * Column implementation to fix ser/deser order issue on usize * Index txs from 0 * Handle including_start through Paginate trait --------- Co-authored-by: canonbrother --- lib/Cargo.lock | 184 +++++++++--------- lib/ain-db/src/lib.rs | 21 +- lib/ain-evm/src/storage/block_store.rs | 11 +- lib/ain-macros/src/lib.rs | 4 +- lib/ain-ocean/src/api/block.rs | 45 ++++- lib/ain-ocean/src/api/common.rs | 14 +- lib/ain-ocean/src/api/loan.rs | 13 +- lib/ain-ocean/src/api/masternode.rs | 7 +- lib/ain-ocean/src/api/mod.rs | 37 ++-- lib/ain-ocean/src/api/query.rs | 1 + lib/ain-ocean/src/api/stats/stats.rs | 18 +- lib/ain-ocean/src/api/transactions.rs | 56 ++++-- lib/ain-ocean/src/indexer/mod.rs | 1 + lib/ain-ocean/src/indexer/transaction.rs | 8 +- lib/ain-ocean/src/lib.rs | 6 +- lib/ain-ocean/src/model/block.rs | 1 + lib/ain-ocean/src/model/transaction.rs | 2 + lib/ain-ocean/src/repository/block.rs | 4 +- .../src/repository/masternode_stats.rs | 4 +- lib/ain-ocean/src/repository/mod.rs | 3 +- lib/ain-ocean/src/repository/transaction.rs | 19 +- .../repository/vault_auction_batch_history.rs | 4 +- lib/ain-ocean/src/storage/columns/mod.rs | 3 +- .../src/storage/columns/transaction.rs | 31 ++- lib/ain-ocean/src/storage/mod.rs | 8 +- 25 files changed, 323 insertions(+), 182 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index e623ed664fd..b0aebf0a99a 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff" +checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" dependencies = [ "cfg-if", "getrandom 0.2.12", @@ -205,7 +205,7 @@ dependencies = [ "serde_json", "serde_with", "sha3", - "syn 2.0.48", + "syn 2.0.50", "tokio", "tonic", "tonic-build", @@ -219,7 +219,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -331,9 +331,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "approx" @@ -401,7 +401,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -423,7 +423,7 @@ checksum = "823b8bb275161044e2ac7a25879cb3e2480cb403e3943022c7c769c599b756aa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -474,7 +474,7 @@ dependencies = [ "http 1.0.0", "http-body 1.0.0", "http-body-util", - "hyper 1.1.0", + "hyper 1.2.0", "hyper-util", "itoa", "matchit", @@ -542,7 +542,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -645,7 +645,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -821,7 +821,7 @@ dependencies = [ "proc-macro-crate 2.0.2", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", "syn_derive", ] @@ -876,9 +876,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "a3b1be7772ee4501dba05acbe66bb1e8760f6a6c474a36035631638e4415f130" [[package]] name = "byte-slice-cast" @@ -962,7 +962,7 @@ version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "355face540df58778b96814c48abb3c2ed67c4878a8087ab1819c1fedeec505f" dependencies = [ - "ahash 0.8.8", + "ahash 0.8.9", "async-trait", "cached_proc_macro", "cached_proc_macro_types", @@ -994,11 +994,10 @@ checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730" dependencies = [ - "jobserver", "libc", ] @@ -1268,9 +1267,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aff472b83efd22bfc0176aa8ba34617dd5c17364670eb201a5f06d339b8abf7" +checksum = "0c15f3b597018782655a05d417f28bac009f6eb60f4b6703eb818998c1aaa16a" dependencies = [ "cc", "cxxbridge-flags", @@ -1280,9 +1279,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf6e7a52c19013a9a0ec421c7d9c2d1125faf333551227e0a017288d71b47c3" +checksum = "81699747d109bba60bd6f87e7cb24b626824b8427b32f199b95c7faa06ee3dc9" dependencies = [ "cc", "codespan-reporting", @@ -1290,36 +1289,36 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "cxx-gen" -version = "0.7.116" +version = "0.7.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2a39f7064dacffa9bf2d33d8dcc7777b60c789a95e1cd62d5fbeb1161428f2" +checksum = "54b629c0d006c7e44c1444dd17d18a458c9390d32276b758ac7abd21a75c99b0" dependencies = [ "codespan-reporting", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "cxxbridge-flags" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589e83d02fc1d4fb78f5ad56ca08835341e23499d086d2821315869426d618dc" +checksum = "7a7eb4c4fd18505f5a935f9c2ee77780350dcdb56da7cd037634e806141c5c43" [[package]] name = "cxxbridge-macro" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2cb1fd8ffae4230c7cfbbaf3698dbeaf750fa8c5dadf7ed897df581b9b572a5" +checksum = "5d914fcc6452d133236ee067a9538be25ba6a644a450e1a6c617da84bf029854" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -1367,7 +1366,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -1389,13 +1388,13 @@ checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be" dependencies = [ "darling_core 0.20.6", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "defichain-rpc" version = "0.18.0" -source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#324f8cf4bf0973be34ae1bb6da26de21b29f03fd" +source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#b69ac6600113d7869b1311381237de0b41debddc" dependencies = [ "async-trait", "defichain-rpc-json", @@ -1408,7 +1407,7 @@ dependencies = [ [[package]] name = "defichain-rpc-json" version = "0.18.0" -source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#324f8cf4bf0973be34ae1bb6da26de21b29f03fd" +source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#b69ac6600113d7869b1311381237de0b41debddc" dependencies = [ "bitcoin", "serde", @@ -1449,24 +1448,24 @@ dependencies = [ [[package]] name = "deunicode" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae2a35373c5c74340b79ae6780b498b2b183915ec5dacf263aac5a099bf485a" +checksum = "b6e854126756c496b8c81dec88f9a706b15b875c5849d4097a3854476b9fdf94" [[package]] name = "dftx-macro" version = "0.1.0" -source = "git+https://github.com/Jouzo/dftx-rs.git#c6ff7772f6bfe8a6d0804c40b2f53f3de69e295e" +source = "git+https://github.com/Jouzo/dftx-rs.git#869a8ceee86c8e98d3a6a3acc7a8abf8fb2f150c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "dftx-rs" version = "0.1.0" -source = "git+https://github.com/Jouzo/dftx-rs.git#c6ff7772f6bfe8a6d0804c40b2f53f3de69e295e" +source = "git+https://github.com/Jouzo/dftx-rs.git#869a8ceee86c8e98d3a6a3acc7a8abf8fb2f150c" dependencies = [ "anyhow", "bitcoin", @@ -1835,7 +1834,7 @@ dependencies = [ "path-slash", "rayon", "regex", - "semver 1.0.21", + "semver 1.0.22", "serde", "serde_json", "solang-parser", @@ -2076,7 +2075,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -2281,7 +2280,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.8", + "ahash 0.8.9", ] [[package]] @@ -2290,7 +2289,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.8", + "ahash 0.8.9", "allocator-api2", ] @@ -2503,9 +2502,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5aa53871fc917b1a9ed87b683a5d86db645e23acb32c2e0785a353e522fb75" +checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" dependencies = [ "bytes", "futures-channel", @@ -2517,6 +2516,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", + "smallvec", "tokio", ] @@ -2559,7 +2559,7 @@ dependencies = [ "futures-util", "http 1.0.0", "http-body 1.0.0", - "hyper 1.1.0", + "hyper 1.2.0", "pin-project-lite", "socket2", "tokio", @@ -2744,15 +2744,6 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" -[[package]] -name = "jobserver" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" -dependencies = [ - "libc", -] - [[package]] name = "js-sys" version = "0.3.68" @@ -3547,7 +3538,7 @@ dependencies = [ "proc-macro-crate 2.0.2", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -3772,7 +3763,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -3810,7 +3801,7 @@ checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -3876,7 +3867,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" dependencies = [ "proc-macro2", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -4250,7 +4241,7 @@ checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -4374,16 +4365,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom 0.2.12", "libc", "spin 0.9.8", "untrusted", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -4607,9 +4599,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "safe_arch" @@ -4670,7 +4662,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" dependencies = [ - "ahash 0.8.8", + "ahash 0.8.9", "cfg-if", "hashbrown 0.13.2", ] @@ -4817,9 +4809,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" dependencies = [ "serde", ] @@ -4832,29 +4824,29 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -4910,7 +4902,7 @@ dependencies = [ "darling 0.20.6", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -5171,7 +5163,7 @@ checksum = "f12dae7cf6c1e825d13ffd4ce16bd9309db7c539929d0302b4443ed451a9f4e5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -5265,7 +5257,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -5329,7 +5321,7 @@ version = "23.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf63ea90ffb5d61048d8fb2fac669114dac198fc2739e913e615f0fd2c36c3e7" dependencies = [ - "ahash 0.8.8", + "ahash 0.8.9", "hash-db 0.16.0", "hashbrown 0.13.2", "lazy_static", @@ -5494,7 +5486,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -5540,7 +5532,7 @@ dependencies = [ "hex", "once_cell", "reqwest", - "semver 1.0.21", + "semver 1.0.22", "serde", "serde_json", "sha2 0.10.8", @@ -5562,9 +5554,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" dependencies = [ "proc-macro2", "quote", @@ -5580,7 +5572,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -5690,14 +5682,14 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -5823,7 +5815,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -6013,7 +6005,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -6166,9 +6158,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -6364,7 +6356,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", "wasm-bindgen-shared", ] @@ -6398,7 +6390,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6878,7 +6870,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] @@ -6898,7 +6890,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.50", ] [[package]] diff --git a/lib/ain-db/src/lib.rs b/lib/ain-db/src/lib.rs index bf69f1c6b84..60d7ade7405 100644 --- a/lib/ain-db/src/lib.rs +++ b/lib/ain-db/src/lib.rs @@ -9,8 +9,8 @@ use std::{ use anyhow::format_err; use bincode; use rocksdb::{ - BlockBasedOptions, Cache, ColumnFamily, ColumnFamilyDescriptor, DBIterator, IteratorMode, - Options, DB, + BlockBasedOptions, Cache, ColumnFamily, ColumnFamilyDescriptor, DBIterator, Direction, + IteratorMode, Options, DB, }; use serde::{de::DeserializeOwned, Serialize}; @@ -181,16 +181,22 @@ where pub fn iter( &self, from: Option, + direction: Direction, ) -> Result> + '_> { - let skip = if from.as_ref().is_some() { 1 } else { 0 }; let index = from .as_ref() .map(|i| C::key(i)) .transpose()? .unwrap_or_default(); - let iterator_mode = from.map_or(IteratorMode::End, |_| { - IteratorMode::From(&index, rocksdb::Direction::Reverse) - }); + + let iterator_mode = match direction { + Direction::Forward => from.map_or(IteratorMode::Start, |_| { + IteratorMode::From(&index, Direction::Forward) + }), + Direction::Reverse => from.map_or(IteratorMode::End, |_| { + IteratorMode::From(&index, Direction::Reverse) + }), + }; Ok(self .backend .iterator_cf::(self.handle()?, iterator_mode) @@ -199,8 +205,7 @@ where let value = bincode::deserialize(&value)?; let key = C::get_key(key)?; Ok((key, value)) - }) - .skip(skip)) + })) } } diff --git a/lib/ain-evm/src/storage/block_store.rs b/lib/ain-evm/src/storage/block_store.rs index dee2042b5df..7dec5d2ec85 100644 --- a/lib/ain-evm/src/storage/block_store.rs +++ b/lib/ain-evm/src/storage/block_store.rs @@ -237,7 +237,10 @@ impl Rollback for BlockStore { let block_deployed_codes_cf = self.column::(); let address_codes_cf = self.column::(); - for item in block_deployed_codes_cf.iter(Some((block.header.number, H160::zero())))? { + for item in block_deployed_codes_cf.iter( + Some((block.header.number, H160::zero())), + rocksdb::Direction::Reverse, + )? { let ((block_number, address), hash) = item?; if block_number == block.header.number { @@ -325,7 +328,11 @@ impl BlockStore { let response_max_size = usize::try_from(ain_cpp_imports::get_max_response_byte_size()) .map_err(|_| format_err!("failed to convert response size limit to usize"))?; - for item in self.column::().iter(from)?.take(limit) { + for item in self + .column::() + .iter(from, rocksdb::Direction::Reverse)? + .take(limit) + { let (k, v) = item?; if out.len() > response_max_size { diff --git a/lib/ain-macros/src/lib.rs b/lib/ain-macros/src/lib.rs index bab85414385..5f8bf923646 100644 --- a/lib/ain-macros/src/lib.rs +++ b/lib/ain-macros/src/lib.rs @@ -113,9 +113,9 @@ pub fn repository_derive(input: TokenStream) -> TokenStream { Ok(self.col.delete(id)?) } - fn list<'a>(&'a self, from: Option<#key_type_ident>) -> Result> + 'a>> + fn list<'a>(&'a self, from: Option<#key_type_ident>, dir: crate::storage::SortOrder) -> Result> + 'a>> { - let it = self.col.iter(from)?; + let it = self.col.iter(from, dir.into())?; Ok(Box::new(it)) } } diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index f04de8d9972..2504e2d8990 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -12,9 +12,11 @@ use super::{ AppContext, }; use crate::{ + api::common::Paginate, error::{ApiError, Error}, - model::Block, + model::{Block, Transaction}, repository::RepositoryOps, + storage::SortOrder, Result, }; @@ -46,6 +48,7 @@ async fn list_blocks( ) -> Result> { let next = query .next + .as_ref() .map(|q| { let height = q .parse::() @@ -58,8 +61,8 @@ async fn list_blocks( .services .block .by_height - .list(next)? - .take(query.size) + .list(next, SortOrder::Descending)? + .paginate(&query) .map(|item| { let (_, id) = item?; let b = ctx @@ -95,11 +98,43 @@ async fn get_block( Ok(Response::new(block)) } +#[ocean_endpoint] async fn get_transactions( Path(hash): Path, + Query(query): Query, Extension(ctx): Extension>, -) -> String { - format!("Transactions for block with hash {}", hash) +) -> Result> { + let next = query.next.as_ref().map_or(Ok((hash, 0)), |q| { + let height = q + .parse::() + .map_err(|_| format_err!("Invalid height"))?; + Ok::<(BlockHash, usize), Error>((hash, height)) + })?; + + let txs = ctx + .services + .transaction + .by_block_hash + .list(Some(next), SortOrder::Ascending)? + .paginate(&query) + .take_while(|item| match item { + Ok(((h, _), _)) => h == &hash, + _ => true, + }) + .map(|item| { + let (_, id) = item?; + let tx = ctx + .services + .transaction + .by_id + .get(&id)? + .ok_or("Missing tx index")?; + + Ok(tx) + }) + .collect::>>()?; + + Ok(ApiPagedResponse::of(txs, query.size, |tx| tx.order)) } // Get highest indexed block diff --git a/lib/ain-ocean/src/api/common.rs b/lib/ain-ocean/src/api/common.rs index b4a6c60ee24..665cc3ff141 100644 --- a/lib/ain-ocean/src/api/common.rs +++ b/lib/ain-ocean/src/api/common.rs @@ -107,27 +107,32 @@ pub fn find_token_balance(tokens: Vec, symbol: &str) -> Decimal { /// .list_loan_schemes() /// .await? /// .into_iter() -/// .paginate(&query, skip_while) +/// .fake_paginate(&query, skip_while) /// .collect(); /// /// assert!(res.len() <= query.size, "The result should not contain more items than the specified limit"); /// assert!(res[0].id > query.next.unwrap(), "The result should start after the requested start id"); /// ``` pub trait Paginate<'a, T>: Iterator + Sized { - fn paginate( + fn fake_paginate( self, query: &PaginationQuery, skip_while: F, ) -> Box + 'a> where F: FnMut(&T) -> bool + 'a; + fn paginate(self, query: &PaginationQuery) -> Box + 'a>; } impl<'a, T, I> Paginate<'a, T> for I where I: Iterator + 'a, { - fn paginate(self, query: &PaginationQuery, skip_while: F) -> Box + 'a> + fn fake_paginate( + self, + query: &PaginationQuery, + skip_while: F, + ) -> Box + 'a> where F: FnMut(&T) -> bool + 'a, { @@ -137,4 +142,7 @@ where .take(query.size), ) } + fn paginate(self, query: &PaginationQuery) -> Box + 'a> { + Box::new(self.skip(query.next.is_some() as usize).take(query.size)) + } } diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index 42970172701..f3be5bdfe95 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -27,6 +27,7 @@ use crate::{ error::{ApiError, Error, NotFoundKind}, model::VaultAuctionBatchHistory, repository::RepositoryOps, + storage::SortOrder, Result, }; @@ -63,7 +64,7 @@ async fn list_scheme( .list_loan_schemes() .await? .into_iter() - .paginate(&query, skip_while) + .fake_paginate(&query, skip_while) .map(Into::into) .collect(); Ok(ApiPagedResponse::of(res, query.size, |loan_scheme| { @@ -76,7 +77,6 @@ async fn get_scheme( Path(scheme_id): Path, Extension(ctx): Extension>, ) -> Result> { - println!("[get_scheme]"); Ok(Response::new( ctx.client.get_loan_scheme(scheme_id).await?.into(), )) @@ -120,7 +120,7 @@ async fn list_collateral_token( let fut = tokens .into_iter() - .paginate(&query, skip_while) + .fake_paginate(&query, skip_while) .map(|v| async { let (id, info) = get_token_cached(&ctx, &v.token_id).await?; Ok::(CollateralToken::from_with_id(id, v, info)) @@ -187,7 +187,7 @@ async fn list_loan_token( interest: el.interest, }) }) - .paginate(&query, |token| match &query.next { + .fake_paginate(&query, |token| match &query.next { None => false, Some(v) => v != &token.id, }) @@ -259,7 +259,10 @@ async fn list_vault_auction_history( .services .auction .by_height - .list(Some((vault_id, batch_index, next.0, next.1)))? + .list( + Some((vault_id, batch_index, next.0, next.1)), + SortOrder::Descending, + )? .take(size) .take_while(|item| match item { Ok((k, _)) => k.0 == vault_id && k.1 == batch_index, diff --git a/lib/ain-ocean/src/api/masternode.rs b/lib/ain-ocean/src/api/masternode.rs index 76b9a1c27d5..72c07ffbd49 100644 --- a/lib/ain-ocean/src/api/masternode.rs +++ b/lib/ain-ocean/src/api/masternode.rs @@ -16,9 +16,11 @@ use super::{ AppContext, }; use crate::{ + api::common::Paginate, error::{ApiError, Error, NotFoundKind}, model::Masternode, repository::RepositoryOps, + storage::SortOrder, Result, }; @@ -105,6 +107,7 @@ async fn list_masternodes( ) -> Result> { let next = query .next + .as_ref() .map(|q| { let height = q[0..8] .parse::() @@ -121,8 +124,8 @@ async fn list_masternodes( .services .masternode .by_height - .list(next)? - .take(query.size) + .list(next, SortOrder::Descending)? + .paginate(&query) .map(|item| { let ((_, id), _) = item?; let mn = ctx diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index 861f0d39102..91fa882f162 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -18,7 +18,7 @@ mod query; mod response; mod stats; mod tokens; -// mod transactions; +mod transactions; use defichain_rpc::Client; use serde::{Deserialize, Serialize}; @@ -59,19 +59,24 @@ pub async fn ocean_router(services: &Arc, client: Arc) -> Resu services: services.clone(), }); - Ok(Router::new() - // .nest("/address", address::router(Arc::clone(&context))) - .nest("/governance", governance::router(Arc::clone(&context))) - .nest("/loans", loan::router(Arc::clone(&context))) - .nest("/fee", fee::router(Arc::clone(&context))) - .nest("/masternodes", masternode::router(Arc::clone(&context))) - // .nest("/oracles", oracle::router(Arc::clone(&context))) - // .nest("/poolpairs", poolpairs::router(Arc::clone(&context))) - // .nest("/prices", prices::router(Arc::clone(&context))) - // .nest("/rawtx", rawtx::router(Arc::clone(&context))) - .nest("/stats", stats::router(Arc::clone(&context))) - .nest("/tokens", tokens::router(Arc::clone(&context))) - // .nest("/transactions", transactions::router(Arc::clone(&context))) - .nest("/blocks", block::router(Arc::clone(&context))) - .fallback(not_found)) + let network = ain_cpp_imports::get_network(); + + Ok(Router::new().nest( + format!("/v0/{network}").as_str(), + Router::new() + // .nest("/address/", address::router(Arc::clone(&context))) + .nest("/governance", governance::router(Arc::clone(&context))) + .nest("/loans", loan::router(Arc::clone(&context))) + .nest("/fee", fee::router(Arc::clone(&context))) + .nest("/masternodes", masternode::router(Arc::clone(&context))) + // .nest("/oracles", oracle::router(Arc::clone(&context))) + // .nest("/poolpairs", poolpairs::router(Arc::clone(&context))) + // .nest("/prices", prices::router(Arc::clone(&context))) + // .nest("/rawtx", rawtx::router(Arc::clone(&context))) + .nest("/stats", stats::router(Arc::clone(&context))) + .nest("/tokens", tokens::router(Arc::clone(&context))) + .nest("/transactions", transactions::router(Arc::clone(&context))) + .nest("/blocks", block::router(Arc::clone(&context))) + .fallback(not_found), + )) } diff --git a/lib/ain-ocean/src/api/query.rs b/lib/ain-ocean/src/api/query.rs index 0b791910331..ba095161f0e 100644 --- a/lib/ain-ocean/src/api/query.rs +++ b/lib/ain-ocean/src/api/query.rs @@ -23,6 +23,7 @@ pub struct PaginationQuery { #[serde_as(as = "DisplayFromStr")] #[serde(default = "default_pagination_size")] pub size: usize, + #[serde(default)] #[serde(deserialize_with = "undefined_to_none")] pub next: Option, } diff --git a/lib/ain-ocean/src/api/stats/stats.rs b/lib/ain-ocean/src/api/stats/stats.rs index 1078cf066c0..aa4e2f80d0a 100644 --- a/lib/ain-ocean/src/api/stats/stats.rs +++ b/lib/ain-ocean/src/api/stats/stats.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; use cached::proc_macro::cached; use defichain_rpc::{ @@ -100,6 +100,17 @@ pub async fn get_count(ctx: &Arc) -> Result { }) } +// TODO Shove it into network struct when available +lazy_static::lazy_static! { + pub static ref BURN_ADDRESS: HashMap<&'static str, &'static str> = HashMap::from([ + ("mainnet", "8defichainBurnAddressXXXXXXXdRQkSm"), + ("testnet", "7DefichainBurnAddressXXXXXXXdMUE5n"), + ("devnet", "7DefichainBurnAddressXXXXXXXdMUE5n"), + ("changi", "7DefichainBurnAddressXXXXXXXdMUE5n"), + ("regtest", "mfburnZSAM7Gs1hpDeNaMotJXSGA7edosG"), + ]); +} + #[cached( result = true, time = 1800, @@ -107,8 +118,9 @@ pub async fn get_count(ctx: &Arc) -> Result { convert = r#"{ format!("burned_total") }"# )] pub async fn get_burned_total(client: &Client) -> Result { - static ADDRESS: &'static str = "76a914f7874e8821097615ec345f74c7e5bcf61b12e2ee88ac"; - let mut tokens = client.get_account(ADDRESS, None, Some(true)).await?; + let network = ain_cpp_imports::get_network(); + let burn_address = BURN_ADDRESS.get(network.as_str()).unwrap(); + let mut tokens = client.get_account(&burn_address, None, Some(true)).await?; let burn_info = client.get_burn_info().await?; let utxo = Decimal::from_f64(burn_info.amount).ok_or(Error::DecimalError)?; diff --git a/lib/ain-ocean/src/api/transactions.rs b/lib/ain-ocean/src/api/transactions.rs index 4f566813c1c..097c543044e 100644 --- a/lib/ain-ocean/src/api/transactions.rs +++ b/lib/ain-ocean/src/api/transactions.rs @@ -1,17 +1,22 @@ +use std::sync::Arc; + +use ain_macros::ocean_endpoint; use axum::{ extract::{Path, Query}, routing::get, - Json, Router, + Extension, Json, Router, }; use bitcoin::Txid; use serde::Deserialize; +use super::{query::PaginationQuery, response::ApiPagedResponse, AppContext}; use crate::{ - api_paged_response::ApiPagedResponse, - api_query::PaginationQuery, + api::response::Response, + error::ApiError, model::{Transaction, TransactionVin, TransactionVout}, repository::RepositoryOps, - services, Result, + storage::SortOrder, + Result, }; #[derive(Deserialize)] @@ -19,25 +24,31 @@ struct TransactionId { id: Txid, } +#[ocean_endpoint] async fn get_transaction( Path(TransactionId { id }): Path, -) -> Result>> { + Extension(ctx): Extension>, +) -> Result>> { format!("Details of transaction with id {}", id); - let transactions = services.transaction.by_id.get(&id)?; - Ok(Json(transactions)) + let transactions = ctx.services.transaction.by_id.get(&id)?; + Ok(Response::new(transactions)) } +#[ocean_endpoint] async fn get_vins( Query(query): Query, -) -> Result>> { - let transaction_list = services + Extension(ctx): Extension>, +) -> Result> { + let transaction_list = ctx + .services .transaction .vin_by_id - .list(None)? + .list(None, SortOrder::Descending)? .take(query.size) .map(|item| { let (txid, id) = item?; - let b = services + let b = ctx + .services .transaction .vin_by_id .get(&txid)? @@ -47,25 +58,29 @@ async fn get_vins( }) .collect::>>()?; - Ok(Json(ApiPagedResponse::of( + Ok(ApiPagedResponse::of( transaction_list, query.size, |transaction_list| transaction_list.id.clone(), - ))) + )) } //get list of vout transaction, by passing id which contains txhash + vout_idx +#[ocean_endpoint] async fn get_vouts( Query(query): Query, -) -> Result>> { - let transaction_list = services + Extension(ctx): Extension>, +) -> Result> { + let transaction_list = ctx + .services .transaction .vout_by_id - .list(None)? + .list(None, SortOrder::Descending)? .take(query.size) .map(|item| { let (txid, id) = item?; - let b = services + let b = ctx + .services .transaction .vout_by_id .get(&txid)? @@ -75,11 +90,11 @@ async fn get_vouts( }) .collect::>>()?; - Ok(Json(ApiPagedResponse::of( + Ok(ApiPagedResponse::of( transaction_list, query.size, - |transaction_list| transaction_list.id.clone(), - ))) + |transaction_list| transaction_list.txid.to_string(), + )) } pub fn router(ctx: Arc) -> Router { @@ -87,4 +102,5 @@ pub fn router(ctx: Arc) -> Router { .route("/:id", get(get_transaction)) .route("/:id/vins", get(get_vins)) .route("/:id/vouts", get(get_vouts)) + .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index de37977f284..7257c412629 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -49,6 +49,7 @@ pub fn index_block(services: &Arc, block: Block) -> Resul let block_mapper = BlockMapper { hash: block_hash, + id: block_hash, previous_hash: block.previousblockhash, height: block.height, version: block.version, diff --git a/lib/ain-ocean/src/indexer/transaction.rs b/lib/ain-ocean/src/indexer/transaction.rs index 1bf5270418e..b4607e3e9ec 100644 --- a/lib/ain-ocean/src/indexer/transaction.rs +++ b/lib/ain-ocean/src/indexer/transaction.rs @@ -56,9 +56,11 @@ pub fn index_transaction(services: &Arc, ctx: Context) -> Result<()> { services.transaction.vin_by_id.put(&vin.id, &vin)?; } + let order = idx; + let tx = TransactionMapper { id: txid, - order: idx, + order, hash: ctx.tx.hash.clone(), block: ctx.block.clone(), version: ctx.tx.version, @@ -72,6 +74,10 @@ pub fn index_transaction(services: &Arc, ctx: Context) -> Result<()> { }; // Index transaction services.transaction.by_id.put(&txid, &tx)?; + services + .transaction + .by_block_hash + .put(&(ctx.block.hash, order), &txid)?; Ok(()) } diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index d9cf152a0bc..33ee035f8c4 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -9,8 +9,8 @@ pub use indexer::{index_block, invalidate_block, transaction::index_transaction, use repository::{ AuctionHistoryByHeightRepository, AuctionHistoryRepository, BlockByHeightRepository, BlockRepository, MasternodeByHeightRepository, MasternodeRepository, MasternodeStatsRepository, - PoolSwapRepository, RawBlockRepository, TransactionRepository, TransactionVinRepository, - TransactionVoutRepository, TxResultRepository, + PoolSwapRepository, RawBlockRepository, TransactionByBlockHashRepository, + TransactionRepository, TransactionVinRepository, TransactionVoutRepository, TxResultRepository, }; pub mod api; mod model; @@ -54,6 +54,7 @@ pub struct PoolService { pub struct TransactionService { by_id: TransactionRepository, + by_block_hash: TransactionByBlockHashRepository, vin_by_id: TransactionVinRepository, vout_by_id: TransactionVoutRepository, } @@ -90,6 +91,7 @@ impl Services { }, transaction: TransactionService { by_id: TransactionRepository::new(Arc::clone(&store)), + by_block_hash: TransactionByBlockHashRepository::new(Arc::clone(&store)), vin_by_id: TransactionVinRepository::new(Arc::clone(&store)), vout_by_id: TransactionVoutRepository::new(Arc::clone(&store)), }, diff --git a/lib/ain-ocean/src/model/block.rs b/lib/ain-ocean/src/model/block.rs index 8a4ca76c9be..8131f2db708 100644 --- a/lib/ain-ocean/src/model/block.rs +++ b/lib/ain-ocean/src/model/block.rs @@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize}; #[serde(rename_all = "camelCase")] pub struct Block { pub hash: BlockHash, + pub id: BlockHash, pub previous_hash: Option, pub height: u32, pub version: i32, diff --git a/lib/ain-ocean/src/model/transaction.rs b/lib/ain-ocean/src/model/transaction.rs index c98f45e919d..1ba344e05be 100644 --- a/lib/ain-ocean/src/model/transaction.rs +++ b/lib/ain-ocean/src/model/transaction.rs @@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize}; use super::BlockContext; +pub type TransactionByBlockHashKey = (BlockHash, usize); + #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Transaction { diff --git a/lib/ain-ocean/src/repository/block.rs b/lib/ain-ocean/src/repository/block.rs index 21eea96c683..6107ae6e7d7 100644 --- a/lib/ain-ocean/src/repository/block.rs +++ b/lib/ain-ocean/src/repository/block.rs @@ -7,7 +7,7 @@ use bitcoin::BlockHash; use super::RepositoryOps; use crate::{ model::Block, - storage::{columns, ocean_store::OceanStore}, + storage::{columns, ocean_store::OceanStore, SortOrder}, Result, }; @@ -45,7 +45,7 @@ impl BlockByHeightRepository { impl BlockByHeightRepository { pub fn get_highest(&self) -> Result> { - match self.col.iter(None)?.next() { + match self.col.iter(None, SortOrder::Descending.into())?.next() { None => Ok(None), Some(Ok((_, id))) => { let col = self.store.column::(); diff --git a/lib/ain-ocean/src/repository/masternode_stats.rs b/lib/ain-ocean/src/repository/masternode_stats.rs index c7fe6340abc..e81657a564a 100644 --- a/lib/ain-ocean/src/repository/masternode_stats.rs +++ b/lib/ain-ocean/src/repository/masternode_stats.rs @@ -6,7 +6,7 @@ use ain_macros::Repository; use super::RepositoryOps; use crate::{ model::MasternodeStats, - storage::{columns, ocean_store::OceanStore}, + storage::{columns, ocean_store::OceanStore, SortOrder}, Result, }; @@ -28,7 +28,7 @@ impl MasternodeStatsRepository { impl MasternodeStatsRepository { pub fn get_latest(&self) -> Result> { - match self.col.iter(None)?.next() { + match self.col.iter(None, SortOrder::Descending.into())?.next() { None => Ok(None), Some(Ok((_, id))) => Ok(Some(id)), Some(Err(e)) => Err(e.into()), diff --git a/lib/ain-ocean/src/repository/mod.rs b/lib/ain-ocean/src/repository/mod.rs index a8b9f282a4f..0ddf3600f25 100644 --- a/lib/ain-ocean/src/repository/mod.rs +++ b/lib/ain-ocean/src/repository/mod.rs @@ -1,4 +1,4 @@ -use crate::Result; +use crate::{storage::SortOrder, Result}; mod block; mod masternode; @@ -51,5 +51,6 @@ pub trait RepositoryOps { fn list<'a>( &'a self, from: Option, + dir: SortOrder, ) -> Result> + 'a>>; } diff --git a/lib/ain-ocean/src/repository/transaction.rs b/lib/ain-ocean/src/repository/transaction.rs index 3a92b97ffc0..13582235394 100644 --- a/lib/ain-ocean/src/repository/transaction.rs +++ b/lib/ain-ocean/src/repository/transaction.rs @@ -6,10 +6,11 @@ use bitcoin::Txid; use super::RepositoryOps; use crate::{ - model::Transaction, + model::{Transaction, TransactionByBlockHashKey}, storage::{columns, ocean_store::OceanStore}, Result, }; + #[derive(Repository)] #[repository(K = "Txid", V = "Transaction")] pub struct TransactionRepository { @@ -25,3 +26,19 @@ impl TransactionRepository { } } } + +#[derive(Repository)] +#[repository(K = "TransactionByBlockHashKey", V = "Txid")] +pub struct TransactionByBlockHashRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl TransactionByBlockHashRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} diff --git a/lib/ain-ocean/src/repository/vault_auction_batch_history.rs b/lib/ain-ocean/src/repository/vault_auction_batch_history.rs index 5e1b370e576..b429b7dc704 100644 --- a/lib/ain-ocean/src/repository/vault_auction_batch_history.rs +++ b/lib/ain-ocean/src/repository/vault_auction_batch_history.rs @@ -6,7 +6,7 @@ use ain_macros::Repository; use super::RepositoryOps; use crate::{ model::{AuctionHistoryByHeightKey, AuctionHistoryKey, VaultAuctionBatchHistory}, - storage::{columns, ocean_store::OceanStore}, + storage::{columns, ocean_store::OceanStore, SortOrder}, Result, }; @@ -44,7 +44,7 @@ impl AuctionHistoryByHeightRepository { impl AuctionHistoryByHeightRepository { pub fn get_latest(&self) -> Result> { - match self.list(None)?.next() { + match self.list(None, SortOrder::Descending)?.next() { None => Ok(None), Some(Ok((_, id))) => { let col = self.store.column::(); diff --git a/lib/ain-ocean/src/storage/columns/mod.rs b/lib/ain-ocean/src/storage/columns/mod.rs index d892df2bfe8..d8d573889a6 100644 --- a/lib/ain-ocean/src/storage/columns/mod.rs +++ b/lib/ain-ocean/src/storage/columns/mod.rs @@ -43,7 +43,7 @@ pub use transaction_vout::*; pub use tx_result::*; pub use vault_auction_history::*; -pub const COLUMN_NAMES: [&'static str; 24] = [ +pub const COLUMN_NAMES: [&'static str; 25] = [ block::Block::NAME, block::BlockByHeight::NAME, masternode_stats::MasternodeStats::NAME, @@ -63,6 +63,7 @@ pub const COLUMN_NAMES: [&'static str; 24] = [ script_aggregation::ScriptAggregation::NAME, script_unspent::ScriptUnspent::NAME, transaction::Transaction::NAME, + transaction::TransactionByBlockHash::NAME, transaction_vin::TransactionVin::NAME, transaction_vout::TransactionVout::NAME, tx_result::TxResult::NAME, diff --git a/lib/ain-ocean/src/storage/columns/transaction.rs b/lib/ain-ocean/src/storage/columns/transaction.rs index d3fefc45584..8f104f15b1c 100644 --- a/lib/ain-ocean/src/storage/columns/transaction.rs +++ b/lib/ain-ocean/src/storage/columns/transaction.rs @@ -1,5 +1,7 @@ -use ain_db::{Column, ColumnName, TypedColumn}; -use bitcoin::{BlockHash, Txid}; +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, BlockHash, Txid}; +use log::debug; use crate::model; #[derive(Debug)] @@ -24,9 +26,30 @@ impl ColumnName for TransactionByBlockHash { } impl Column for TransactionByBlockHash { - type Index = BlockHash; + type Index = model::TransactionByBlockHashKey; + + fn key(index: &Self::Index) -> Result, DBError> { + let (hash, txno) = index; + let mut vec = hash.as_byte_array().to_vec(); + vec.extend_from_slice(&txno.to_be_bytes()); + Ok(vec) + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + if raw_key.len() != 40 { + return Err(format_err!("Length of the slice is not 40").into()); + } + let mut hash_array = [0u8; 32]; + hash_array.copy_from_slice(&raw_key[..32]); + let mut txno_array = [0u8; 8]; + txno_array.copy_from_slice(&raw_key[32..]); + + let hash = BlockHash::from_byte_array(hash_array); + let txno = usize::from_be_bytes(txno_array); + Ok((hash, txno)) + } } impl TypedColumn for TransactionByBlockHash { - type Type = model::Transaction; + type Type = Txid; } diff --git a/lib/ain-ocean/src/storage/mod.rs b/lib/ain-ocean/src/storage/mod.rs index c73816d91fb..25828fe4959 100644 --- a/lib/ain-ocean/src/storage/mod.rs +++ b/lib/ain-ocean/src/storage/mod.rs @@ -1,4 +1,4 @@ -use rocksdb::IteratorMode; +use rocksdb::Direction; pub mod columns; pub mod ocean_store; @@ -9,11 +9,11 @@ pub enum SortOrder { Descending, } -impl<'a> From for IteratorMode<'a> { +impl From for Direction { fn from(sort_order: SortOrder) -> Self { match sort_order { - SortOrder::Ascending => IteratorMode::Start, - SortOrder::Descending => IteratorMode::End, + SortOrder::Ascending => Direction::Forward, + SortOrder::Descending => Direction::Reverse, } } } From d4b9bb34670ace317396fbce371025f4fc9d8357 Mon Sep 17 00:00:00 2001 From: jouzo Date: Fri, 23 Feb 2024 09:10:46 +0100 Subject: [PATCH 054/185] Fix block indexing --- lib/ain-ocean/src/indexer/mod.rs | 96 +++++++++++++++++--------------- 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 7257c412629..05c3ee3089b 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -8,7 +8,7 @@ pub mod tx_result; use std::{sync::Arc, time::Instant}; use defichain_rpc::json::blockchain::{Block, Transaction}; -use dftx_rs::{deserialize, DfTx}; +use dftx_rs::{deserialize, DfTx, Stack}; use log::debug; use crate::{ @@ -24,6 +24,7 @@ pub(crate) trait Index { fn invalidate(&self, services: &Arc, ctx: &Context) -> Result<()>; } +#[derive(Debug)] pub struct Context { block: BlockContext, tx: Transaction, @@ -40,6 +41,7 @@ pub fn index_block(services: &Arc, block: Block) -> Resul let start = Instant::now(); let block_hash = block.hash; + let transaction_count = block.tx.len(); let block_ctx = BlockContext { height: block.height, hash: block_hash, @@ -47,6 +49,53 @@ pub fn index_block(services: &Arc, block: Block) -> Resul median_time: block.mediantime, }; + for (tx_idx, tx) in block.tx.into_iter().enumerate() { + let start = Instant::now(); + let ctx = Context { + block: block_ctx.clone(), + tx, + tx_idx, + }; + + let bytes = &ctx.tx.vout[0].script_pub_key.hex; + if bytes.len() > 6 && bytes[0] == 0x6a && bytes[1] <= 0x4e { + let offset = 1 + match bytes[1] { + 0x4c => 2, + 0x4d => 3, + 0x4e => 4, + _ => 1, + }; + + let raw_tx = &bytes[offset..]; + match deserialize::(raw_tx) { + Err(bitcoin::consensus::encode::Error::ParseFailed("Invalid marker")) => { + println!("Discarding invalid marker"); + } + Err(e) => return Err(e.into()), + Ok(Stack { dftx, .. }) => { + match &dftx { + DfTx::CreateMasternode(data) => data.index(services, &ctx)?, + DfTx::UpdateMasternode(data) => data.index(services, &ctx)?, + DfTx::ResignMasternode(data) => data.index(services, &ctx)?, + // DfTx::AppointOracle(data) => data.index(services,&ctx)?, + // DfTx::RemoveOracle(data) => data.index(services,&ctx)?, + // DfTx::UpdateOracle(data) => data.index(services,&ctx)?, + // DfTx::SetOracleData(data) => data.index(services,&ctx)?, + DfTx::PoolSwap(data) => data.index(services, &ctx)?, + DfTx::CompositeSwap(data) => data.index(services, &ctx)?, + DfTx::PlaceAuctionBid(data) => data.index(services, &ctx)?, + _ => (), + } + log_elapsed(start, &format!("Indexed dftx")); + } + } + } + + index_transaction(services, ctx)?; + } + + log_elapsed(start, "Indexed block"); + let block_mapper = BlockMapper { hash: block_hash, id: block_hash, @@ -55,7 +104,7 @@ pub fn index_block(services: &Arc, block: Block) -> Resul version: block.version, time: block.time, median_time: block.mediantime, - transaction_count: block.tx.len(), + transaction_count, difficulty: block.difficulty, masternode: block.masternode, minter: block.minter, @@ -74,49 +123,6 @@ pub fn index_block(services: &Arc, block: Block) -> Resul .by_height .put(&block_ctx.height, &block_hash)?; - for (tx_idx, tx) in block.tx.into_iter().enumerate() { - let start = Instant::now(); - let ctx = Context { - block: block_ctx.clone(), - tx, - tx_idx, - }; - - let bytes = &ctx.tx.vout[0].script_pub_key.hex; - if bytes.len() > 2 && bytes[0] == 0x6a && bytes[1] <= 0x4e { - let offset = 1 + match bytes[1] { - 0x4c => 2, - 0x4d => 3, - 0x4e => 4, - _ => 1, - }; - - let raw_tx = &bytes[offset..]; - let dftx = deserialize::(raw_tx)?; - debug!("dftx : {:?}", dftx); - - match &dftx { - DfTx::CreateMasternode(data) => data.index(services, &ctx)?, - DfTx::UpdateMasternode(data) => data.index(services, &ctx)?, - DfTx::ResignMasternode(data) => data.index(services, &ctx)?, - // DfTx::AppointOracle(data) => data.index(services,&ctx)?, - // DfTx::RemoveOracle(data) => data.index(services,&ctx)?, - // DfTx::UpdateOracle(data) => data.index(services,&ctx)?, - // DfTx::SetOracleData(data) => data.index(services,&ctx)?, - DfTx::PoolSwap(data) => data.index(services, &ctx)?, - DfTx::CompositeSwap(data) => data.index(services, &ctx)?, - DfTx::PlaceAuctionBid(data) => data.index(services, &ctx)?, - - _ => (), - } - log_elapsed(start, &format!("Indexed tx {:?}", dftx)); - } - - index_transaction(services, ctx)?; - } - - log_elapsed(start, "Indexed block"); - Ok(()) } From 3c123d21245ffba9385c84ed60461964f5503e24 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Fri, 23 Feb 2024 17:36:34 +0800 Subject: [PATCH 055/185] Ocean: fix ocean api tx get (#2831) * serialize f64 to string * missing txid at struct Transaction * custom path rejection * fmt_rs --- lib/ain-ocean/src/api/mod.rs | 1 + lib/ain-ocean/src/api/path.rs | 102 +++++++++++++++++++++++ lib/ain-ocean/src/api/transactions.rs | 8 +- lib/ain-ocean/src/indexer/transaction.rs | 1 + lib/ain-ocean/src/model/transaction.rs | 8 +- 5 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 lib/ain-ocean/src/api/path.rs diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index 91fa882f162..a0cf7f9e3b6 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -14,6 +14,7 @@ mod masternode; // mod rawtx; mod cache; mod common; +mod path; mod query; mod response; mod stats; diff --git a/lib/ain-ocean/src/api/path.rs b/lib/ain-ocean/src/api/path.rs new file mode 100644 index 00000000000..029879b3c28 --- /dev/null +++ b/lib/ain-ocean/src/api/path.rs @@ -0,0 +1,102 @@ +use axum::{ + async_trait, + extract::{path::ErrorKind, rejection::PathRejection, FromRequestParts}, + http::{request::Parts, StatusCode}, +}; +use serde::{de::DeserializeOwned, Serialize}; + +use crate::error::ApiError; + +// We define our own `Path` extractor that customizes the error from `axum::extract::Path` +#[derive(Debug)] +pub struct Path(pub T); + +#[async_trait] +impl FromRequestParts for Path +where + // these trait bounds are copied from `impl FromRequest for axum::extract::path::Path` + T: DeserializeOwned + Send, + S: Send + Sync, +{ + type Rejection = ApiError; + + async fn from_request_parts(parts: &mut Parts, state: &S) -> Result { + match axum::extract::Path::::from_request_parts(parts, state).await { + Ok(value) => Ok(Self(value.0)), + Err(rejection) => { + let error = match rejection { + PathRejection::FailedToDeserializePathParams(inner) => { + let kind = inner.into_kind(); + let error = match &kind { + ErrorKind::WrongNumberOfParameters { .. } => ApiError::new( + StatusCode::BAD_REQUEST, + kind.to_string(), + parts.uri.to_string(), + ), + + ErrorKind::ParseErrorAtKey { key, .. } => ApiError::new( + StatusCode::BAD_REQUEST, + format!("key: {key}, {kind}"), + parts.uri.to_string(), + ), + + ErrorKind::ParseErrorAtIndex { index, .. } => ApiError::new( + StatusCode::BAD_REQUEST, + format!("index: {index}, {kind}"), + parts.uri.to_string(), + ), + + ErrorKind::ParseError { .. } => ApiError::new( + StatusCode::BAD_REQUEST, + kind.to_string(), + parts.uri.to_string(), + ), + + ErrorKind::InvalidUtf8InPathParam { key } => ApiError::new( + StatusCode::BAD_REQUEST, + format!("key: {key}, {kind}"), + parts.uri.to_string(), + ), + + ErrorKind::UnsupportedType { .. } => { + // this error is caused by the programmer using an unsupported type + // (such as nested maps) so respond with `500` instead + ApiError::new( + StatusCode::INTERNAL_SERVER_ERROR, + kind.to_string(), + parts.uri.to_string(), + ) + } + + ErrorKind::Message(msg) => ApiError::new( + StatusCode::BAD_REQUEST, + msg.clone(), + parts.uri.to_string(), + ), + + _ => ApiError::new( + StatusCode::BAD_REQUEST, + format!("Unhandled deserialization error: {kind}"), + parts.uri.to_string(), + ), + }; + + error + } + PathRejection::MissingPathParams(error) => ApiError::new( + StatusCode::INTERNAL_SERVER_ERROR, + error.to_string(), + parts.uri.to_string(), + ), + _ => ApiError::new( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Unhandled path rejection: {rejection}"), + parts.uri.to_string(), + ), + }; + + Err(error) + } + } + } +} diff --git a/lib/ain-ocean/src/api/transactions.rs b/lib/ain-ocean/src/api/transactions.rs index 097c543044e..04c310f03b5 100644 --- a/lib/ain-ocean/src/api/transactions.rs +++ b/lib/ain-ocean/src/api/transactions.rs @@ -1,15 +1,11 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; -use axum::{ - extract::{Path, Query}, - routing::get, - Extension, Json, Router, -}; +use axum::{extract::Query, routing::get, Extension, Router}; use bitcoin::Txid; use serde::Deserialize; -use super::{query::PaginationQuery, response::ApiPagedResponse, AppContext}; +use super::{path::Path, query::PaginationQuery, response::ApiPagedResponse, AppContext}; use crate::{ api::response::Response, error::ApiError, diff --git a/lib/ain-ocean/src/indexer/transaction.rs b/lib/ain-ocean/src/indexer/transaction.rs index b4607e3e9ec..5d99adf295d 100644 --- a/lib/ain-ocean/src/indexer/transaction.rs +++ b/lib/ain-ocean/src/indexer/transaction.rs @@ -60,6 +60,7 @@ pub fn index_transaction(services: &Arc, ctx: Context) -> Result<()> { let tx = TransactionMapper { id: txid, + txid, order, hash: ctx.tx.hash.clone(), block: ctx.block.clone(), diff --git a/lib/ain-ocean/src/model/transaction.rs b/lib/ain-ocean/src/model/transaction.rs index 1ba344e05be..bbe713b54e9 100644 --- a/lib/ain-ocean/src/model/transaction.rs +++ b/lib/ain-ocean/src/model/transaction.rs @@ -1,21 +1,25 @@ use bitcoin::{BlockHash, Txid}; use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, DisplayFromStr}; use super::BlockContext; pub type TransactionByBlockHashKey = (BlockHash, usize); +#[serde_as] #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Transaction { - pub id: Txid, - pub order: usize, + pub id: Txid, // unique id of the transaction, same as the txid + pub txid: Txid, + pub order: usize, // tx order pub block: BlockContext, pub hash: String, pub version: u32, pub size: u64, pub v_size: u64, pub weight: u64, + #[serde_as(as = "DisplayFromStr")] pub total_vout_value: f64, pub lock_time: u64, pub vin_count: usize, From 4db943bf8068f1ea05cd527419f57006bbff38ae Mon Sep 17 00:00:00 2001 From: jouzo Date: Fri, 23 Feb 2024 14:05:32 +0100 Subject: [PATCH 056/185] Revert Column default impl --- lib/ain-evm/src/storage/db.rs | 85 +++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 4 deletions(-) diff --git a/lib/ain-evm/src/storage/db.rs b/lib/ain-evm/src/storage/db.rs index c4176b471b4..e16d6281b3b 100644 --- a/lib/ain-evm/src/storage/db.rs +++ b/lib/ain-evm/src/storage/db.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use ain_db::{Column, ColumnName, DBError, Result, TypedColumn}; use ethereum::{BlockAny, TransactionV2}; use ethereum_types::{H160, H256, U256}; @@ -102,42 +102,119 @@ pub const COLUMN_NAMES: [&'static str; 8] = [ impl Column for columns::Transactions { type Index = H256; + + fn key(index: &Self::Index) -> Result> { + Ok(index.as_bytes().to_vec()) + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + Ok(Self::Index::from_slice(&raw_key)) + } } impl Column for columns::Blocks { type Index = U256; + + fn key(index: &Self::Index) -> Result> { + let mut bytes = [0_u8; 32]; + index.to_big_endian(&mut bytes); + Ok(bytes.to_vec()) + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + Ok(Self::Index::from(&*raw_key)) + } } impl Column for columns::Receipts { type Index = H256; + + fn key(index: &Self::Index) -> Result> { + Ok(index.to_fixed_bytes().to_vec()) + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + Ok(Self::Index::from_slice(&raw_key)) + } } impl Column for columns::BlockMap { type Index = H256; + + fn key(index: &Self::Index) -> Result> { + Ok(index.to_fixed_bytes().to_vec()) + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + Ok(Self::Index::from_slice(&raw_key)) + } } impl Column for columns::LatestBlockNumber { type Index = String; - fn key(_index: &Self::Index) -> Result, DBError> { + fn key(_index: &Self::Index) -> Result> { Ok(b"latest".to_vec()) } - fn get_key(_raw_key: Box<[u8]>) -> Result { - Ok(String::from("latest")) + fn get_key(_raw_key: Box<[u8]>) -> Result { + Ok("latest".to_string()) } } impl Column for columns::AddressLogsMap { type Index = U256; + + fn key(index: &Self::Index) -> Result> { + let mut bytes = [0_u8; 32]; + index.to_big_endian(&mut bytes); + Ok(bytes.to_vec()) + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + Ok(Self::Index::from(&*raw_key)) + } } impl Column for columns::AddressCodeMap { type Index = (H160, H256); + + fn key(index: &Self::Index) -> Result> { + let mut bytes = Vec::with_capacity(20 + 32); + bytes.extend_from_slice(&index.0.to_fixed_bytes()); + bytes.extend_from_slice(&index.1.to_fixed_bytes()); + Ok(bytes) + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + let address = H160::from_slice(&raw_key[..20]); + let code_hash = H256::from_slice(&raw_key[20..]); + Ok((address, code_hash)) + } } impl Column for columns::BlockDeployedCodeHashes { type Index = (U256, H160); + + fn key(index: &Self::Index) -> Result> { + let mut u256_bytes = [0_u8; 32]; + index.0.to_big_endian(&mut u256_bytes); + + let mut bytes = Vec::with_capacity(32 + 20); + bytes.extend_from_slice(&u256_bytes); + bytes.extend_from_slice(&index.1.to_fixed_bytes()); + Ok(bytes) + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + let u256_bytes = &raw_key[0..32]; + let h160_bytes = &raw_key[32..52]; + + let u256 = U256::from_big_endian(u256_bytes); + let h160 = H160::from_slice(h160_bytes); + + Ok((u256, h160)) + } } // From e567c134cd65a125fb3626c05912079f61cb1b12 Mon Sep 17 00:00:00 2001 From: jouzo Date: Fri, 23 Feb 2024 14:09:47 +0100 Subject: [PATCH 057/185] Revert cache changes --- lib/ain-evm/src/storage/cache.rs | 69 ++++++++++++++++---------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/lib/ain-evm/src/storage/cache.rs b/lib/ain-evm/src/storage/cache.rs index b645cdc5bdf..2c81ce46625 100644 --- a/lib/ain-evm/src/storage/cache.rs +++ b/lib/ain-evm/src/storage/cache.rs @@ -3,16 +3,18 @@ use std::{borrow::ToOwned, num::NonZeroUsize, sync::RwLock}; use ethereum::{BlockAny, TransactionV2}; use ethereum_types::{H256, U256}; use lru::LruCache; +use parking_lot::Mutex; use super::traits::{BlockStorage, Rollback, TransactionStorage}; use crate::Result; #[derive(Debug)] pub struct Cache { - transactions: RwLock>, - blocks: RwLock>, - block_hashes: RwLock>, + transactions: Mutex>, + blocks: Mutex>, + block_hashes: Mutex>, latest_block: RwLock>, + contract_code: Mutex>>, } impl Cache { @@ -20,13 +22,16 @@ impl Cache { pub fn new(cache_size: Option) -> Self { Cache { - transactions: RwLock::new(LruCache::new( + transactions: Mutex::new(LruCache::new( NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), )), - blocks: RwLock::new(LruCache::new( + blocks: Mutex::new(LruCache::new( NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), )), - block_hashes: RwLock::new(LruCache::new( + block_hashes: Mutex::new(LruCache::new( + NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), + )), + contract_code: Mutex::new(LruCache::new( NonZeroUsize::new(cache_size.unwrap_or(Self::DEFAULT_CACHE_SIZE)).unwrap(), )), latest_block: RwLock::new(None), @@ -36,19 +41,13 @@ impl Cache { impl BlockStorage for Cache { fn get_block_by_number(&self, number: &U256) -> Result> { - let block = self - .blocks - .write() - .unwrap() - .get(number) - .map(ToOwned::to_owned); + let block = self.blocks.lock().get(number).map(ToOwned::to_owned); Ok(block) } fn get_block_by_hash(&self, block_hash: &H256) -> Result> { self.block_hashes - .write() - .unwrap() + .lock() .get(block_hash) .map_or(Ok(None), |block_number| { self.get_block_by_number(block_number) @@ -60,11 +59,8 @@ impl BlockStorage for Cache { let block_number = block.header.number; let hash = block.header.hash(); - self.blocks - .write() - .unwrap() - .put(block_number, block.clone()); - self.block_hashes.write().unwrap().put(hash, block_number); + self.blocks.lock().put(block_number, block.clone()); + self.block_hashes.lock().put(hash, block_number); Ok(()) } @@ -87,7 +83,7 @@ impl BlockStorage for Cache { impl TransactionStorage for Cache { fn extend_transactions_from_block(&self, block: &BlockAny) -> Result<()> { - let mut cache = self.transactions.write().unwrap(); + let mut cache = self.transactions.lock(); for transaction in &block.transactions { let hash = transaction.hash(); @@ -97,12 +93,7 @@ impl TransactionStorage for Cache { } fn get_transaction_by_hash(&self, hash: &H256) -> Result> { - let transaction = self - .transactions - .write() - .unwrap() - .get(hash) - .map(ToOwned::to_owned); + let transaction = self.transactions.lock().get(hash).map(ToOwned::to_owned); Ok(transaction) } @@ -112,8 +103,7 @@ impl TransactionStorage for Cache { index: usize, ) -> Result> { self.block_hashes - .write() - .unwrap() + .lock() .get(block_hash) .map_or(Ok(None), |block_number| { self.get_transaction_by_block_number_and_index(block_number, index) @@ -127,8 +117,7 @@ impl TransactionStorage for Cache { ) -> Result> { let transaction = self .blocks - .write() - .unwrap() + .lock() .get(block_number) .and_then(|block| block.transactions.get(index).map(ToOwned::to_owned)); Ok(transaction) @@ -136,8 +125,7 @@ impl TransactionStorage for Cache { fn put_transaction(&self, transaction: &TransactionV2) -> Result<()> { self.transactions - .write() - .unwrap() + .lock() .put(transaction.hash(), transaction.clone()); Ok(()) } @@ -146,13 +134,13 @@ impl TransactionStorage for Cache { impl Rollback for Cache { fn disconnect_latest_block(&self) -> Result<()> { if let Some(block) = self.get_latest_block()? { - let mut transaction_cache = self.transactions.write().unwrap(); + let mut transaction_cache = self.transactions.lock(); for tx in &block.transactions { transaction_cache.pop(&tx.hash()); } - self.block_hashes.write().unwrap().pop(&block.header.hash()); - self.blocks.write().unwrap().pop(&block.header.number); + self.block_hashes.lock().pop(&block.header.hash()); + self.blocks.lock().pop(&block.header.number); let previous_block = self.get_block_by_hash(&block.header.parent_hash)?; self.put_latest_block(previous_block.as_ref())?; @@ -160,3 +148,14 @@ impl Rollback for Cache { Ok(()) } } + +impl Cache { + pub fn get_code_by_hash(&self, hash: &H256) -> Result>> { + Ok(self.contract_code.lock().get(hash).map(ToOwned::to_owned)) + } + + pub fn put_code(&self, hash: H256, code: &[u8]) -> Result<()> { + self.contract_code.lock().put(hash, code.to_vec()); + Ok(()) + } +} From f4679ad741020e4951273758e8f9c239ff733532 Mon Sep 17 00:00:00 2001 From: jouzo Date: Fri, 23 Feb 2024 14:12:12 +0100 Subject: [PATCH 058/185] Revert code cache changes --- lib/ain-evm/src/storage/mod.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/ain-evm/src/storage/mod.rs b/lib/ain-evm/src/storage/mod.rs index d3ee93c5b9a..00f5eda18dc 100644 --- a/lib/ain-evm/src/storage/mod.rs +++ b/lib/ain-evm/src/storage/mod.rs @@ -193,7 +193,17 @@ impl FlushableStorage for Storage { impl Storage { pub fn get_code_by_hash(&self, address: H160, hash: H256) -> Result>> { - self.blockstore.get_code_by_hash(address, &hash) + match self.cache.get_code_by_hash(&hash) { + Ok(Some(code)) => Ok(Some(code)), + Ok(None) => { + let code = self.blockstore.get_code_by_hash(address, &hash); + if let Ok(Some(ref code)) = code { + self.cache.put_code(hash, code)?; + } + code + } + Err(e) => Err(e), + } } pub fn put_code( From 544ac6b4e6d947e990daf23fbe930e0e27dfd2a9 Mon Sep 17 00:00:00 2001 From: jouzo Date: Fri, 23 Feb 2024 14:17:06 +0100 Subject: [PATCH 059/185] Clippy cleanup --- lib/ain-evm/src/storage/db.rs | 2 +- lib/ain-ocean/src/api/common.rs | 1 - lib/ain-ocean/src/api/governance.rs | 2 +- lib/ain-ocean/src/api/loan.rs | 7 +++---- lib/ain-ocean/src/api/path.rs | 2 +- lib/ain-ocean/src/api/transactions.rs | 2 +- lib/ain-ocean/src/error.rs | 1 - lib/ain-ocean/src/storage/columns/transaction.rs | 1 - 8 files changed, 7 insertions(+), 11 deletions(-) diff --git a/lib/ain-evm/src/storage/db.rs b/lib/ain-evm/src/storage/db.rs index e16d6281b3b..a5977f87b7e 100644 --- a/lib/ain-evm/src/storage/db.rs +++ b/lib/ain-evm/src/storage/db.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use ain_db::{Column, ColumnName, DBError, Result, TypedColumn}; +use ain_db::{Column, ColumnName, Result, TypedColumn}; use ethereum::{BlockAny, TransactionV2}; use ethereum_types::{H160, H256, U256}; diff --git a/lib/ain-ocean/src/api/common.rs b/lib/ain-ocean/src/api/common.rs index 665cc3ff141..f1906e98f3a 100644 --- a/lib/ain-ocean/src/api/common.rs +++ b/lib/ain-ocean/src/api/common.rs @@ -1,6 +1,5 @@ use defichain_rpc::json::token::TokenInfo; use rust_decimal::Decimal; -use serde::{Deserialize, Serialize}; use super::query::PaginationQuery; diff --git a/lib/ain-ocean/src/api/governance.rs b/lib/ain-ocean/src/api/governance.rs index 36e04abaece..9870ab347f4 100644 --- a/lib/ain-ocean/src/api/governance.rs +++ b/lib/ain-ocean/src/api/governance.rs @@ -13,7 +13,7 @@ use super::{ }; use crate::{ error::{ApiError, Error, NotFoundKind}, - Result, Services, + Result, }; #[derive(Deserialize, Default)] diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index f3be5bdfe95..a820f328b64 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -1,12 +1,11 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; -use anyhow::format_err; use axum::{extract::Path, routing::get, Extension, Router}; use bitcoin::Txid; use defichain_rpc::{ defichain_rpc_json::{ - loan::{CollateralTokenDetail, LoanSchemeResult, LoanTokenResult}, + loan::{CollateralTokenDetail, LoanSchemeResult}, token::TokenInfo, }, LoanRPC, @@ -24,7 +23,7 @@ use super::{ AppContext, }; use crate::{ - error::{ApiError, Error, NotFoundKind}, + error::{ApiError, Error}, model::VaultAuctionBatchHistory, repository::RepositoryOps, storage::SortOrder, @@ -172,7 +171,7 @@ async fn list_loan_token( id: String, data: TokenInfo, interest: f64, - }; + } let fut = tokens .into_iter() diff --git a/lib/ain-ocean/src/api/path.rs b/lib/ain-ocean/src/api/path.rs index 029879b3c28..3e288b8b67e 100644 --- a/lib/ain-ocean/src/api/path.rs +++ b/lib/ain-ocean/src/api/path.rs @@ -3,7 +3,7 @@ use axum::{ extract::{path::ErrorKind, rejection::PathRejection, FromRequestParts}, http::{request::Parts, StatusCode}, }; -use serde::{de::DeserializeOwned, Serialize}; +use serde::de::DeserializeOwned; use crate::error::ApiError; diff --git a/lib/ain-ocean/src/api/transactions.rs b/lib/ain-ocean/src/api/transactions.rs index 04c310f03b5..0583233678f 100644 --- a/lib/ain-ocean/src/api/transactions.rs +++ b/lib/ain-ocean/src/api/transactions.rs @@ -74,7 +74,7 @@ async fn get_vouts( .list(None, SortOrder::Descending)? .take(query.size) .map(|item| { - let (txid, id) = item?; + let (txid, _) = item?; let b = ctx .services .transaction diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index fbc305b4ed8..c3fd95034ce 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -8,7 +8,6 @@ use axum::{ Json, }; use bitcoin::hex::HexToArrayError; -use log::debug; use serde::Serialize; use thiserror::Error; diff --git a/lib/ain-ocean/src/storage/columns/transaction.rs b/lib/ain-ocean/src/storage/columns/transaction.rs index 8f104f15b1c..3d48b099b5c 100644 --- a/lib/ain-ocean/src/storage/columns/transaction.rs +++ b/lib/ain-ocean/src/storage/columns/transaction.rs @@ -1,7 +1,6 @@ use ain_db::{Column, ColumnName, DBError, TypedColumn}; use anyhow::format_err; use bitcoin::{hashes::Hash, BlockHash, Txid}; -use log::debug; use crate::model; #[derive(Debug)] From bba99a68e46e37c1fb3938383681bd97a7f0e8db Mon Sep 17 00:00:00 2001 From: jouzo Date: Fri, 23 Feb 2024 17:40:22 +0100 Subject: [PATCH 060/185] Fix TransactionId visibility --- lib/ain-ocean/src/api/transactions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ain-ocean/src/api/transactions.rs b/lib/ain-ocean/src/api/transactions.rs index 0583233678f..b9b52aa92bf 100644 --- a/lib/ain-ocean/src/api/transactions.rs +++ b/lib/ain-ocean/src/api/transactions.rs @@ -16,7 +16,7 @@ use crate::{ }; #[derive(Deserialize)] -struct TransactionId { +pub struct TransactionId { id: Txid, } From 4b4e871bf384934d1b79ea1ef4ebb0504c52c452 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Fri, 23 Feb 2024 17:40:53 +0100 Subject: [PATCH 061/185] dftx-rs as crate (#2832) --- lib/Cargo.lock | 115 +++--- lib/Cargo.toml | 2 +- lib/ain-dftx/Cargo.toml | 14 + lib/ain-dftx/src/custom_tx.rs | 135 +++++++ lib/ain-dftx/src/lib.rs | 41 +++ lib/ain-dftx/src/types/account.rs | 58 +++ lib/ain-dftx/src/types/balance.rs | 24 ++ lib/ain-dftx/src/types/common.rs | 171 +++++++++ lib/ain-dftx/src/types/evmtx.rs | 7 + lib/ain-dftx/src/types/governance.rs | 171 +++++++++ lib/ain-dftx/src/types/icxorderbook.rs | 60 +++ lib/ain-dftx/src/types/loans.rs | 77 ++++ lib/ain-dftx/src/types/masternode.rs | 72 ++++ lib/ain-dftx/src/types/mod.rs | 343 ++++++++++++++++++ lib/ain-dftx/src/types/oracles.rs | 34 ++ lib/ain-dftx/src/types/pool.rs | 67 ++++ lib/ain-dftx/src/types/price.rs | 22 ++ lib/ain-dftx/src/types/token.rs | 85 +++++ lib/ain-dftx/src/types/vault.rs | 45 +++ lib/ain-dftx/tests/account.rs | 17 + lib/ain-dftx/tests/block.rs | 30 ++ lib/ain-dftx/tests/data/accounttoaccount.txt | 5 + lib/ain-dftx/tests/data/accounttoutxos.txt | 3 + .../tests/data/anyaccountoaccount.txt | 4 + lib/ain-dftx/tests/data/appointoracle.txt | 1 + lib/ain-dftx/tests/data/autoauthprep.txt | 1 + lib/ain-dftx/tests/data/block.txt | 4 + lib/ain-dftx/tests/data/closevault.txt | 3 + lib/ain-dftx/tests/data/compositeswap.txt | 4 + lib/ain-dftx/tests/data/createcfp.txt | 1 + lib/ain-dftx/tests/data/createmasternode.txt | 7 + lib/ain-dftx/tests/data/createvault.txt | 3 + lib/ain-dftx/tests/data/createvoc.txt | 1 + lib/ain-dftx/tests/data/deposittovault.txt | 3 + lib/ain-dftx/tests/data/destroyloanscheme.txt | 3 + lib/ain-dftx/tests/data/evmtx.txt | 2 + lib/ain-dftx/tests/data/futureswap.txt | 7 + lib/ain-dftx/tests/data/icxclaimdfchtlc.txt | 3 + lib/ain-dftx/tests/data/icxcloseoffer.txt | 3 + lib/ain-dftx/tests/data/icxcloseorder.txt | 3 + lib/ain-dftx/tests/data/icxcreateorder.txt | 5 + lib/ain-dftx/tests/data/icxmakeoffer.txt | 5 + lib/ain-dftx/tests/data/icxsubmitdfchtlc.txt | 3 + lib/ain-dftx/tests/data/icxsubmitexthtlc.txt | 3 + lib/ain-dftx/tests/data/paybackloan.txt | 3 + lib/ain-dftx/tests/data/paybackloanv2.txt | 3 + lib/ain-dftx/tests/data/placeauctionbid.txt | 3 + lib/ain-dftx/tests/data/pooladdliquidity.txt | 6 + lib/ain-dftx/tests/data/poolcreatepair.txt | 17 + .../tests/data/poolremoveliquidity.txt | 10 + lib/ain-dftx/tests/data/poolswap.txt | 13 + lib/ain-dftx/tests/data/poolupdatepair.txt | 7 + lib/ain-dftx/tests/data/removeoracle.txt | 1 + lib/ain-dftx/tests/data/resignmasternode.txt | 2 + lib/ain-dftx/tests/data/scriptbalances.txt | 0 .../tests/data/setcollateraltoken.txt | 3 + .../tests/data/setdefaultloanscheme.txt | 1 + lib/ain-dftx/tests/data/setgovernance.txt | 13 + .../tests/data/setgovernanceheight.txt | 8 + lib/ain-dftx/tests/data/setloanscheme.txt | 3 + lib/ain-dftx/tests/data/setloantoken.txt | 3 + lib/ain-dftx/tests/data/setoracledata.txt | 1 + lib/ain-dftx/tests/data/takeloan.txt | 3 + lib/ain-dftx/tests/data/tokenbalance.txt | 0 lib/ain-dftx/tests/data/tokenburn.txt | 3 + lib/ain-dftx/tests/data/tokencreate.txt | 8 + lib/ain-dftx/tests/data/tokenmint.txt | 4 + lib/ain-dftx/tests/data/tokenupdate.txt | 1 + lib/ain-dftx/tests/data/tokenupdateany.txt | 3 + lib/ain-dftx/tests/data/transferdomain.txt | 2 + lib/ain-dftx/tests/data/updateloantoken.txt | 3 + lib/ain-dftx/tests/data/updatemasternode.txt | 9 + lib/ain-dftx/tests/data/updateoracle.txt | 1 + lib/ain-dftx/tests/data/updatevault.txt | 3 + lib/ain-dftx/tests/data/utxostoaccount.txt | 10 + lib/ain-dftx/tests/data/vote.txt | 3 + lib/ain-dftx/tests/data/withdrawfromvault.txt | 3 + lib/ain-dftx/tests/evmtx.rs | 5 + lib/ain-dftx/tests/governance.rs | 21 ++ lib/ain-dftx/tests/icxorderbook.rs | 29 ++ lib/ain-dftx/tests/loans.rs | 37 ++ lib/ain-dftx/tests/masternode.rs | 13 + lib/ain-dftx/tests/oracles.rs | 75 ++++ lib/ain-dftx/tests/pool.rs | 25 ++ lib/ain-dftx/tests/token.rs | 21 ++ lib/ain-dftx/tests/vault.rs | 25 ++ lib/ain-macros/src/lib.rs | 72 +++- lib/ain-ocean/Cargo.toml | 2 +- lib/ain-ocean/src/indexer/auction.rs | 2 +- lib/ain-ocean/src/indexer/masternode.rs | 2 +- lib/ain-ocean/src/indexer/mod.rs | 2 +- lib/ain-ocean/src/indexer/oracle.rs | 2 +- lib/ain-ocean/src/indexer/pool.rs | 2 +- lib/ain-ocean/src/model/tx_result.rs | 2 +- lib/ain-rs-exports/Cargo.toml | 2 +- 95 files changed, 2086 insertions(+), 73 deletions(-) create mode 100644 lib/ain-dftx/Cargo.toml create mode 100644 lib/ain-dftx/src/custom_tx.rs create mode 100644 lib/ain-dftx/src/lib.rs create mode 100644 lib/ain-dftx/src/types/account.rs create mode 100644 lib/ain-dftx/src/types/balance.rs create mode 100644 lib/ain-dftx/src/types/common.rs create mode 100644 lib/ain-dftx/src/types/evmtx.rs create mode 100644 lib/ain-dftx/src/types/governance.rs create mode 100644 lib/ain-dftx/src/types/icxorderbook.rs create mode 100644 lib/ain-dftx/src/types/loans.rs create mode 100644 lib/ain-dftx/src/types/masternode.rs create mode 100644 lib/ain-dftx/src/types/mod.rs create mode 100644 lib/ain-dftx/src/types/oracles.rs create mode 100644 lib/ain-dftx/src/types/pool.rs create mode 100644 lib/ain-dftx/src/types/price.rs create mode 100644 lib/ain-dftx/src/types/token.rs create mode 100644 lib/ain-dftx/src/types/vault.rs create mode 100644 lib/ain-dftx/tests/account.rs create mode 100644 lib/ain-dftx/tests/block.rs create mode 100644 lib/ain-dftx/tests/data/accounttoaccount.txt create mode 100644 lib/ain-dftx/tests/data/accounttoutxos.txt create mode 100644 lib/ain-dftx/tests/data/anyaccountoaccount.txt create mode 100644 lib/ain-dftx/tests/data/appointoracle.txt create mode 100644 lib/ain-dftx/tests/data/autoauthprep.txt create mode 100644 lib/ain-dftx/tests/data/block.txt create mode 100644 lib/ain-dftx/tests/data/closevault.txt create mode 100644 lib/ain-dftx/tests/data/compositeswap.txt create mode 100644 lib/ain-dftx/tests/data/createcfp.txt create mode 100644 lib/ain-dftx/tests/data/createmasternode.txt create mode 100644 lib/ain-dftx/tests/data/createvault.txt create mode 100644 lib/ain-dftx/tests/data/createvoc.txt create mode 100644 lib/ain-dftx/tests/data/deposittovault.txt create mode 100644 lib/ain-dftx/tests/data/destroyloanscheme.txt create mode 100644 lib/ain-dftx/tests/data/evmtx.txt create mode 100644 lib/ain-dftx/tests/data/futureswap.txt create mode 100644 lib/ain-dftx/tests/data/icxclaimdfchtlc.txt create mode 100644 lib/ain-dftx/tests/data/icxcloseoffer.txt create mode 100644 lib/ain-dftx/tests/data/icxcloseorder.txt create mode 100644 lib/ain-dftx/tests/data/icxcreateorder.txt create mode 100644 lib/ain-dftx/tests/data/icxmakeoffer.txt create mode 100644 lib/ain-dftx/tests/data/icxsubmitdfchtlc.txt create mode 100644 lib/ain-dftx/tests/data/icxsubmitexthtlc.txt create mode 100644 lib/ain-dftx/tests/data/paybackloan.txt create mode 100644 lib/ain-dftx/tests/data/paybackloanv2.txt create mode 100644 lib/ain-dftx/tests/data/placeauctionbid.txt create mode 100644 lib/ain-dftx/tests/data/pooladdliquidity.txt create mode 100644 lib/ain-dftx/tests/data/poolcreatepair.txt create mode 100644 lib/ain-dftx/tests/data/poolremoveliquidity.txt create mode 100644 lib/ain-dftx/tests/data/poolswap.txt create mode 100644 lib/ain-dftx/tests/data/poolupdatepair.txt create mode 100644 lib/ain-dftx/tests/data/removeoracle.txt create mode 100644 lib/ain-dftx/tests/data/resignmasternode.txt create mode 100644 lib/ain-dftx/tests/data/scriptbalances.txt create mode 100644 lib/ain-dftx/tests/data/setcollateraltoken.txt create mode 100644 lib/ain-dftx/tests/data/setdefaultloanscheme.txt create mode 100644 lib/ain-dftx/tests/data/setgovernance.txt create mode 100644 lib/ain-dftx/tests/data/setgovernanceheight.txt create mode 100644 lib/ain-dftx/tests/data/setloanscheme.txt create mode 100644 lib/ain-dftx/tests/data/setloantoken.txt create mode 100644 lib/ain-dftx/tests/data/setoracledata.txt create mode 100644 lib/ain-dftx/tests/data/takeloan.txt create mode 100644 lib/ain-dftx/tests/data/tokenbalance.txt create mode 100644 lib/ain-dftx/tests/data/tokenburn.txt create mode 100644 lib/ain-dftx/tests/data/tokencreate.txt create mode 100644 lib/ain-dftx/tests/data/tokenmint.txt create mode 100644 lib/ain-dftx/tests/data/tokenupdate.txt create mode 100644 lib/ain-dftx/tests/data/tokenupdateany.txt create mode 100644 lib/ain-dftx/tests/data/transferdomain.txt create mode 100644 lib/ain-dftx/tests/data/updateloantoken.txt create mode 100644 lib/ain-dftx/tests/data/updatemasternode.txt create mode 100644 lib/ain-dftx/tests/data/updateoracle.txt create mode 100644 lib/ain-dftx/tests/data/updatevault.txt create mode 100644 lib/ain-dftx/tests/data/utxostoaccount.txt create mode 100644 lib/ain-dftx/tests/data/vote.txt create mode 100644 lib/ain-dftx/tests/data/withdrawfromvault.txt create mode 100644 lib/ain-dftx/tests/evmtx.rs create mode 100644 lib/ain-dftx/tests/governance.rs create mode 100644 lib/ain-dftx/tests/icxorderbook.rs create mode 100644 lib/ain-dftx/tests/loans.rs create mode 100644 lib/ain-dftx/tests/masternode.rs create mode 100644 lib/ain-dftx/tests/oracles.rs create mode 100644 lib/ain-dftx/tests/pool.rs create mode 100644 lib/ain-dftx/tests/token.rs create mode 100644 lib/ain-dftx/tests/vault.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index b0aebf0a99a..400f4e042b8 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -116,6 +116,17 @@ dependencies = [ "serde", ] +[[package]] +name = "ain-dftx" +version = "0.1.0" +dependencies = [ + "ain-macros", + "anyhow", + "bitcoin", + "bitflags 2.4.2", + "hex", +] + [[package]] name = "ain-evm" version = "0.1.0" @@ -228,6 +239,7 @@ version = "0.1.0" dependencies = [ "ain-cpp-imports", "ain-db", + "ain-dftx", "ain-macros", "anyhow", "axum 0.7.4", @@ -237,7 +249,6 @@ dependencies = [ "cached", "chrono", "defichain-rpc", - "dftx-rs", "futures", "hex", "hyper 0.14.28", @@ -876,9 +887,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.15.2" +version = "3.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b1be7772ee4501dba05acbe66bb1e8760f6a6c474a36035631638e4415f130" +checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" [[package]] name = "byte-slice-cast" @@ -1034,7 +1045,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.0", + "windows-targets 0.52.3", ] [[package]] @@ -1333,12 +1344,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.6" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c376d08ea6aa96aafe61237c7200d1241cb177b7d3a542d791f2d118e9cbb955" +checksum = "3a5d17510e4a1a87f323de70b7b1eaac1ee0e37866c6720b2d279452d0edf389" dependencies = [ - "darling_core 0.20.6", - "darling_macro 0.20.6", + "darling_core 0.20.7", + "darling_macro 0.20.7", ] [[package]] @@ -1357,9 +1368,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.6" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33043dcd19068b8192064c704b3f83eb464f91f1ff527b44a4e2b08d9cdb8855" +checksum = "a98eea36a7ff910fa751413d0895551143a8ea41d695d9798ec7d665df7f7f5e" dependencies = [ "fnv", "ident_case", @@ -1382,11 +1393,11 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.6" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be" +checksum = "d6a366a3f90c5d59a4b91169775f88e52e8f71a0e7804cc98a8db2932cf4ed57" dependencies = [ - "darling_core 0.20.6", + "darling_core 0.20.7", "quote", "syn 2.0.50", ] @@ -1452,28 +1463,6 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6e854126756c496b8c81dec88f9a706b15b875c5849d4097a3854476b9fdf94" -[[package]] -name = "dftx-macro" -version = "0.1.0" -source = "git+https://github.com/Jouzo/dftx-rs.git#869a8ceee86c8e98d3a6a3acc7a8abf8fb2f150c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.50", -] - -[[package]] -name = "dftx-rs" -version = "0.1.0" -source = "git+https://github.com/Jouzo/dftx-rs.git#869a8ceee86c8e98d3a6a3acc7a8abf8fb2f150c" -dependencies = [ - "anyhow", - "bitcoin", - "bitflags 2.4.2", - "dftx-macro", - "hex", -] - [[package]] name = "diff" version = "0.1.13" @@ -4899,7 +4888,7 @@ version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "865f9743393e638991566a8b7a479043c2c8da94a33e0a31f18214c9cae0a64d" dependencies = [ - "darling 0.20.6", + "darling 0.20.7", "proc-macro2", "quote", "syn 2.0.50", @@ -5610,9 +5599,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.13" +version = "0.12.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" [[package]] name = "tempdir" @@ -6618,7 +6607,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.3", ] [[package]] @@ -6645,7 +6634,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.3", ] [[package]] @@ -6680,17 +6669,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.3", + "windows_aarch64_msvc 0.52.3", + "windows_i686_gnu 0.52.3", + "windows_i686_msvc 0.52.3", + "windows_x86_64_gnu 0.52.3", + "windows_x86_64_gnullvm 0.52.3", + "windows_x86_64_msvc 0.52.3", ] [[package]] @@ -6707,9 +6696,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" [[package]] name = "windows_aarch64_msvc" @@ -6725,9 +6714,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" [[package]] name = "windows_i686_gnu" @@ -6743,9 +6732,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" [[package]] name = "windows_i686_msvc" @@ -6761,9 +6750,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" [[package]] name = "windows_x86_64_gnu" @@ -6779,9 +6768,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" [[package]] name = "windows_x86_64_gnullvm" @@ -6797,9 +6786,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" [[package]] name = "windows_x86_64_msvc" @@ -6815,9 +6804,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" [[package]] name = "winnow" diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 2da7c1c154d..51bc45f8ecf 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -119,7 +119,6 @@ sp-io = "24.0" substrate-bn = "0.6" #### Ocean dependencies -dftx-rs = { git = "https://github.com/Jouzo/dftx-rs.git" } bitcoin = "0.31" cached = { version = "0.48", features = ["async"] } defichain-rpc = { version = "0.18.0", git = "https://github.com/Jouzo/rust-defichain-rpc.git" } @@ -128,3 +127,4 @@ defichain-rpc = { version = "0.18.0", git = "https://github.com/Jouzo/rust-defic ain-cpp-imports = { path = "./ain-cpp-imports" } ain-db = { path = "./ain-db" } ain-macros = { path = "./ain-macros" } +ain-dftx = { path = "./ain-dftx" } diff --git a/lib/ain-dftx/Cargo.toml b/lib/ain-dftx/Cargo.toml new file mode 100644 index 00000000000..12b71e40140 --- /dev/null +++ b/lib/ain-dftx/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "ain-dftx" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ain-macros.workspace = true +anyhow.workspace = true +bitcoin.workspace = true +hex.workspace = true +bitflags = "2.4.1" + diff --git a/lib/ain-dftx/src/custom_tx.rs b/lib/ain-dftx/src/custom_tx.rs new file mode 100644 index 00000000000..2f4ade47fee --- /dev/null +++ b/lib/ain-dftx/src/custom_tx.rs @@ -0,0 +1,135 @@ +#[derive(Debug)] +#[repr(u8)] +pub enum CustomTxType { + None = 0, + Reject = 1, + ICXCreateOrder = b'1', + ICXMakeOffer = b'2', + ICXSubmitDFCHTLC = b'3', + ICXSubmitEXTHTLC = b'4', + ICXClaimDFCHTLC = b'5', + ICXCloseOrder = b'6', + ICXCloseOffer = b'7', + TransferDomain = b'8', + EvmTx = b'9', + AutoAuthPrep = b'A', + AccountToAccount = b'B', + CreateMasternode = b'C', + DestroyLoanScheme = b'D', + CreateVoc = b'E', + BurnToken = b'F', + SetGovVariable = b'G', + PaybackLoan = b'H', + AuctionBid = b'I', + WithdrawFromVault = b'J', + SmartContract = b'K', + LoanScheme = b'L', + MintToken = b'M', + UpdateToken = b'N', + Vote = b'O', + TokenSplit = b'P', + FutureSwap = b'Q', + ResignMasternode = b'R', + DepositToVault = b'S', + CreateToken = b'T', + UtxosToAccount = b'U', + CreateVault = b'V', + PaybackWithCollateral = b'W', + TakeLoan = b'X', + ProposalFeeRedistribution = b'Y', + UnsetGovVariable = b'Z', + AnyAccountsToAccounts = b'a', + AccountToUtxos = b'b', + SetLoanCollateralToken = b'c', + DefaultLoanScheme = b'd', + CloseVault = b'e', + SetLoanToken = b'g', + RemoveOracle = b'h', + PoolSwapV2 = b'i', + SetGovVariableHeight = b'j', + PaybackLoanV2 = b'k', + PoolAddLiquidity = b'l', + UpdateMasternode = b'm', + UpdateTokenAny = b'n', + AppointOracle = b'o', + CreatePoolPair = b'p', + FutureSwapExecution = b'q', + RemovePoolLiquidity = b'r', + PoolSwap = b's', + UpdateOracleAppoint = b't', + UpdatePoolPair = b'u', + UpdateVault = b'v', + FutureSwapRefund = b'w', + UpdateLoanToken = b'x', + SetOracleData = b'y', + CreateCfp = b'z', +} + +impl From for CustomTxType { + fn from(value: u8) -> Self { + match value { + 1 => CustomTxType::Reject, + b'1' => CustomTxType::ICXCreateOrder, + b'2' => CustomTxType::ICXMakeOffer, + b'3' => CustomTxType::ICXSubmitDFCHTLC, + b'4' => CustomTxType::ICXSubmitEXTHTLC, + b'5' => CustomTxType::ICXClaimDFCHTLC, + b'6' => CustomTxType::ICXCloseOrder, + b'7' => CustomTxType::ICXCloseOffer, + b'8' => CustomTxType::TransferDomain, + b'9' => CustomTxType::EvmTx, + b'A' => CustomTxType::AutoAuthPrep, + b'B' => CustomTxType::AccountToAccount, + b'C' => CustomTxType::CreateMasternode, + b'D' => CustomTxType::DestroyLoanScheme, + b'E' => CustomTxType::CreateVoc, + b'F' => CustomTxType::BurnToken, + b'G' => CustomTxType::SetGovVariable, + b'H' => CustomTxType::PaybackLoan, + b'I' => CustomTxType::AuctionBid, + b'J' => CustomTxType::WithdrawFromVault, + b'K' => CustomTxType::SmartContract, + b'L' => CustomTxType::LoanScheme, + b'M' => CustomTxType::MintToken, + b'N' => CustomTxType::UpdateToken, + b'O' => CustomTxType::Vote, + b'P' => CustomTxType::TokenSplit, + b'Q' => CustomTxType::FutureSwap, + b'R' => CustomTxType::ResignMasternode, + b'S' => CustomTxType::DepositToVault, + b'T' => CustomTxType::CreateToken, + b'U' => CustomTxType::UtxosToAccount, + b'V' => CustomTxType::CreateVault, + b'W' => CustomTxType::PaybackWithCollateral, + b'X' => CustomTxType::TakeLoan, + b'Y' => CustomTxType::ProposalFeeRedistribution, + b'Z' => CustomTxType::UnsetGovVariable, + b'a' => CustomTxType::AnyAccountsToAccounts, + b'b' => CustomTxType::AccountToUtxos, + b'c' => CustomTxType::SetLoanCollateralToken, + b'd' => CustomTxType::DefaultLoanScheme, + b'e' => CustomTxType::CloseVault, + b'g' => CustomTxType::SetLoanToken, + b'h' => CustomTxType::RemoveOracle, + b'i' => CustomTxType::PoolSwapV2, + b'j' => CustomTxType::SetGovVariableHeight, + b'k' => CustomTxType::PaybackLoanV2, + b'l' => CustomTxType::PoolAddLiquidity, + b'm' => CustomTxType::UpdateMasternode, + b'n' => CustomTxType::UpdateTokenAny, + b'o' => CustomTxType::AppointOracle, + b'p' => CustomTxType::CreatePoolPair, + b'q' => CustomTxType::FutureSwapExecution, + b'r' => CustomTxType::RemovePoolLiquidity, + b's' => CustomTxType::PoolSwap, + b't' => CustomTxType::UpdateOracleAppoint, + b'u' => CustomTxType::UpdatePoolPair, + b'v' => CustomTxType::UpdateVault, + b'w' => CustomTxType::FutureSwapRefund, + b'x' => CustomTxType::UpdateLoanToken, + b'y' => CustomTxType::SetOracleData, + b'z' => CustomTxType::CreateCfp, + _ => CustomTxType::None, + } + } +} diff --git a/lib/ain-dftx/src/lib.rs b/lib/ain-dftx/src/lib.rs new file mode 100644 index 00000000000..652674c5af3 --- /dev/null +++ b/lib/ain-dftx/src/lib.rs @@ -0,0 +1,41 @@ +pub mod custom_tx; +pub mod types; + +use anyhow::format_err; +pub use bitcoin::{ + consensus::{deserialize, serialize}, + Block, Transaction, TxIn, TxOut, +}; + +pub use crate::types::*; + +const OP_PUSHDATA1: u8 = 0x4c; +const OP_PUSHDATA2: u8 = 0x4d; +const OP_PUSHDATA4: u8 = 0x4e; +const OP_RETURN: u8 = 0x6a; +pub const COIN: i64 = 100_000_000; + +fn get_dftx_data(data: &[u8]) -> std::result::Result<&[u8], anyhow::Error> { + if data[0] != OP_RETURN { + return Err(format_err!("Should start with op return")); + } + validate_buffer_len(data[1], data[2..].len())?; + + Ok(&data[2..]) +} + +fn validate_buffer_len(v: u8, len: usize) -> std::result::Result<(), anyhow::Error> { + let marker = match len { + 0..=75 => len as u8, + 76..=255 => OP_PUSHDATA1, + 256..=65535 => OP_PUSHDATA2, + 65536..=16777215 => OP_PUSHDATA4, + _ => return Err(format_err!("OP_PUSHDATA buffer is larger than 16777215")), + }; + + if v != marker { + return Err(format_err!("OP_PUSHDATA is not between 0x01 or 0x4e")); + }; + + Ok(()) +} diff --git a/lib/ain-dftx/src/types/account.rs b/lib/ain-dftx/src/types/account.rs new file mode 100644 index 00000000000..e3c2086c49a --- /dev/null +++ b/lib/ain-dftx/src/types/account.rs @@ -0,0 +1,58 @@ +use ain_macros::ConsensusEncoding; +use bitcoin::{impl_consensus_encoding, io, ScriptBuf, VarInt}; + +use super::{ + balance::{ScriptBalances, TokenBalanceUInt32, TokenBalanceVarInt}, + common::CompactVec, +}; + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct UtxosToAccount { + pub to: CompactVec, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct AccountToUtxos { + pub from: ScriptBuf, + pub balances: CompactVec, + pub minting_outputs_start: VarInt, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct AccountToAccount { + pub from: ScriptBuf, + pub to: CompactVec, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct AnyAccountsToAccounts { + pub from: CompactVec, + pub to: CompactVec, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct TransferDomainItem { + pub address: ScriptBuf, + pub amount: TokenBalanceVarInt, + pub domain: u8, + pub data: Vec, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct TransferDomainPair { + pub src: TransferDomainItem, + pub dst: TransferDomainItem, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct TransferDomain { + pub items: CompactVec, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct SetFutureSwap { + pub owner: ScriptBuf, + pub source: TokenBalanceVarInt, + pub destination: u32, + pub withdraw: bool, +} diff --git a/lib/ain-dftx/src/types/balance.rs b/lib/ain-dftx/src/types/balance.rs new file mode 100644 index 00000000000..929558fe22d --- /dev/null +++ b/lib/ain-dftx/src/types/balance.rs @@ -0,0 +1,24 @@ +use ain_macros::ConsensusEncoding; +use bitcoin::{impl_consensus_encoding, io, ScriptBuf, VarInt}; + +use super::common::CompactVec; + +// CBalances +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct TokenBalanceUInt32 { + pub token: u32, + pub amount: i64, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct ScriptBalances { + pub script: ScriptBuf, + pub balances: CompactVec, +} + +// CTokenAmount +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct TokenBalanceVarInt { + pub token: VarInt, + pub amount: i64, +} diff --git a/lib/ain-dftx/src/types/common.rs b/lib/ain-dftx/src/types/common.rs new file mode 100644 index 00000000000..a6360a2a18c --- /dev/null +++ b/lib/ain-dftx/src/types/common.rs @@ -0,0 +1,171 @@ +use bitcoin::{ + consensus::{Decodable, Encodable}, + io::{self, ErrorKind}, +}; + +#[derive(Debug, PartialEq, Eq)] +pub struct CompactVec(Vec); + +impl Encodable for CompactVec { + fn consensus_encode( + &self, + w: &mut W, + ) -> Result { + let mut len = VarInt(self.0.len() as u64).consensus_encode(w)?; + for item in self.0.iter() { + len += item.consensus_encode(w)?; + } + Ok(len) + } +} + +impl Decodable for CompactVec { + fn consensus_decode( + r: &mut R, + ) -> Result { + let len = VarInt::consensus_decode(r)?.0; + let mut ret = Vec::with_capacity(len as usize); + for _ in 0..len { + ret.push(Decodable::consensus_decode(r)?); + } + Ok(CompactVec(ret)) + } +} + +impl From> for CompactVec { + fn from(v: Vec) -> Self { + Self(v) + } +} + +impl AsRef> for CompactVec { + fn as_ref(&self) -> &Vec { + &self.0 + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct Maybe(pub Option); +impl Encodable for Maybe { + fn consensus_encode( + &self, + w: &mut W, + ) -> Result { + match &self.0 { + Some(v) => v.consensus_encode(w), + None => Ok(0), + } + } +} + +impl Decodable for Maybe { + fn consensus_decode( + r: &mut R, + ) -> Result { + match T::consensus_decode(r) { + Ok(v) => Ok(Self(Some(v))), + Err(bitcoin::consensus::encode::Error::Io(e)) + if e.kind() == ErrorKind::UnexpectedEof => + { + Ok(Self(None)) + } + Err(e) => Err(e), + } + } +} + +impl From> for Maybe { + fn from(v: Option) -> Self { + Self(v) + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct RawBytes(pub Vec); + +impl Encodable for RawBytes { + fn consensus_encode( + &self, + writer: &mut W, + ) -> Result { + writer.write(&self.0) + } +} + +impl Decodable for RawBytes { + fn consensus_decode( + reader: &mut R, + ) -> Result { + let mut buf = [0u8; 512]; + let v = reader.read(&mut buf)?; + Ok(Self(buf[..v].to_vec())) + } +} + +/// This `VarInt` struct is designed to encode/decode in-line with Bitcoin core VarInt implementation +/// +/// ## Motivation +/// In the rust-bitcoin library, variable-length integers are implemented as CompactSize. +/// See [issue #1016](https://github.com/rust-bitcoin/rust-bitcoin/issues/1016) + +#[derive(Debug, PartialEq, Eq)] +pub struct VarInt(pub u64); + +impl Encodable for VarInt { + fn consensus_encode(&self, writer: &mut W) -> Result { + let mut n = self.0; + let mut len = 0; + let mut tmp = Vec::new(); + + loop { + let byte = ((n & 0x7F) | if len > 0 { 0x80 } else { 0x00 }) as u8; + tmp.push(byte); + len += 1; + + if n <= 0x7F { + break; + } + n = (n >> 7) - 1; + } + + for byte in tmp.iter().rev() { + writer.write_all(&[*byte])?; + } + + Ok(len) + } +} + +impl Decodable for VarInt { + fn consensus_decode( + reader: &mut R, + ) -> Result { + let mut n = 0u64; + + loop { + let mut buf = [0u8; 1]; + reader.read_exact(&mut buf)?; + let ch_data = buf[0]; + if n > (u64::MAX >> 7) { + return Err(bitcoin::consensus::encode::Error::Io(io::Error::new( + io::ErrorKind::InvalidInput, + "VarInt: size too large", + ))); + } + n = (n << 7) | (ch_data & 0x7F) as u64; + if ch_data & 0x80 != 0 { + if n == u64::MAX { + return Err(bitcoin::consensus::encode::Error::Io(io::Error::new( + io::ErrorKind::InvalidInput, + "VarInt: size too large", + ))); + } + n += 1; + } else { + break; + } + } + + Ok(VarInt(n)) + } +} diff --git a/lib/ain-dftx/src/types/evmtx.rs b/lib/ain-dftx/src/types/evmtx.rs new file mode 100644 index 00000000000..5fd44812fbd --- /dev/null +++ b/lib/ain-dftx/src/types/evmtx.rs @@ -0,0 +1,7 @@ +use ain_macros::ConsensusEncoding; +use bitcoin::{impl_consensus_encoding, io}; + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct EvmTx { + pub raw: Vec, +} diff --git a/lib/ain-dftx/src/types/governance.rs b/lib/ain-dftx/src/types/governance.rs new file mode 100644 index 00000000000..6a0319e154b --- /dev/null +++ b/lib/ain-dftx/src/types/governance.rs @@ -0,0 +1,171 @@ +use ain_macros::ConsensusEncoding; +use bitcoin::{ + consensus::{Decodable, Encodable, ReadExt}, + impl_consensus_encoding, + io::{self}, + ScriptBuf, Txid, VarInt, +}; + +use super::common::CompactVec; +use crate::{common::RawBytes, types::common::Maybe}; + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct LiqPoolSplit { + pub token_id: u32, + pub value: i64, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct LpDailyReward { + pub key: String, + pub value: i64, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct LpSplits { + pub key: String, + pub value: CompactVec, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct LpUnmapped { + pub key: String, + pub value: RawBytes, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct LoanTokenSplit { + pub token_id: VarInt, + pub value: i64, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct LpLoanTokenSplits { + pub key: String, + pub value: CompactVec, +} + +#[derive(Debug, PartialEq, Eq)] +pub enum GovernanceVar { + LpDailyReward(LpDailyReward), + LpSplits(LpSplits), + LpLoanTokenSplits(LpLoanTokenSplits), + Unmapped(LpUnmapped), +} + +impl Encodable for GovernanceVar { + fn consensus_encode(&self, writer: &mut W) -> Result { + match self { + GovernanceVar::LpDailyReward(data) => data.consensus_encode(writer), + GovernanceVar::LpSplits(data) => data.consensus_encode(writer), + GovernanceVar::LpLoanTokenSplits(data) => data.consensus_encode(writer), + GovernanceVar::Unmapped(data) => data.consensus_encode(writer), + } + } +} + +impl Decodable for GovernanceVar { + fn consensus_decode( + reader: &mut R, + ) -> Result { + let key = String::consensus_decode(reader)?; + match key.as_str() { + "LP_DAILY_DFI_REWARD" => Ok(Self::LpDailyReward(LpDailyReward { + key, + value: i64::consensus_decode(reader)?, + })), + "LP_SPLITS" => Ok(Self::LpSplits(LpSplits { + key, + value: >::consensus_decode(reader)?, + })), + "LP_LOAN_TOKEN_SPLITS" => Ok(Self::LpLoanTokenSplits(LpLoanTokenSplits { + key, + value: >::consensus_decode(reader)?, + })), + _ => Ok(Self::Unmapped(LpUnmapped { + key, + value: RawBytes::consensus_decode(reader)?, + })), + } + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct SetGovernance { + pub governance_vars: Vec, +} + +impl Encodable for SetGovernance { + fn consensus_encode(&self, writer: &mut W) -> Result { + self.governance_vars.iter().try_fold(0, |acc, var| { + var.consensus_encode(writer).map(|len| acc + len) + }) + } +} + +impl Decodable for SetGovernance { + fn consensus_decode( + reader: &mut R, + ) -> Result { + let mut govs = Vec::new(); + while let Maybe(Some(var)) = >::consensus_decode(reader)? { + govs.push(var) + } + + Ok(Self { + governance_vars: govs, + }) + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct SetGovernanceHeight { + pub var: GovernanceVar, + pub activation_height: u32, +} + +impl Encodable for SetGovernanceHeight { + fn consensus_encode(&self, writer: &mut W) -> Result { + let mut len = self.var.consensus_encode(writer)?; + len += self.activation_height.consensus_encode(writer)?; + Ok(len) + } +} + +impl Decodable for SetGovernanceHeight { + fn consensus_decode( + reader: &mut R, + ) -> Result { + let mut var = GovernanceVar::consensus_decode(reader)?; + let activation_height = match var { + GovernanceVar::Unmapped(ref mut v) => { + let height_bytes = v.value.0.drain((v.value.0.len() - 4)..).collect::>(); + u32::consensus_decode(&mut height_bytes.as_slice()) + } + _ => reader.read_u32(), + }?; + Ok(Self { + var, + activation_height, + }) + } +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct CreateProposal { + pub r#type: u8, + pub address: ScriptBuf, + pub n_amount: i64, + pub n_cycles: u8, + pub title: String, + pub context: String, + pub contexthash: String, + pub options: u8, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct Vote { + pub proposal_id: Txid, + pub masternode_id: Txid, + pub vote_decision: u8, +} diff --git a/lib/ain-dftx/src/types/icxorderbook.rs b/lib/ain-dftx/src/types/icxorderbook.rs new file mode 100644 index 00000000000..c4f1a9272f8 --- /dev/null +++ b/lib/ain-dftx/src/types/icxorderbook.rs @@ -0,0 +1,60 @@ +use ain_macros::ConsensusEncoding; +use bitcoin::{impl_consensus_encoding, io, ScriptBuf, Txid}; + +use crate::common::{CompactVec, Maybe, VarInt}; + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct ICXCreateOrder { + pub order_type: u8, + pub token_id: VarInt, + pub owner_address: ScriptBuf, + pub receive_pubkey: Maybe>, + pub amount_from: i64, + pub amount_to_fill: i64, + pub order_price: i64, + pub expiry: u32, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct ICXMakeOffer { + pub order_tx: Txid, + pub amount: i64, + pub owner_address: ScriptBuf, + pub receive_pubkey: Maybe>, + pub expiry: u32, + pub taker_fee: u64, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct ICXSubmitDFCHTLC { + pub offer_tx: Txid, + pub amount: i64, + pub hash: Txid, + pub timeout: u32, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct ICXSubmitEXTHTLC { + pub offer_tx: Txid, + pub amount: i64, + pub hash: Txid, + pub htlc_script_address: String, + pub owner_pubkey: CompactVec, + pub timeout: u32, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct ICXClaimDFCHTLC { + pub dfc_htlc_tx: Txid, + pub seed: Vec, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct ICXCloseOrder { + pub order_tx: Txid, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct ICXCloseOffer { + pub offer_tx: Txid, +} diff --git a/lib/ain-dftx/src/types/loans.rs b/lib/ain-dftx/src/types/loans.rs new file mode 100644 index 00000000000..63941a7d391 --- /dev/null +++ b/lib/ain-dftx/src/types/loans.rs @@ -0,0 +1,77 @@ +use ain_macros::ConsensusEncoding; +use bitcoin::{impl_consensus_encoding, io, ScriptBuf, Txid, VarInt}; + +use super::{balance::TokenBalanceUInt32, common::CompactVec, price::CurrencyPair}; + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct SetLoanScheme { + pub ratio: u32, + pub rate: i64, + pub identifier: String, + pub update: i64, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct DestroyLoanScheme { + pub identifier: String, + pub height: i64, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct SetDefaultLoanScheme { + pub identifier: String, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct SetCollateralToken { + pub token: VarInt, + pub factor: i64, + pub currency_pair: CurrencyPair, + pub activate_after_block: u32, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct SetLoanToken { + pub symbol: String, + pub name: String, + pub currency_pair: CurrencyPair, + pub mintable: bool, + pub interest: i64, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct UpdateLoanToken { + pub symbol: String, + pub name: String, + pub currency_pair: CurrencyPair, + pub mintable: bool, + pub interest: i64, + pub token_tx: Txid, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct TakeLoan { + pub vault_id: Txid, + pub to: ScriptBuf, + pub token_amounts: CompactVec, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct PaybackLoan { + pub vault_id: Txid, + pub from: ScriptBuf, + pub token_amounts: CompactVec, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct TokenPayback { + pub d_token: VarInt, + pub amounts: CompactVec, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct PaybackLoanV2 { + pub vault_id: Txid, + pub from: ScriptBuf, + pub loans: CompactVec, +} diff --git a/lib/ain-dftx/src/types/masternode.rs b/lib/ain-dftx/src/types/masternode.rs new file mode 100644 index 00000000000..508ab4d3f0e --- /dev/null +++ b/lib/ain-dftx/src/types/masternode.rs @@ -0,0 +1,72 @@ +use ain_macros::ConsensusEncoding; +use bitcoin::{ + consensus::{Decodable, Encodable}, + hashes::Hash, + impl_consensus_encoding, io, PubkeyHash, Txid, VarInt, +}; + +use super::common::{CompactVec, Maybe}; + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct CreateMasternode { + pub operator_type: u8, + pub operator_pub_key_hash: PubkeyHash, + pub timelock: Maybe, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct ResignMasternode { + pub node_id: Txid, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct UpdateMasternodeAddress { + pub r#type: u8, + pub address_pub_key_hash: Option, +} + +impl Encodable for UpdateMasternodeAddress { + fn consensus_encode(&self, writer: &mut W) -> Result { + let mut len = self.r#type.consensus_encode(writer)?; + match self.address_pub_key_hash { + Some(key) => { + len += 20u8.consensus_encode(writer)?; + len += writer.write(&key.to_byte_array())?; + } + None => { + len += 0u8.consensus_encode(writer)?; + } + } + Ok(len) + } +} + +impl Decodable for UpdateMasternodeAddress { + fn consensus_decode( + reader: &mut R, + ) -> Result { + let r#type = u8::consensus_decode(reader)?; + let len = VarInt::consensus_decode(reader)?; + let address_pub_key_hash = if len.0 > 0 { + Some(PubkeyHash::consensus_decode(reader)?) + } else { + None + }; + Ok(UpdateMasternodeAddress { + r#type, + address_pub_key_hash, + }) + } +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct UpdateMasternodeData { + pub r#type: u8, + pub address: UpdateMasternodeAddress, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct UpdateMasternode { + pub node_id: Txid, + pub updates: CompactVec, +} diff --git a/lib/ain-dftx/src/types/mod.rs b/lib/ain-dftx/src/types/mod.rs new file mode 100644 index 00000000000..324c1f59a88 --- /dev/null +++ b/lib/ain-dftx/src/types/mod.rs @@ -0,0 +1,343 @@ +pub mod account; +pub mod balance; +pub mod common; +pub mod evmtx; +pub mod governance; +pub mod icxorderbook; +pub mod loans; +pub mod masternode; +pub mod oracles; +pub mod pool; +pub mod price; +pub mod token; +pub mod vault; + +pub use ain_macros::ConsensusEncoding; +use bitcoin::{ + consensus::{Decodable, Encodable}, + impl_consensus_encoding, io, +}; + +use self::{ + account::*, common::RawBytes, evmtx::*, governance::*, icxorderbook::*, loans::*, + masternode::*, oracles::*, pool::*, token::*, vault::*, +}; +use crate::custom_tx::CustomTxType; + +#[derive(Debug, PartialEq, Eq)] +pub enum DfTx { + AccountToAccount(AccountToAccount), + AccountToUtxos(AccountToUtxos), + AnyAccountsToAccounts(AnyAccountsToAccounts), + AppointOracle(AppointOracle), + CloseVault(CloseVault), + CompositeSwap(CompositeSwap), + CreateCfp(CreateProposal), + CreateMasternode(CreateMasternode), + CreateVault(CreateVault), + CreateVoc(CreateProposal), + DepositToVault(DepositToVault), + DestroyLoanScheme(DestroyLoanScheme), + EvmTx(EvmTx), + ICXClaimDFCHTLC(ICXClaimDFCHTLC), + ICXCloseOffer(ICXCloseOffer), + ICXCloseOrder(ICXCloseOrder), + ICXCreateOrder(ICXCreateOrder), + ICXMakeOffer(ICXMakeOffer), + ICXSubmitDFCHTLC(ICXSubmitDFCHTLC), + ICXSubmitEXTHTLC(ICXSubmitEXTHTLC), + PaybackLoan(PaybackLoan), + PaybackLoanV2(PaybackLoanV2), + PlaceAuctionBid(PlaceAuctionBid), + PoolAddLiquidity(PoolAddLiquidity), + PoolCreatePair(PoolCreatePair), + PoolRemoveLiquidity(PoolRemoveLiquidity), + PoolSwap(PoolSwap), + PoolUpdatePair(PoolUpdatePair), + RemoveOracle(RemoveOracle), + ResignMasternode(ResignMasternode), + SetCollateralToken(SetCollateralToken), + SetDefaultLoanScheme(SetDefaultLoanScheme), + SetFutureSwap(SetFutureSwap), + SetGovernance(SetGovernance), + SetGovernanceHeight(SetGovernanceHeight), + SetLoanScheme(SetLoanScheme), + SetLoanToken(SetLoanToken), + SetOracleData(SetOracleData), + TakeLoan(TakeLoan), + BurnToken(BurnToken), + CreateToken(CreateToken), + MintToken(MintToken), + UpdateToken(UpdateToken), + UpdateTokenAny(UpdateTokenAny), + TransferDomain(TransferDomain), + UpdateLoanToken(UpdateLoanToken), + UpdateMasternode(UpdateMasternode), + UpdateOracle(UpdateOracle), + UpdateVault(UpdateVault), + UtxosToAccount(UtxosToAccount), + Vote(Vote), + WithdrawFromVault(WithdrawFromVault), + Reject, + None, +} + +impl DfTx { + fn to_u8(&self) -> u8 { + match self { + DfTx::None => 0, + DfTx::Reject => 1, + DfTx::ICXCreateOrder(_) => b'1', + DfTx::ICXMakeOffer(_) => b'2', + DfTx::ICXSubmitDFCHTLC(_) => b'3', + DfTx::ICXSubmitEXTHTLC(_) => b'4', + DfTx::ICXClaimDFCHTLC(_) => b'5', + DfTx::ICXCloseOrder(_) => b'6', + DfTx::ICXCloseOffer(_) => b'7', + DfTx::TransferDomain(_) => b'8', + DfTx::EvmTx(_) => b'9', + DfTx::AccountToAccount(_) => b'B', + DfTx::CreateMasternode(_) => b'C', + DfTx::DestroyLoanScheme(_) => b'D', + DfTx::CreateVoc(_) => b'E', + DfTx::BurnToken(_) => b'F', + DfTx::SetGovernance(_) => b'G', + DfTx::SetGovernanceHeight(_) => b'j', + DfTx::PaybackLoan(_) => b'H', + DfTx::PlaceAuctionBid(_) => b'I', + DfTx::WithdrawFromVault(_) => b'J', + DfTx::SetLoanScheme(_) => b'L', + DfTx::MintToken(_) => b'M', + DfTx::UpdateToken(_) => b'N', + DfTx::Vote(_) => b'O', + DfTx::SetFutureSwap(_) => b'Q', + DfTx::ResignMasternode(_) => b'R', + DfTx::DepositToVault(_) => b'S', + DfTx::CreateToken(_) => b'T', + DfTx::UtxosToAccount(_) => b'U', + DfTx::CreateVault(_) => b'V', + DfTx::TakeLoan(_) => b'X', + DfTx::AnyAccountsToAccounts(_) => b'a', + DfTx::AccountToUtxos(_) => b'b', + DfTx::SetCollateralToken(_) => b'c', + DfTx::SetDefaultLoanScheme(_) => b'd', + DfTx::CloseVault(_) => b'e', + DfTx::SetLoanToken(_) => b'g', + DfTx::RemoveOracle(_) => b'h', + DfTx::CompositeSwap(_) => b'i', + DfTx::PaybackLoanV2(_) => b'k', + DfTx::PoolAddLiquidity(_) => b'l', + DfTx::UpdateMasternode(_) => b'm', + DfTx::UpdateTokenAny(_) => b'n', + DfTx::AppointOracle(_) => b'o', + DfTx::PoolCreatePair(_) => b'p', + DfTx::PoolRemoveLiquidity(_) => b'r', + DfTx::PoolSwap(_) => b's', + DfTx::UpdateOracle(_) => b't', + DfTx::PoolUpdatePair(_) => b'u', + DfTx::UpdateVault(_) => b'v', + DfTx::UpdateLoanToken(_) => b'x', + DfTx::SetOracleData(_) => b'y', + DfTx::CreateCfp(_) => b'z', + } + } +} + +const DFTX_MARKER: [u8; 4] = *b"DfTx"; + +impl Decodable for DfTx { + fn consensus_decode( + r: &mut R, + ) -> Result { + let signature = <[u8; 4]>::consensus_decode(r)?; + if signature != DFTX_MARKER { + return Err(bitcoin::consensus::encode::Error::ParseFailed( + "Invalid marker", + )); + } + + let r#type = u8::consensus_decode(r)?; + let message = match CustomTxType::from(r#type) { + CustomTxType::AccountToAccount => { + DfTx::AccountToAccount(AccountToAccount::consensus_decode(r)?) + } + CustomTxType::AccountToUtxos => { + DfTx::AccountToUtxos(AccountToUtxos::consensus_decode(r)?) + } + CustomTxType::PoolAddLiquidity => { + DfTx::PoolAddLiquidity(PoolAddLiquidity::consensus_decode(r)?) + } + CustomTxType::AnyAccountsToAccounts => { + DfTx::AnyAccountsToAccounts(AnyAccountsToAccounts::consensus_decode(r)?) + } + CustomTxType::AppointOracle => DfTx::AppointOracle(AppointOracle::consensus_decode(r)?), + CustomTxType::AuctionBid => { + DfTx::PlaceAuctionBid(PlaceAuctionBid::consensus_decode(r)?) + } + CustomTxType::BurnToken => DfTx::BurnToken(BurnToken::consensus_decode(r)?), + CustomTxType::CloseVault => DfTx::CloseVault(CloseVault::consensus_decode(r)?), + CustomTxType::CreateCfp => DfTx::CreateCfp(CreateProposal::consensus_decode(r)?), + CustomTxType::CreateMasternode => { + DfTx::CreateMasternode(CreateMasternode::consensus_decode(r)?) + } + CustomTxType::CreatePoolPair => { + DfTx::PoolCreatePair(PoolCreatePair::consensus_decode(r)?) + } + CustomTxType::CreateToken => DfTx::CreateToken(CreateToken::consensus_decode(r)?), + CustomTxType::CreateVoc => DfTx::CreateVoc(CreateProposal::consensus_decode(r)?), + CustomTxType::DefaultLoanScheme => { + DfTx::SetDefaultLoanScheme(SetDefaultLoanScheme::consensus_decode(r)?) + } + CustomTxType::DepositToVault => { + DfTx::DepositToVault(DepositToVault::consensus_decode(r)?) + } + CustomTxType::DestroyLoanScheme => { + DfTx::DestroyLoanScheme(DestroyLoanScheme::consensus_decode(r)?) + } + CustomTxType::EvmTx => DfTx::EvmTx(EvmTx::consensus_decode(r)?), + CustomTxType::ICXClaimDFCHTLC => { + DfTx::ICXClaimDFCHTLC(ICXClaimDFCHTLC::consensus_decode(r)?) + } + CustomTxType::ICXCloseOffer => DfTx::ICXCloseOffer(ICXCloseOffer::consensus_decode(r)?), + CustomTxType::ICXCloseOrder => DfTx::ICXCloseOrder(ICXCloseOrder::consensus_decode(r)?), + CustomTxType::ICXCreateOrder => { + DfTx::ICXCreateOrder(ICXCreateOrder::consensus_decode(r)?) + } + CustomTxType::ICXMakeOffer => DfTx::ICXMakeOffer(ICXMakeOffer::consensus_decode(r)?), + CustomTxType::ICXSubmitDFCHTLC => { + DfTx::ICXSubmitDFCHTLC(ICXSubmitDFCHTLC::consensus_decode(r)?) + } + CustomTxType::ICXSubmitEXTHTLC => { + DfTx::ICXSubmitEXTHTLC(ICXSubmitEXTHTLC::consensus_decode(r)?) + } + CustomTxType::LoanScheme => DfTx::SetLoanScheme(SetLoanScheme::consensus_decode(r)?), + CustomTxType::MintToken => DfTx::MintToken(MintToken::consensus_decode(r)?), + CustomTxType::PaybackLoan => DfTx::PaybackLoan(PaybackLoan::consensus_decode(r)?), + CustomTxType::PaybackLoanV2 => DfTx::PaybackLoanV2(PaybackLoanV2::consensus_decode(r)?), + CustomTxType::PoolSwap => DfTx::PoolSwap(PoolSwap::consensus_decode(r)?), + CustomTxType::PoolSwapV2 => DfTx::CompositeSwap(CompositeSwap::consensus_decode(r)?), + CustomTxType::Reject => DfTx::AccountToUtxos(AccountToUtxos::consensus_decode(r)?), + CustomTxType::RemoveOracle => DfTx::RemoveOracle(RemoveOracle::consensus_decode(r)?), + CustomTxType::RemovePoolLiquidity => { + DfTx::PoolRemoveLiquidity(PoolRemoveLiquidity::consensus_decode(r)?) + } + CustomTxType::ResignMasternode => { + DfTx::ResignMasternode(ResignMasternode::consensus_decode(r)?) + } + CustomTxType::SetGovVariable => { + DfTx::SetGovernance(SetGovernance::consensus_decode(r)?) + } + CustomTxType::SetGovVariableHeight => { + DfTx::SetGovernanceHeight(SetGovernanceHeight::consensus_decode(r)?) + } + CustomTxType::SetLoanCollateralToken => { + DfTx::SetCollateralToken(SetCollateralToken::consensus_decode(r)?) + } + CustomTxType::SetLoanToken => DfTx::SetLoanToken(SetLoanToken::consensus_decode(r)?), + CustomTxType::SetOracleData => DfTx::SetOracleData(SetOracleData::consensus_decode(r)?), + CustomTxType::TakeLoan => DfTx::TakeLoan(TakeLoan::consensus_decode(r)?), + CustomTxType::TransferDomain => { + DfTx::TransferDomain(TransferDomain::consensus_decode(r)?) + } + CustomTxType::UpdateLoanToken => { + DfTx::UpdateLoanToken(UpdateLoanToken::consensus_decode(r)?) + } + CustomTxType::UpdateMasternode => { + DfTx::UpdateMasternode(UpdateMasternode::consensus_decode(r)?) + } + CustomTxType::UpdateOracleAppoint => { + DfTx::UpdateOracle(UpdateOracle::consensus_decode(r)?) + } + CustomTxType::UpdatePoolPair => { + DfTx::PoolUpdatePair(PoolUpdatePair::consensus_decode(r)?) + } + CustomTxType::UpdateToken => DfTx::UpdateToken(UpdateToken::consensus_decode(r)?), + CustomTxType::UpdateTokenAny => { + DfTx::UpdateTokenAny(UpdateTokenAny::consensus_decode(r)?) + } + CustomTxType::UpdateVault => DfTx::UpdateVault(UpdateVault::consensus_decode(r)?), + CustomTxType::UtxosToAccount => { + DfTx::UtxosToAccount(UtxosToAccount::consensus_decode(r)?) + } + CustomTxType::CreateVault => DfTx::CreateVault(CreateVault::consensus_decode(r)?), + CustomTxType::Vote => DfTx::Vote(Vote::consensus_decode(r)?), + CustomTxType::WithdrawFromVault => { + DfTx::WithdrawFromVault(WithdrawFromVault::consensus_decode(r)?) + } + _ => DfTx::None, + }; + + Ok(message) + } +} + +impl Encodable for DfTx { + fn consensus_encode(&self, w: &mut W) -> Result { + let mut len = DFTX_MARKER.consensus_encode(w)?; + + let r#type = self.to_u8(); + len += r#type.consensus_encode(w)?; + len += match self { + DfTx::AccountToAccount(data) => data.consensus_encode(w), + DfTx::AccountToUtxos(data) => data.consensus_encode(w), + DfTx::PoolAddLiquidity(data) => data.consensus_encode(w), + DfTx::AnyAccountsToAccounts(data) => data.consensus_encode(w), + DfTx::AppointOracle(data) => data.consensus_encode(w), + DfTx::PlaceAuctionBid(data) => data.consensus_encode(w), + DfTx::BurnToken(data) => data.consensus_encode(w), + DfTx::CloseVault(data) => data.consensus_encode(w), + DfTx::CreateMasternode(data) => data.consensus_encode(w), + DfTx::PoolCreatePair(data) => data.consensus_encode(w), + DfTx::CreateCfp(data) => data.consensus_encode(w), + DfTx::CreateToken(data) => data.consensus_encode(w), + DfTx::CreateVoc(data) => data.consensus_encode(w), + DfTx::SetDefaultLoanScheme(data) => data.consensus_encode(w), + DfTx::DepositToVault(data) => data.consensus_encode(w), + DfTx::DestroyLoanScheme(data) => data.consensus_encode(w), + DfTx::EvmTx(data) => data.consensus_encode(w), + DfTx::ICXClaimDFCHTLC(data) => data.consensus_encode(w), + DfTx::ICXCloseOffer(data) => data.consensus_encode(w), + DfTx::ICXCloseOrder(data) => data.consensus_encode(w), + DfTx::ICXCreateOrder(data) => data.consensus_encode(w), + DfTx::ICXMakeOffer(data) => data.consensus_encode(w), + DfTx::ICXSubmitDFCHTLC(data) => data.consensus_encode(w), + DfTx::ICXSubmitEXTHTLC(data) => data.consensus_encode(w), + DfTx::SetLoanScheme(data) => data.consensus_encode(w), + DfTx::MintToken(data) => data.consensus_encode(w), + DfTx::PaybackLoan(data) => data.consensus_encode(w), + DfTx::PaybackLoanV2(data) => data.consensus_encode(w), + DfTx::PoolSwap(data) => data.consensus_encode(w), + DfTx::CompositeSwap(data) => data.consensus_encode(w), + DfTx::RemoveOracle(data) => data.consensus_encode(w), + DfTx::PoolRemoveLiquidity(data) => data.consensus_encode(w), + DfTx::ResignMasternode(data) => data.consensus_encode(w), + DfTx::SetGovernance(data) => data.consensus_encode(w), + DfTx::SetGovernanceHeight(data) => data.consensus_encode(w), + DfTx::SetCollateralToken(data) => data.consensus_encode(w), + DfTx::SetLoanToken(data) => data.consensus_encode(w), + DfTx::SetOracleData(data) => data.consensus_encode(w), + DfTx::TakeLoan(data) => data.consensus_encode(w), + DfTx::TransferDomain(data) => data.consensus_encode(w), + DfTx::UpdateLoanToken(data) => data.consensus_encode(w), + DfTx::UpdateMasternode(data) => data.consensus_encode(w), + DfTx::UpdateOracle(data) => data.consensus_encode(w), + DfTx::PoolUpdatePair(data) => data.consensus_encode(w), + DfTx::UpdateToken(data) => data.consensus_encode(w), + DfTx::UpdateTokenAny(data) => data.consensus_encode(w), + DfTx::UpdateVault(data) => data.consensus_encode(w), + DfTx::UtxosToAccount(data) => data.consensus_encode(w), + DfTx::CreateVault(data) => data.consensus_encode(w), + DfTx::SetFutureSwap(data) => data.consensus_encode(w), + DfTx::Vote(data) => data.consensus_encode(w), + DfTx::WithdrawFromVault(data) => data.consensus_encode(w), + DfTx::Reject | DfTx::None => Ok(0), + }?; + Ok(len) + } +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct Stack { + pub dftx: DfTx, + rest: RawBytes, +} diff --git a/lib/ain-dftx/src/types/oracles.rs b/lib/ain-dftx/src/types/oracles.rs new file mode 100644 index 00000000000..8a4a7940437 --- /dev/null +++ b/lib/ain-dftx/src/types/oracles.rs @@ -0,0 +1,34 @@ +use ain_macros::ConsensusEncoding; +use bitcoin::{hash_types::Txid, impl_consensus_encoding, io, ScriptBuf}; + +use super::{ + common::CompactVec, + price::{CurrencyPair, TokenPrice}, +}; + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct SetOracleData { + pub oracle_id: Txid, + pub timestamp: i64, + pub token_prices: CompactVec, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct RemoveOracle { + pub oracle_id: Txid, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct AppointOracle { + pub script: ScriptBuf, + pub weightage: u8, + pub price_feeds: CompactVec, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct UpdateOracle { + pub oracle_id: Txid, + pub script: ScriptBuf, + pub weightage: u8, + pub price_feeds: CompactVec, +} diff --git a/lib/ain-dftx/src/types/pool.rs b/lib/ain-dftx/src/types/pool.rs new file mode 100644 index 00000000000..d637cad926d --- /dev/null +++ b/lib/ain-dftx/src/types/pool.rs @@ -0,0 +1,67 @@ +use ain_macros::ConsensusEncoding; +use bitcoin::{impl_consensus_encoding, io, ScriptBuf}; + +use super::{ + balance::{ScriptBalances, TokenBalanceUInt32, TokenBalanceVarInt}, + common::{CompactVec, Maybe}, +}; +use crate::common::VarInt; + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct MaxPrice { + integer: i64, + fraction: i64, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct PoolSwap { + pub from_script: ScriptBuf, + pub from_token_id: VarInt, + pub from_amount: i64, + pub to_script: ScriptBuf, + pub to_token_id: VarInt, + pub max_price: MaxPrice, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct PoolId { + pub id: VarInt, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct CompositeSwap { + pub pool_swap: PoolSwap, + pub pools: CompactVec, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct PoolAddLiquidity { + pub from: CompactVec, + pub share_address: ScriptBuf, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct PoolRemoveLiquidity { + pub script: ScriptBuf, + pub amount: TokenBalanceVarInt, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct PoolCreatePair { + pub token_a: VarInt, + pub token_b: VarInt, + pub commission: i64, + pub owner_address: ScriptBuf, + pub status: u8, + pub pair_symbol: String, + pub custom_rewards: Maybe>, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct PoolUpdatePair { + pub pool_id: u32, + pub status: u8, + pub commission: i64, + pub owner_address: ScriptBuf, + pub custom_rewards: Maybe>, +} diff --git a/lib/ain-dftx/src/types/price.rs b/lib/ain-dftx/src/types/price.rs new file mode 100644 index 00000000000..f7b716d4b52 --- /dev/null +++ b/lib/ain-dftx/src/types/price.rs @@ -0,0 +1,22 @@ +use ain_macros::ConsensusEncoding; +use bitcoin::{impl_consensus_encoding, io}; + +use super::common::CompactVec; + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct CurrencyPair { + pub token: String, + pub currency: String, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct TokenAmount { + pub currency: String, + pub amount: i64, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct TokenPrice { + pub token: String, + pub prices: CompactVec, +} diff --git a/lib/ain-dftx/src/types/token.rs b/lib/ain-dftx/src/types/token.rs new file mode 100644 index 00000000000..d81bac9a988 --- /dev/null +++ b/lib/ain-dftx/src/types/token.rs @@ -0,0 +1,85 @@ +use ain_macros::ConsensusEncoding; +use bitcoin::{ + consensus::{Decodable, Encodable, ReadExt}, + impl_consensus_encoding, io, ScriptBuf, Txid, +}; +use bitflags::bitflags; + +use super::{balance::TokenBalanceUInt32, common::CompactVec}; +use crate::common::Maybe; + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct MintToken { + pub balances: CompactVec, + pub to: Maybe, +} + +bitflags! { + #[derive(Debug, PartialEq, Eq)] + struct TokenFlags: u8 { + const NONE = 0; + const MINTABLE = 0x01; + const TRADEABLE = 0x02; + const DAT = 0x04; + const LPS = 0x08; // Liquidity Pool Share + const FINALIZED = 0x10; // locked forever + const LOANTOKEN = 0x20; // token created for loan + const DEFAULT = TokenFlags::MINTABLE.bits() | TokenFlags::TRADEABLE.bits(); + } +} + +impl Default for TokenFlags { + fn default() -> Self { + Self::DEFAULT + } +} + +impl Encodable for TokenFlags { + fn consensus_encode(&self, writer: &mut W) -> Result { + self.bits().consensus_encode(writer) + } +} + +impl Decodable for TokenFlags { + fn consensus_decode( + reader: &mut R, + ) -> Result { + let v = reader.read_u8()?; + Ok(Self::from_bits_retain(v)) + } +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct CreateToken { + pub symbol: String, + pub name: String, + pub decimal: u8, + pub limit: i64, + pub flags: u8, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct UpdateToken { + pub creation_tx: Txid, + pub is_dat: bool, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct UpdateTokenAny { + pub creation_tx: Txid, + pub token: CreateToken, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct VariantScript { + pub r#type: u32, + pub context: ScriptBuf, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct BurnToken { + pub amounts: CompactVec, + pub from: ScriptBuf, + pub burn_type: u8, + pub variant_context: VariantScript, +} diff --git a/lib/ain-dftx/src/types/vault.rs b/lib/ain-dftx/src/types/vault.rs new file mode 100644 index 00000000000..5cb04567ef0 --- /dev/null +++ b/lib/ain-dftx/src/types/vault.rs @@ -0,0 +1,45 @@ +use ain_macros::ConsensusEncoding; +use bitcoin::{impl_consensus_encoding, io, ScriptBuf, Txid}; + +use super::balance::TokenBalanceVarInt; + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct CreateVault { + pub owner_address: ScriptBuf, + pub scheme_id: String, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct UpdateVault { + pub vault_id: Txid, + pub owner_address: ScriptBuf, + pub scheme_id: String, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct DepositToVault { + pub vault_id: Txid, + pub from: ScriptBuf, + pub token_amount: TokenBalanceVarInt, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct WithdrawFromVault { + pub vault_id: Txid, + pub to: ScriptBuf, + pub token_amount: TokenBalanceVarInt, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct CloseVault { + pub vault_id: Txid, + pub to: ScriptBuf, +} + +#[derive(ConsensusEncoding, Debug, PartialEq, Eq)] +pub struct PlaceAuctionBid { + pub vault_id: Txid, + pub index: u32, + pub from: ScriptBuf, + pub token_amount: TokenBalanceVarInt, +} diff --git a/lib/ain-dftx/tests/account.rs b/lib/ain-dftx/tests/account.rs new file mode 100644 index 00000000000..cf458e04428 --- /dev/null +++ b/lib/ain-dftx/tests/account.rs @@ -0,0 +1,17 @@ +use ain_macros::test_dftx_serialization; + +#[test] +#[test_dftx_serialization] +fn test_utxos_to_account() {} + +#[test] +#[test_dftx_serialization] +fn test_account_to_utxos() {} + +#[test] +#[test_dftx_serialization] +fn test_account_to_account() {} + +#[test] +#[test_dftx_serialization] +fn test_transfer_domain() {} diff --git a/lib/ain-dftx/tests/block.rs b/lib/ain-dftx/tests/block.rs new file mode 100644 index 00000000000..db3ced0ddd5 --- /dev/null +++ b/lib/ain-dftx/tests/block.rs @@ -0,0 +1,30 @@ +use ain_dftx::{deserialize, Block, DfTx}; + +#[test] +fn test_block() { + let path = format!("./tests/data/block.txt"); + let s = std::fs::read_to_string(&path).unwrap(); + + for line in s.lines() { + let l = line.split(' ').next().unwrap(); + let hex = &hex::decode(l).unwrap(); + let block = deserialize::(&hex).unwrap(); + + for tx in block.txdata { + let bytes = tx.output[0].clone().script_pubkey.into_bytes(); + if bytes.len() > 2 && bytes[0] == 0x6a && bytes[1] <= 0x4e { + let offset = 1 + match bytes[1] { + 0x4c => 2, + 0x4d => 3, + 0x4e => 4, + _ => 1, + }; + + let raw_tx = &bytes[offset..]; + + let tx = deserialize::(raw_tx).unwrap(); + println!("tx : {:?}", tx); + } + } + } +} diff --git a/lib/ain-dftx/tests/data/accounttoaccount.txt b/lib/ain-dftx/tests/data/accounttoaccount.txt new file mode 100644 index 00000000000..88d2aa3f3b4 --- /dev/null +++ b/lib/ain-dftx/tests/data/accounttoaccount.txt @@ -0,0 +1,5 @@ +6a4544665478421976a914078084bb24a623d99521a2d6a53de6c558811de888ac0117a9146db59cbbcb1c7eeb0550c21669966c18c47028ba8701000000003da5a50300000000 +6a43446654784217a914b76160c26b3e25fffe1a0fcf0107ace1cc586db0870117a914990b4f2d928f6dfb98c812b485c54dc73434ac248701070000007203000000000000 +6a4544665478421976a9147d9ec663ae7c31a7f26990529d63fda2b565c38e88ac0117a9140ae6eab32e282e09dd929519ad674d96cbb202e687010000000095382a2e00000000 +6a43446654784217a9146a75e3dbdee2de17134e891b3a408050fa44eac1870117a91463277879e3992a30a94671b4f61d1ca634d95442870103000000bd7c0d0000000000 +6a43446654784217a914b76160c26b3e25fffe1a0fcf0107ace1cc586db0870117a914990b4f2d928f6dfb98c812b485c54dc73434ac248701070000009319000000000000 diff --git a/lib/ain-dftx/tests/data/accounttoutxos.txt b/lib/ain-dftx/tests/data/accounttoutxos.txt new file mode 100644 index 00000000000..ffada8b0d60 --- /dev/null +++ b/lib/ain-dftx/tests/data/accounttoutxos.txt @@ -0,0 +1,3 @@ +6a2b446654786217a914d6e3de1c51f22e580944bb6a1647f1d22f0159c78701000000007030e6550200000002 +6a2b446654786217a914fad0d4ab78412ec38e7a0b118e51e147e947e02d870100000000f2664e750200000002 +6a2b446654786217a91462f401bfbe944884f07b489eb97fd3b001d5303287010000000000a81dd50f00000002 diff --git a/lib/ain-dftx/tests/data/anyaccountoaccount.txt b/lib/ain-dftx/tests/data/anyaccountoaccount.txt new file mode 100644 index 00000000000..894fb30517c --- /dev/null +++ b/lib/ain-dftx/tests/data/anyaccountoaccount.txt @@ -0,0 +1,4 @@ +6a4c9d44665478610317a91457188c8b982570fe69ed6b99ce0489a9ea482023870100000000f28302000000000017a914d6e3de1c51f22e580944bb6a1647f1d22f0159c787010000000038a9d855020000001976a914016d3983837e91768af05e7fbbd956995c0ea37088ac010000000046030b00000000000117a914d6e3de1c51f22e580944bb6a1647f1d22f0159c78701000000007030e65502000000 +6a4c5144665478610117a914fad0d4ab78412ec38e7a0b118e51e147e947e02d870100000000f6ba3e75020000000117a914fad0d4ab78412ec38e7a0b118e51e147e947e02d870100000000f6ba3e7502000000 +6a4c5144665478610117a914f9038d01ce94d1b063d38fb580b1c85f927094a8870100000000b6d3ce1d000000000117a914fb61bf557ad5548558c054255026c858c8fefc83870100000000b6d3ce1d00000000 +6a4c5144665478610117a9147983732a70b6bdc52f3a3cc1bd1a35017f69ecb887010300000000ca9a3b000000000117a914fb3cc0b39e5634578c914f132a1eba0ac9992feb87010300000000ca9a3b00000000 diff --git a/lib/ain-dftx/tests/data/appointoracle.txt b/lib/ain-dftx/tests/data/appointoracle.txt new file mode 100644 index 00000000000..0f606377a02 --- /dev/null +++ b/lib/ain-dftx/tests/data/appointoracle.txt @@ -0,0 +1 @@ +6a35446654786f1976a914c52fcb3c6dd28e530e5d162fee41f235bf7709cd88ac0102055445534c4103455552055445534c4103555344 diff --git a/lib/ain-dftx/tests/data/autoauthprep.txt b/lib/ain-dftx/tests/data/autoauthprep.txt new file mode 100644 index 00000000000..a4441a9936d --- /dev/null +++ b/lib/ain-dftx/tests/data/autoauthprep.txt @@ -0,0 +1 @@ +6a054466547841 diff --git a/lib/ain-dftx/tests/data/block.txt b/lib/ain-dftx/tests/data/block.txt new file mode 100644 index 00000000000..af10f10ee56 --- /dev/null +++ b/lib/ain-dftx/tests/data/block.txt @@ -0,0 +1,4 @@ +00000020198d8f7943220625073b4d37242aa877b788db9364c46b74cc81261800000d6f511934d2c432e286acac11b6a2e80705723e650a1f31f384e4f3d5325178fe85efdd6d6579e3221891c74832c03e178d49a62618ef00c4e481a53a5d6022608ac2aacbded52b2165a6a33500000000000e0100000000000041203c65cf658d78b43e730088b0ee461ccead2047d204dd58e899ccf9f26693437963805faa2e16eb53c5928bb8a5b694683b4c17707d8f2d1c0f6d23f367092f7301040000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0503a6a33500ffffffff03507838d3000000001976a9144a09879788e96fd530b2467a9b25b64dfcfa924788ac000000000000000000856a4c8200000000000000004030326163646535323232646266666330623538353766663634333032633537333434343562336337333231323766386134613166323762666263363237663336000000000000000000000000000000002835646661376534376466643163373638333430333038366633643230306131356366656666383837000000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf9000120000000000000000000000000000000000000000000000000000000000000000000000000 // Single TX, block 3515302 +00000020bd4d7d7001e5377683562e28e37c905ced38da4fca99a1daac8f98714cc8502ea38702f36621c960b9238a016247f96ed29b6224a3ea56342c7c161e608612ae87f06565cc0c1918a79a2128c145be009dd349b2a0efb5dbb845970b9101d15a7027fc3d6dfc8a1b4e61350000000000b400000000000000411fe53acf9ab28de8c342216931086d6418ce3e4866d368acf2777cb7842e23a27c0b819927f78177ab3809a6f1c442a23e5254ce23063fef6c2dc9fbebd155bc441a040000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff05034e613500ffffffff038026c8d6000000001976a914301f6ef78fbafd3b07fba66c30428529bc7e0ec188ac000000000000000000856a4c820000000000000000403863333836663330356264643831333663393938303338373861303366323432306466313239623136353833613639373831616366313566353639626564313248231300000000005b130300000000002864326664373333386139316533646636346263626665326561313263326639353934323733643232000000000000000000266a24aa21a9ed916d254d3b56d2d5e31c3002e3585c1883cd5078f21f2a26eb509e58a2ba61800001200000000000000000000000000000000000000000000000000000000000000000000000000400000000010153721b2f089fbd43a6ec173691370e752283ad464025e9cd8f73ace075db31110100000000ffffffff020000000000000000976a4c944466547879de4f982782d9b6e49908576a0f85f9b70cb31eb3e2342801a66fc0c2ac687c063bf065650000000006035841550103555344bd414b032f000000035841470103555344d41209930000000003455552010355534484a78806000000000353474401035553448907770400000000035843550103555344b58f8816000000000342434f0103555344cc1fb2de01000000002c6c521100000000160014d2d67c71521d7a87a08dba607d6a7eced0f5ca7b000247304402202c6f217ed461abe75c8e9090f34271bff9365f77c173634591fde5e443f10f9702206a27f658ef39cfe52821d4dce2833d1cb683e57454cafb83668d2671f1d8534d01210238b96d8fffb8f353204e44841fd47e11331c9d8468ecf55b47f38464fe5f59fd0000000004000000020000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff010000000000000000fdc3016a4dbf014466547839fdb70102f901b382046a258459682f008505017ff700830565bb943e8c92491fc73390166ba00725b8f5bd734b8fba80b9014438ed17390000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000df27a2cdf44800000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000d4518384a9b5f93a7a5eec1d28dda3c981a33049000000000000000000000000000000000000000000000000000000006565f5050000000000000000000000000000000000000000000000000000000000000004000000000000000000000000ff00000000000000000000000000000000000003000000000000000000000000870c765f8af9b189c324be88b99884e5bae4514b00000000000000000000000049febbf9626b2d39aba11c01d83ef59b3d56d2a4000000000000000000000000ff0000000000000000000000000000000000000dc0809f8e22afaf89dc7ef80e8d7e70c68eba8d8dcf00fa24a1f16acedff3f9bcac0ea0411ba1b579f38399b758ffff148044d0c5d29e609e4d725a2fd3bb2160ddf13400000000000400000000010113de87062d02912f8f028e13bf6c7495f62dbdb8437f0677614e09ddeddfd1ad0000000017160014de440d4715fcf49fbb07f912252b0de926a79420feffffff020000000000000000076a054466547841004218f35c2c0000001976a914c09a7f5bd86950e6cd2e82f8c933579ae6643dcd88ac000247304402200a74c404602b17da4bf369aa50a2a4c64bd5e3f98a151918c5068bc1fafab7d1022021513b4bf85ba277082948d17ddf6157af48b8c7dd400f7a015f6b68e6536618012103dbd271b2fd596c7b218d828ba9e85cc73923ce20c29a7087ac355157fa768730000000000400000001a841704b6f7c119622ca4eec41917aa08636534aea2f5aad3917b9f1e6178e59010000006a47304402206c63ef05a8cc728c338239ca9ebcf47430d2761aa36b79864213313b04bed7b2022059cc65ba6ef1cc74009d11ab67f568a5d9024a97b89c81821858ddd2044a463e012103aebf3b7446341d2b86c825ee8e81fb6c69f42a7796e2b7616e111f30ad91d0ceffffffff020000000000000000486a46446654784f9612bfb7a68f878f45782cfd2aca1adeb60704dd2b51d8a7a47588d72d6659aa0d0869b7839a8c2438268515c33d92f7c1a8ac34ad816c6d67fadced2b1c445101003017f35c2c0000001976a914c09a7f5bd86950e6cd2e82f8c933579ae6643dcd88ac000000000004000000020000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff010000000000000000fdef026a4deb024466547839fde30202f902df82046a8205f184773594008504a817c800830aae60946ac1189052a1ca29773a7c1f49d34b9458a6b5fa89069d17119dc5a80000b902647e5e1136000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000003e8c92491fc73390166ba00725b8f5bd734b8fba0000000000000000000000003e8c92491fc73390166ba00725b8f5bd734b8fba0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000300000000000000000000000049febbf9626b2d39aba11c01d83ef59b3d56d2a4000000000000000000000000ff00000000000000000000000000000000000003000000000000000000000000870c765f8af9b189c324be88b99884e5bae4514b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000870c765f8af9b189c324be88b99884e5bae4514b00000000000000000000000049febbf9626b2d39aba11c01d83ef59b3d56d2a4c080a0ef9362bfe63a3863cd4020ef2edcc31fe3392ed673182c3320269e1772369987a0226e538c01f821150656c3f6e8e5243c0ed6d12aba49442717f625202c09490b000000000004000000020000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff010000000000000000df6a4cdc4466547839d602f8d382046a508459682f008505017ff7008307a12094e99ca567fb57936ef91c472cbe80f35867fd732380b864769ee0580000000000000000000000ff51dbf5263c4de693c01eee054afc4b351c1d64ce0000000000000000000000ff76ab2422ae4ba9ea8e6791b2ce68fe6cc8edf8a800000000000000000000000036633d610302044fce7fd05638c6ca00e8908788c001a033f1afe7890397dbb15b9fe0730a7a23849c44ee0b86c1200de502212e08baf0a0414dd165b9d9bbf5073babd79669b50d3aeaed708cab41b3731b019c1d738d98000000000004000000020000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff010000000000000000df6a4cdc4466547839d602f8d382046a478459682f008505017ff7008307a12094e99ca567fb57936ef91c472cbe80f35867fd732380b864769ee058000000000000000000000000bf032f22f7f084a4aa9f5408bb29e91f7082385900000000000000000000000051dbf5263c4de693c01eee054afc4b351c1d64ce0000000000000000000000ff61777ee1e80936dfb229f8ef9999c91d1bc5d784c001a05d0dc6d77f95f3092ffddabe5f47498f43de8499dab8a560bdc9c4ede66a0ecba00ff3a6b0ef879804abc3468cbaf2607ff9a0a475fa60a8fec5054bd3bf319750000000000004000000020000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff010000000000000000df6a4cdc4466547839d602f8d382046a348459682f008505017ff7008307a12094e99ca567fb57936ef91c472cbe80f35867fd732380b864769ee058000000000000000000000000bf032f22f7f084a4aa9f5408bb29e91f7082385900000000000000000000000051dbf5263c4de693c01eee054afc4b351c1d64ce0000000000000000000000ff61777ee1e80936dfb229f8ef9999c91d1bc5d784c001a0b90b7f5dd11ba79756b4dd1b339c1e54f71711c0a7e32d1a1eb3c83914f6d0aea04c39ce0103ac50d9bf7238bd00db308109ac1189429b163680a3354c49631bc5000000000004000000020000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff010000000000000000df6a4cdc4466547839d602f8d382046a3e8459682f008505017ff7008307a12094e99ca567fb57936ef91c472cbe80f35867fd732380b864769ee058000000000000000000000000bf032f22f7f084a4aa9f5408bb29e91f7082385900000000000000000000000051dbf5263c4de693c01eee054afc4b351c1d64ce0000000000000000000000ff61777ee1e80936dfb229f8ef9999c91d1bc5d784c080a0d903887cb46e26e679dc0b3cbc59db1e8004c76b032c34d55b4c726651bc8e63a0439ca37d5cbc73f0feedf8771043940679195849b3977384512d65819b89d324000000000004000000020000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff010000000000000000df6a4cdc4466547839d602f8d382046a348459682f008505017ff7008307a12094e99ca567fb57936ef91c472cbe80f35867fd732380b864769ee058000000000000000000000000bf032f22f7f084a4aa9f5408bb29e91f7082385900000000000000000000000051dbf5263c4de693c01eee054afc4b351c1d64ce0000000000000000000000ff61777ee1e80936dfb229f8ef9999c91d1bc5d784c080a07ec6d08bedcf6eab80fba8cba1717e0948e6953af76f951e6c8db4696162512ba067a59b09cf607cb2ecdd292b33e89d94d03828b182e28f410856df45538b838a000000000004000000020000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff010000000000000000df6a4cdc4466547839d602f8d382046a5d8459682f008505017ff7008307a12094e99ca567fb57936ef91c472cbe80f35867fd732380b864769ee058000000000000000000000000bf032f22f7f084a4aa9f5408bb29e91f7082385900000000000000000000000051dbf5263c4de693c01eee054afc4b351c1d64ce0000000000000000000000ff61777ee1e80936dfb229f8ef9999c91d1bc5d784c001a0d7f37f7a6369267a9c8084640e39b1aacf071087b3b96abf15392f5ee03d36caa023934c20456b271bca5c5f2bc4c68391ab4578405131089930b46c0c4dd75b2a000000000004000000020000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff010000000000000000e16a4cde4466547839d802f8d582046a82011a8459682f008505017ff7008307a12094e99ca567fb57936ef91c472cbe80f35867fd732380b864769ee0580000000000000000000000ff51dbf5263c4de693c01eee054afc4b351c1d64ce0000000000000000000000ff76ab2422ae4ba9ea8e6791b2ce68fe6cc8edf8a800000000000000000000000036633d610302044fce7fd05638c6ca00e8908788c080a05fb93ba32b15eca0fe76efeaf56e9b5bbe9648ae7b3c6f9c4aa3bd4b59b508e1a06c096ea4c5629c3991fc1e6897f53819706e107f469674042a88f2ff9fb15fd2000000000004000000020000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff010000000000000000df6a4cdc4466547839d602f8d382046a3e8459682f008505017ff7008307a12094e99ca567fb57936ef91c472cbe80f35867fd732380b864769ee058000000000000000000000000bf032f22f7f084a4aa9f5408bb29e91f7082385900000000000000000000000051dbf5263c4de693c01eee054afc4b351c1d64ce0000000000000000000000ff61777ee1e80936dfb229f8ef9999c91d1bc5d784c080a0a34b9bfbc328ecf3358a5f7bc81e8394cb685d8b926ac17ddf687160e9138aafa070dffb0b969ae58271f208ec3d1714a5e4f080b888943dc94aa63246e7e92497000000000004000000020000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff010000000000000000df6a4cdc4466547839d602f8d382046a398459682f008505017ff7008307a12094e99ca567fb57936ef91c472cbe80f35867fd732380b864769ee058000000000000000000000000bf032f22f7f084a4aa9f5408bb29e91f7082385900000000000000000000000051dbf5263c4de693c01eee054afc4b351c1d64ce0000000000000000000000ff61777ee1e80936dfb229f8ef9999c91d1bc5d784c001a0e4c9d8f213c2ad0715957924df4be3fa5e46ba0bfc86617cde0759bdba8962a6a00a0b712dc848557e7f141dd54248cb819d1c911d439f16a78b6372f7b7356cf3000000000004000000020000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff010000000000000000df6a4cdc4466547839d602f8d382046a398459682f008505017ff7008307a12094e99ca567fb57936ef91c472cbe80f35867fd732380b864769ee058000000000000000000000000bf032f22f7f084a4aa9f5408bb29e91f7082385900000000000000000000000051dbf5263c4de693c01eee054afc4b351c1d64ce0000000000000000000000ff61777ee1e80936dfb229f8ef9999c91d1bc5d784c080a058a9dbf89b71cdcf0dd8bb772a6682d12cf48e117b1f7343a1d7ab35b89c48b5a04020d259464c07f6b4d1bf95100e75091082a36a7441575a27172aa7df3bf6bb000000000004000000020000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff010000000000000000df6a4cdc4466547839d602f8d382046a398459682f008505017ff7008307a12094e99ca567fb57936ef91c472cbe80f35867fd732380b864769ee058000000000000000000000000bf032f22f7f084a4aa9f5408bb29e91f7082385900000000000000000000000051dbf5263c4de693c01eee054afc4b351c1d64ce0000000000000000000000ff61777ee1e80936dfb229f8ef9999c91d1bc5d784c080a04bd47ac5fc3c83c3231db99991d9a02df2da27db535b7c11d6ac678d4d61486ca04ce19aa7cc65352fb2472b29ba31f24dd27ba9946a333a24138392b4f88c107a000000000004000000020000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff0100ffffffff010000000000000000df6a4cdc4466547839d602f8d382046a4e8459682f008505017ff7008307a12094e99ca567fb57936ef91c472cbe80f35867fd732380b864769ee0580000000000000000000000ff51dbf5263c4de693c01eee054afc4b351c1d64ce0000000000000000000000ff76ab2422ae4ba9ea8e6791b2ce68fe6cc8edf8a800000000000000000000000036633d610302044fce7fd05638c6ca00e8908788c080a0190aecd3cde62c86aa71de77b8d3210dcd1b69b5535739454ac6658a9707b042a0724d3524c7f2cdfd4015dcb62ec6fc0dc33fd0ee208462fe917608e8b8e6abb20000000000040000000001013b2e01254fab9f5f8967986e81b2943bacb897e99695e044f27cb05e1b8dc34b0100000000ffffffff0200000000000000004b6a4944665478487593d12e9e8c1bceb4fe670975f67cfe39d0da80d298483c7f61ac46128aba4d16001428513279352299cba7af79979974381dd7d524af010f0000002010b1050e01000000451aeb6a7400000016001428513279352299cba7af79979974381dd7d524af000247304402203516927916fdd949a77030332bee11ab8fc1d458701be68ca9660ec87b0972d50220217e86d63751937a6d654647f4a066bc4bea1126c5f08a0878f7a689582bfa01012102b5900b35b3bf9ad2216b41025625a07b8c6579f136472c2eb2e0b3d29e176c6f00000000040000000001012cb7490147dbd101b05f3f0843af7c740552ef014389f384df06c024c50831030100000000ffffffff020000000000000000516a4c4e446654786916001443d9ea3a4d97ad21b62fd0846f1d9159a3671e3c0000902f500900000016001443d9ea3a4d97ad21b62fd0846f1d9159a3671e3c0304000000000000007b14b4000000000000008ed9bc020000000016001443d9ea3a4d97ad21b62fd0846f1d9159a3671e3c000247304402207af019ea1e201a159eb5231a20fb92f76afb4bfd627d667a47cc1e6b7d31604302204c23d62ac39f1ea7c414ed68798a639f2d73f0c4c2d1739ba627cda915dad08401210216f40c84d671db75a80b2898ea452db26e75a8d191815e8327f4ee26559fd61e00000000040000000001019b4915f054d87052effcb8911183883fd0f0933d2c97b08439776e06f7e1e5a70100000000ffffffff020000000000000000fd2b016a4d270144665478792187cc54b78d730ee8cdf6d7a119472bdeea9d71df62d3eced281942073af9e74cf06565000000000e03564f4f0103555344c1576fb909000000044b52424e0103555344782059d6000000000441524b4b01035553448a7ae80e010000000441524b470103555344aee8e0a5000000000441524b460103555344333e1889000000000441524b510103555344dbffda37010000000441524b57010355534479eb1184010000000441524b5801035553447f8d675400000000035151510103555344785da60f09000000044351515101035553447c0ec9dc000000000345454d0103555344bc2db8ea0000000004534f58580103555344ccbb18fc0b00000004534f584c01035553447cffe78800000000044d434849010355534433dc12010100000000610625100000000016001470df854480fb84a326f1326c28584eaf8fac0779000247304402205a7a0f6613bf3c3b187ddf118e2d35092e8d3e3755e9c972d2a774231ada35590220623e36e9a39b1c2b201fbbc1bb16dede651c8c9cf3a00f2f9bf2b11fc76d05270121039fb09cf83a124eaedd1e55667bacbc3a2cd1c29c1bf63bec7885915aac4c85b200000000040000000001014ba83554ae968c7b0cc489fbad001ea99641b92d8efb0676fa68c8dd39aba3ef0100000000ffffffff020000000000000000fd2b016a4d27014466547879408dc6311edf621fd4779ba1692b6a0dfb23c239639e63055910906997634c9850f06565000000000e03564f4f01035553440c1881b509000000044d434849010355534481df1201010000000441524b4701035553443db7e2a50000000004534f584c01035553449a39d787000000000441524b570103555344da3d1584010000000443515151010355534447b9c4dc000000000345454d0103555344a742baea000000000441524b51010355534498dbd937010000000351515101035553443b1b960b090000000441524b4b01035553440a682e0e01000000044b52424e0103555344f63157d6000000000441524b580103555344486e66540000000004534f585801035553441888f8fb0b0000000441524b460103555344c9eb1689000000000059bf2f1000000000160014ef3b2518b55409773ab558078d83c83ae4a09636000247304402200ceabbafef8894cd7445eff9e7ecd56b8aecdb9f30ef3c7c8d6ea42c0df20a0b02203b652a8594432fa927ba86735ad503edb864f79a728f98349ad3aa04453d4f64012102f5b1d37b8bc41ca668790999b5c4b448a97c8033ff3de8e736b06b272d2d4e310000000004000000000101b3a7179b1b4489599b0dd354ca25bcd5df835a184a0e1f9d02c8e4ac162709c20100000017160014b457f25a6caac40d0f490e83ac1769e1c51384d9ffffffff020000000000000000546a4c5144665478610117a914e1184257a6ea610fa3be99b86f3dbcf5e37f15908701e3000000008bb578050000000117a91409ea2b512855e8f5e155b3e0c3a1c37c5f3eb15c8701e3000000008bb5780500000000b0e40f000000000017a914e1184257a6ea610fa3be99b86f3dbcf5e37f159087000247304402206abe198957e3ed72e97db45c5a08950c3a8c49a1f80c8ac44aee2373d444c23f02204cdf4d0b018691a7307ce310bf6cdba54442f3e95ffaec419517f718d1b82a1c0121031ac209c1850fe939ce6f39de6f47a1f2f3a3ef47679cd0812056993f49ffe21d00000000040000000113deac6e07e31068f64aaedab58ee52e0e6d7e486b566c39fab469aff0ab5987010000006a47304402205286506a96ca744151af039b144b2e5e622d180479de56dab714a28d57a8d39a02203a43f4c782085aa2f1b151a3bd2fbaca04fc2964e1632200158b1685965bdd6c0121027382d48c5a23164285760700df9d87aaacb4a833241239752df536d1ca09c196feffffff020000000000000000076a05446654784100f40e767b310000001976a914324d8db0b675519c2669bb6193522e11a25ee85188ac000000000004000000000101f417160a21987e222d0f036d608b743e5a5ee826822c153ac4a90908d2fcf8680100000000ffffffff020000000000000000276a25446654787216001416e4adca6efd38985530d7655f7aed9135cf9ec6664007a81b5000000000dd8198000000000016001416e4adca6efd38985530d7655f7aed9135cf9ec6000247304402205aff4c8e75df3dbeb9ddecc9ca8f22a00ed755d037e9eb599e42bb1813e611fd0220610e12c45542702af43509348a5599ac5ef850a63fda9b94ae774ae027aeb12001210390434dc90c74dc1f91860b75eb90c34c38c3081bef8438e8b74cd76a9acfa233000000000400000001ae338f1815fb4cb8666e8a7174ebed0a0d3d9adf9461435cf5265b149396c628010000006a47304402202a4411786708350b708d1be4c3a365d526e47b6f8c28f56ffb8dc3b6bc42e31f022021ae67d3a48b6846c1f46ac067950ac896c07be05e6408435c1b248522fc993f01210389d3a079f954bd3f554efc65b74122383d216368cf153e4b0325547f639033d3ffffffff020000000000000000486a46446654784f30decb3edfea3df9ef6ba1655a53cc56ee39f207ae33a4f944b0935bd625a175b612048f8de84c28a997a96b7c44c42871bd8bc554a02db8c20f2f474911e74d0100e20d767b310000001976a914324d8db0b675519c2669bb6193522e11a25ee85188ac0000000000 // Block 3498318 +00000020d7bd8bdd074423197ce96ae7bd679e8a4a7e44bb9a03aacea675327cb1c81e963a624acd8d5926868df20821060a73c65c83fa0b4485f7350e2ade49598eb532e5e84360e98d1919025fa1b33a861d644c97b3ed2ba6ae0a20449d9f584f91b26e3d0264d215744ad1880a00000000000100000000000000412057f584ca455594531e15f61b9677e6210abf927254a5e583f069700a13fd2d870d65c1d9d7855d950cec64113adf52c5f7a67497137bacf1e9b09ea8cf370b6109040000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0503d1880a00ffffffff034a7daa24030000001976a91405bd119a2c36376ce53e56679b8cdd7cb75818d188ac0080fd9c760000000017a914dd7730517e0e4969b4e43677ff5bee682e53420a87000000000000000000266a24aa21a9edad257d06209a5b7b9327ad1f7a3d593d2a7a3329246d11360337f36a9573c48d00012000000000000000000000000000000000000000000000000000000000000000000000000004000000000101dd0e781393f1cbcc586afc72f10593420af29a55c207767464ae13e35b16104f010000001716001414390b6d61850726350df63a4bd71cbd859a5ac2feffffff020000000000000000076a0544665478410023553f030000000017a914edd93bfb85095d2f125048c4ec176cd5579bef5d8700024730440220230a2eb49dcfcc51786ebc530f4a072df5305e3980796fa96f70eb640d1d5fa50220713017ee1db7d46f183380cca63df0ab4520a40f06ba2c4dfa35fabe189923800121030ab7f1a90d64149c9d50690415af1044dc68d1356709c3b0c8cbedf5eedada6e000000000400000001879b6bbe4ac3c789f2d7bd6718a6186b6f011b3f7d77d7d5bb9c1399245f0db2010000006a47304402203dfb0e58a3554dfe3a4cc7f1efd76d94b6173326229f7551ce5e6b6c3067bc1c0220569c899e1dc78a910cb3e574eaa22e9d93d08536776218220e6bf7927d973d0a01210219d872592a5b949bd82c37651e356427c26d66eec1ef24306ce9f234d4fd86dbffffffff020000000000000000566a4c53446654786c011976a9147742abf9be1e2a9e42d665faf9c982c65f41315988ac0200000000d7d51d00000000000200000081000000000000001976a9147742abf9be1e2a9e42d665faf9c982c65f41315988ac007cac0500000000001976a9147742abf9be1e2a9e42d665faf9c982c65f41315988ac000000000004000000000101531570843a345a3a70455c948038f6ce916f0799aa7d36ad14b5632deffe19120200000017160014df6530df81b7be4ceabf9a073506be44d94449b3feffffff0300ca9a3b000000001c6a1a44665478430176b6b03f87f14ca9a6908407c716cba7a9d2f7e70000204aa9d10100001976a914cf9bf8f044e54f025bd081eee8bf4b8c6a08f7d788ac007b9745e06e19000017a91419e2872e8a738e1ce403f35b9b790318064e792d87000247304402203c62b308889b6264fa07e7915343ec6f516060eda34606e275710fb2f2101dfc022065c0054dc14186cead79eb966b42360b7ca7c7c862163e4a3a3b75c554128dbd0121033fb8261c63cdaeb554deac1b11469013f2c2255ce8e70df9d67a7add89626f1e00000000040000000001013e8bee4f5612a7a2d5daa5650a8c1fbd0856dedf051ddd4000f68664cf693b3a01000000171600148b8dddf9ac9337082807a557b96c0cb87404a4aafeffffff029c1731010000000017a91400ea47788ef1b981dd6f8e26e396a0f64d12ad578700009be6a60400000017a9141ea50479fbcd2c5cf9f946139abd4c72f22854c18700024730440220447c78b027fd53a095220074ede5e692be5e1abe855767428da540525dc7d67d0220799eef22429ed4044b865630858ef5779d7d6fe372e4e31a256878e471f631cd012103c68ff5cac0eabad78c1c358192e2526f86bd273e0a6ab901a8b8a3723874a3e1ce880a00040000000001016d33ec2f3690c88610708746b9df8530e26d494fc175e30f6bb1d4901e51ffac020000001716001420e8fb3a79c7c26666d4147954489febb07455e7feffffff020ed2763a000000002d6a2b44665478550117a9145d998f35ec773b65e0e678d3a25785a237cc3f468701000000000ed2763a00000000008af847140000000017a9140ba02d939a69651169edb5883242f80b72bec941870002473044022000a905195bc8c5638aa2fa8e744c5b87c15e82e8c4004ed3b626dba9fe4af3cb0220719ee051cec0b6be15d69127644ba3f667f4445b530cea6f4c760c530af3e966012102650277a8882ff00960780de687b8a0ccf1a82c1eaf368141543c7aa08cd52e3b00000000040000000001012dc55aa6a41617d90612d365acc6235225f4a184149bb2edc81267029b9527020100000017160014445f0885f58324baf3ec5c9dd6212822e83840ddfeffffff02ec2b0200000000002d6a2b44665478550117a9141b4ecf964359d5ed2cafc744a3da536c70e1b11f870100000000ec2b020000000000004e0214000000000017a91477833f30e9a8ffdbb500a5ff70cd0732ae3252b087000247304402206999f60c327e8a1e941436520cc212bbf1befcc08f21f400c64d281a1ee8d2560220675dd99791d9b1cdeaf875fffe8b5c4e4a368c0c6535bb0edadea9e0464882ca012103b0e612c61fdb0ef7472fa1c253b796c6f307e125234d82661d31225c2e3098470000000004000000000101daeae304abe63cb2339ab2999f55a57274371fb75c04f63137778faa8eb3198e0100000017160014cbe6b4d9e63715c5bf3c8ec7f2b7eb9fc181c606ffffffff020000000000000000526a4c4f446654787317a914f3171902f64abcffbcf304920a9b12f160df14c68700691d1d4b0000000017a914f3171902f64abcffbcf304920a9b12f160df14c68702ffffffffffffff7fffffffffffffff7f00af4f1f000000000017a914f3171902f64abcffbcf304920a9b12f160df14c6870002473044022036f96b347477c6e34ebb2b45b9e0d0d9bdae8b940bf7728b54b1d1351a560da00220047dafd43592c9874240f5396081294629389cc1e0b13fdfb629e872b8c839360121021837b731663e6c347593546ba0928ba88c9ab031316bf141a47e9ddbcaff71180000000004000000000101e7f546574a92b9691b2927f92f3c2974c0d058b1fec7ba35d542bd781715a70d0100000017160014cafb67425eb126fb0dd6b1c49ae9ea2de33ae53effffffff020000000000000000526a4c4f446654786c0117a914edd93bfb85095d2f125048c4ec176cd5579bef5d870200000000a9f002000000000003000000575109000000000017a914edd93bfb85095d2f125048c4ec176cd5579bef5d870099cbb5020000000017a914edd93bfb85095d2f125048c4ec176cd5579bef5d87000247304402202e4f900f00759aa0379f607a8b95299a8c2460d8d4886af2f3b1c1f2ac7a5bb00220334df76d47233e84c399a2a10a9f4a2a0fee46cabde4b50d30b486017835dbfd012103f246682a59e016d879d59037fa4b37e91b056d5f21cff7d1aa007a292f2b55fc00000000 // Block 690385 +010000000000000000000000000000000000000000000000000000000000000000000000388ddb5b3f5d2bd8bb425fb51d47b7e155795ad2024e69dd93a89d37bbdb1556c9501e5effff7f20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6b0004ffff001d01044c6146696e616e6369616c2054696d65732032332f4d61722f3230323020546865204665646572616c20526573657276652068617320676f6e652077656c6c20706173742074686520706f696e74206f6620e28098514520696e66696e697479e28099ffffffff050000c16ff28623001976a914b36814fd26190b321aa985809293a41273cfe15e88ac0000c16ff28623001976a9148857c8c3ce618fe7ae5f8ee11ecc8ea421a1d82988ac0000c16ff28623001976a9148080dad765cbfd1c38f95e88592e24e43fb6428288ac0000c16ff28623001976a9146688df29563f6e8a6227d09322435237453229d988ac00e40b54020000001976a9149ab96d8f6df07466f5b497153ba69ea73b7a656188ac0000000001000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff0200e1f505000000001c6a1a4466547843018857c8c3ce618fe7ae5f8ee11ecc8ea421a1d82900ca9a3b000000001976a914b36814fd26190b321aa985809293a41273cfe15e88ac0000000001000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff0200e1f505000000001c6a1a4466547843016688df29563f6e8a6227d09322435237453229d900ca9a3b000000001976a9148080dad765cbfd1c38f95e88592e24e43fb6428288ac0000000001000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff0200e1f505000000001c6a1a4466547843018f765e54f7b309965b6eb6d455de6f04445fe79400ca9a3b000000001976a914c2700426e3b889b602df089a4d53aef05fe6316a88ac0000000001000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff0200e1f505000000001c6a1a446654784301de3fa64045e6ef4227e832a3886dfc4a121b38ab00ca9a3b000000001976a914b48ac7f6ba3b966c4c5c81a985cd51416cf52c4488ac0000000001000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff0200e1f505000000001c6a1a446654784301d3f2ca03f247b0e6b44d62821a8e11912c10d40500ca9a3b000000001976a9140ecd8fe751e20391dfb8a7f9664d5686db540d9d88ac0000000001000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff0200e1f505000000001c6a1a44665478430131fab767bf34cd1e9e856b5d2c5688358666607600ca9a3b000000001976a9149ab96d8f6df07466f5b497153ba69ea73b7a656188ac0000000001000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff0200e1f505000000001c6a1a446654784304da58e8b431e692d602cdc3c91f8df9a175fc970900ca9a3b0000000016001420d230f5ae43bc1a66f1c96f196f95b3be2a84660000000001000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff0200e1f505000000001c6a1a446654784304e0dc4bafbea4d48f538ae526d8143a7159a510ee00ca9a3b000000001600142679c28d803f75e91f41132f4397dd4b76d9049d00000000 diff --git a/lib/ain-dftx/tests/data/closevault.txt b/lib/ain-dftx/tests/data/closevault.txt new file mode 100644 index 00000000000..7ea617d8a0c --- /dev/null +++ b/lib/ain-dftx/tests/data/closevault.txt @@ -0,0 +1,3 @@ +6a3c44665478655490de6280bcd61c0f26342cb3254b41354c24f28e01ce4f003f21ca6d156a1816001463f29965a35135ecdf4ec0b3fe5627a7166e3f9e +6a3c44665478659f84e32b851a05368fd7643239f705c89ea930bb24b2138ded3ed782c5ed1b3c160014fe1b31f4db7943f76677fc315e99badcde116fa7 +6a3c44665478655d4d885ca767a2956253f18b56bedc119edfaf9b1f5464fd74c457639374fb8016001469e51a841bcf4f5440d215af87ea60574f162a7a diff --git a/lib/ain-dftx/tests/data/compositeswap.txt b/lib/ain-dftx/tests/data/compositeswap.txt new file mode 100644 index 00000000000..dcf2957293c --- /dev/null +++ b/lib/ain-dftx/tests/data/compositeswap.txt @@ -0,0 +1,4 @@ +6a4c51446654786917a9140806eb42b6d5bb69726909fb6da34a9152afdf048701c7b3240d0000000017a9140806eb42b6d5bb69726909fb6da34a9152afdf048700ffffffffffffff7fffffffffffffff7f0105 // single pool id can use simple poolswap instead +6a4c52446654786917a914c34ca9c54dc87e7e875b212ec6ba0704be3de587870000d6117e0300000017a914c34ca9c54dc87e7e875b212ec6ba0704be3de58787022fe28e7915000080ffcf430300000000020102 +6a4c53446654786917a914635794bb3db157b6dac4dcb7467710a10f03c6ac8700809698000000000017a914582328ee9beebc3fb5844964302cc0fdbb27e04c87022fe28e7915000080ffcf43030000000003020406 +6a4c5444665478691976a9140b7127e943eaa3f28536c3f046ddbdeb790f691e88ac0080889e2a0100000017a914b3a65aa3fd9c60860bebd231d71b5bc5749ff5be87022fe28e7915000080ffcf430300000000020204 // longer swap info data diff --git a/lib/ain-dftx/tests/data/createcfp.txt b/lib/ain-dftx/tests/data/createcfp.txt new file mode 100644 index 00000000000..efc77910ce3 --- /dev/null +++ b/lib/ain-dftx/tests/data/createcfp.txt @@ -0,0 +1 @@ +6a4c7b446654787a0117a9148b5401d88a3d4e54fc701663dd99a5ab792af0a48700e40b5402000000022354657374696e67206e657720636f6d6d756e6974792066756e642070726f706f73616c1f68747470733a2f2f6769746875622e636f6d2f4465466943682f64666970730e3c636f6e7465787420686173683e00 diff --git a/lib/ain-dftx/tests/data/createmasternode.txt b/lib/ain-dftx/tests/data/createmasternode.txt new file mode 100644 index 00000000000..02d375bd25c --- /dev/null +++ b/lib/ain-dftx/tests/data/createmasternode.txt @@ -0,0 +1,7 @@ +6a1a446654784301742b337e0f40d5f229a89d3a26d53ae1093b6cff +6a1a44665478430121978f97842d623b79acecd7201a60538c13e935 // undefined operator pkh use collateral pkh +6a1a44665478430147bfb0a67b85a1718381558434fbfe7c4866cf2e // p2pkh +6a1a4466547843040e12cde53c156560faa1d01d144d234a74b65395 // p2wpkh +6a1c4466547843040e12cde53c156560faa1d01d144d234a74b653950000 // default timelock 0000 if not specified +6a1c4466547843040e12cde53c156560faa1d01d144d234a74b653950401 // with timelock 5 years (260) +6a1c4466547843040e12cde53c156560faa1d01d144d234a74b653950802 // with timelock 10 years (520) diff --git a/lib/ain-dftx/tests/data/createvault.txt b/lib/ain-dftx/tests/data/createvault.txt new file mode 100644 index 00000000000..0def96f33a7 --- /dev/null +++ b/lib/ain-dftx/tests/data/createvault.txt @@ -0,0 +1,3 @@ +6a2444665478561600147f3b2ccdb32982c3fa5380112dffad8a6792bba807736368656d6531 +6a2444665478561600148eca904c1e4bab2c7212938cb89728741539355507736368656d6532 +6a1d44665478561600145c51469b068db1a7af14db363a74935eb34a628f00 diff --git a/lib/ain-dftx/tests/data/createvoc.txt b/lib/ain-dftx/tests/data/createvoc.txt new file mode 100644 index 00000000000..793e0a90e7a --- /dev/null +++ b/lib/ain-dftx/tests/data/createvoc.txt @@ -0,0 +1 @@ +6a4c5744665478450200000000000000000001166e657720766f7465206f6620636f6e666964656e63651f68747470733a2f2f6769746875622e636f6d2f4465466943682f64666970730e3c636f6e7465787420686173683e00 diff --git a/lib/ain-dftx/tests/data/deposittovault.txt b/lib/ain-dftx/tests/data/deposittovault.txt new file mode 100644 index 00000000000..21bbe0e326f --- /dev/null +++ b/lib/ain-dftx/tests/data/deposittovault.txt @@ -0,0 +1,3 @@ +6a454466547853aec2e44aa7a618b4b8d911c3e270616553debabf90199c8147d5038f55b059ed16001488d52b9b1dded932272e0c9bebb0dccdd46ecf99000010a5d4e8000000 +6a454466547853aec2e44aa7a618b4b8d911c3e270616553debabf90199c8147d5038f55b059ed16001488d52b9b1dded932272e0c9bebb0dccdd46ecf990100e1f50500000000 +6a454466547853afc2e44aa7a618b4b8d911c3e270616553debabf90199c8147d5038f55b059ed1600149d04d9764bdd97432f13411fe9753f808dc279260100e1f50500000000 diff --git a/lib/ain-dftx/tests/data/destroyloanscheme.txt b/lib/ain-dftx/tests/data/destroyloanscheme.txt new file mode 100644 index 00000000000..88bfcdeee91 --- /dev/null +++ b/lib/ain-dftx/tests/data/destroyloanscheme.txt @@ -0,0 +1,3 @@ +6a15446654784407736368656d65310000000000000000 +6a15446654784407736368656d65328c00000000000000 +6a15446654784407736368656d65339600000000000000 diff --git a/lib/ain-dftx/tests/data/evmtx.txt b/lib/ain-dftx/tests/data/evmtx.txt new file mode 100644 index 00000000000..f1b57fef76a --- /dev/null +++ b/lib/ain-dftx/tests/data/evmtx.txt @@ -0,0 +1,2 @@ +6a4c7444665478396ef86c808504e3b292008252089494c2acef73afe7409220af7aab48f0add9e4e7ee880de0b6b3a76400008026a0be7b6f57bf2c838a48fa6e666945994b3b6f386c92f1523667c8c50f753e63c0a018226da7216224a0217bbe186a456eb943ca8bcbef3d7421d544d6fcb9ab2479 +6a4c7444665478396ef86c018504e3b2920082520894585bd64cf6574abf77f216efc894940e87cad5b1880de0b6b3a76400008026a035e16fa88aa4a1d01990c3b6acb0e6d869fe4d5960992490814f65e063ba3ed7a0401a72637c21501313e1a5c8b03cd1031ea7823085c6a8f6d388caf078027d7b diff --git a/lib/ain-dftx/tests/data/futureswap.txt b/lib/ain-dftx/tests/data/futureswap.txt new file mode 100644 index 00000000000..0ab0064d2d2 --- /dev/null +++ b/lib/ain-dftx/tests/data/futureswap.txt @@ -0,0 +1,7 @@ +6a2a44665478511600148866af6e0455e34b5ef4ecb51b07dad4e51431790200e1f505000000000000000000 +6a2a4466547851160014dbe1bf723cbc2ce57945a601d658294d6b03aa2a0400e1f505000000000200000000 +6a2a4466547851160014bc9f5c20a7fee0e32e3f80282b92dda623fd6c1b0000ac4206010000000100000000 +6a2a4466547851160014bc9f5c20a7fee0e32e3f80282b92dda623fd6c1b0000b33f71000000000100000001 +6a2a44665478511600148866af6e0455e34b5ef4ecb51b07dad4e51431790200e1f505000000000000000001 +6a2a4466547851160014dbe1bf723cbc2ce57945a601d658294d6b03aa2a0400e1f505000000000200000001 +04000000000101d56bd67834fb6db66fe0dcfc1ccc167e8734cb1f9a67392f9adf5e3eda1b10f10100000017160014952581abb6fbc2e49e0ada10f1080e6759f33bffffffffff0200000000000000002d6a2b446654785117a9147eb6b3e8e91fa665ba8bfb1f609fff13a0ab44438718a086010000000000000000000000e22a3a0f0000000017a9147eb6b3e8e91fa665ba8bfb1f609fff13a0ab444387000247304402202a188675c0338c5b148657839923e6655372dbf32cabff003895009ba4c4b0c20220399a760d9aae08c6d9221398a0f822172d0d192603aded233e3afe864e79e49e0121022c76812cd795c4002bda17585086972c92546ea7e7a0996ad595a0ce8043651800000000 diff --git a/lib/ain-dftx/tests/data/icxclaimdfchtlc.txt b/lib/ain-dftx/tests/data/icxclaimdfchtlc.txt new file mode 100644 index 00000000000..f8a59b26e74 --- /dev/null +++ b/lib/ain-dftx/tests/data/icxclaimdfchtlc.txt @@ -0,0 +1,3 @@ +6a464466547835da660ff1965fbdce08cf5ae1b75178abd6a9882d3206e0bf3a1fc7abd1ba969a20f75a61ad8f7a6e0ab701d5be1f5d4523a9b534571e4e92e0c4610c6a6784ccef +6a364466547835da660ff1965fbdce08cf5ae1b75178abd6a9882d3206e0bf3a1fc7abd1ba969a10a9b534571e4e92e0c4610c6a6784ccef +6a274466547835da660ff1965fbdce08cf5ae1b75178abd6a9882d3206e0bf3a1fc7abd1ba969a01f7 diff --git a/lib/ain-dftx/tests/data/icxcloseoffer.txt b/lib/ain-dftx/tests/data/icxcloseoffer.txt new file mode 100644 index 00000000000..f5ddb069813 --- /dev/null +++ b/lib/ain-dftx/tests/data/icxcloseoffer.txt @@ -0,0 +1,3 @@ +6a2544665478373bb3380de375459bf71a0b2dd4c1b392365834a5f1fbebc929415d79efd31152 +6a254466547837788eaf4c2a1611644856715fcc276c21a0a513429630d43d57ead7535131fac0 +6a254466547837aa8a6de3c090d7edf6c20a1cb53059c9a70b7275179fda52c13d415e752de450 diff --git a/lib/ain-dftx/tests/data/icxcloseorder.txt b/lib/ain-dftx/tests/data/icxcloseorder.txt new file mode 100644 index 00000000000..d7c02fffe73 --- /dev/null +++ b/lib/ain-dftx/tests/data/icxcloseorder.txt @@ -0,0 +1,3 @@ +6a2544665478363bb3380de375459bf71a0b2dd4c1b392365834a5f1fbebc929415d79efd31152 +6a254466547836b51d86647bf0110ae624106200a0f6ff7dba4a69533855f4e36535d2135dea6e +6a254466547836e49d88b50b16c35763aca6da6ac53e803ca04197f5b9c0bad82ca6207b64c533 diff --git a/lib/ain-dftx/tests/data/icxcreateorder.txt b/lib/ain-dftx/tests/data/icxcreateorder.txt new file mode 100644 index 00000000000..162ac39e7e4 --- /dev/null +++ b/lib/ain-dftx/tests/data/icxcreateorder.txt @@ -0,0 +1,5 @@ +6a4c5d4466547831010017a914a21888038057490b84aab333846aa568839520d68721037f9563f30c609b19fd435a19b8bde7d6db703012ba1aba72e9f42a87366d1941002f685900000000002f68590000000040420f0000000000400b0000 +6a3c4466547831020017a9149b2552a44b95afa2d435e416f8c16cfd12e97efd870000c2eb0b0000000000c2eb0b0000000000e8764817000000400b0000 +6a4c5d4466547831010017a9149b2552a44b95afa2d435e416f8c16cfd12e97efd8721037f9563f30c609b19fd435a19b8bde7d6db703012ba1aba72e9f42a87366d1941002f685900000000002f68590000000040420f0000000000400b0000 +// {"type":"EXTERNAL","chainFrom":"BTC","tokenTo":"GOLD#167","receivePubkey":"","ownerAddress":"dazewCkFnaw4o67RQrS5FATMKy9mAcohNA","amountFrom":0.00010000,"amountToFill":0.00010000,"orderPrice":200.00000000,"amountToFillInToAsset":0.02000000,"expiry":2900} +6a3d446654783102802717a914ecaa29d217a0961eb2410ee65b587442930e5b4787001027000000000000102700000000000000c817a804000000540b0000 diff --git a/lib/ain-dftx/tests/data/icxmakeoffer.txt b/lib/ain-dftx/tests/data/icxmakeoffer.txt new file mode 100644 index 00000000000..2f135c05f77 --- /dev/null +++ b/lib/ain-dftx/tests/data/icxmakeoffer.txt @@ -0,0 +1,5 @@ +6a4c5244665478324cbd9eecf0444e083de88cd3e5174aa803b00a88885bf7cd7464b47c94694db5809698000000000017a914887b8586ac0c39b0d07e6a479486f32ac4701c538700140000000000000000000000 +6a4c52446654783286ef8673487055726f412f3a472bd87eba9514b2349162785501daaa950e779b809698000000000017a9147df9e0e2fdfe388555c189bf21a1417150c99a468700140000000000000000000000 +6a4c734466547832bfb2faf4dd9d5cb9f9b24bb7b54d566a7feaaa3e3593cf2ea013c948a8dfd74a00e40b540200000017a914668960586aad364c3550ef3e944d356d77206eab87210348790cb93b203a8ea5ce07279cb209d807b535b2ca8b0988a6f7a6578e41f7a5140000000000000000000000 +6a4c7344665478324adf7be28d237ff1f888015fe9be58e45f3d0e2bdea13a533f0ea6d0c2d2965800e40b540200000017a9147df9e0e2fdfe388555c189bf21a1417150c99a4687210348790cb93b203a8ea5ce07279cb209d807b535b2ca8b0988a6f7a6578e41f7a5140000000000000000000000 +6a4c93446654783230d4008be1e0b3535ee0793a210e87c0b9490aa3a98294c472bde3318ccb077e00e40b540200000017a91444d349f8e932bd12dce80d6d623447bfceab3bda874104e6873a6492abfbcf66524249828eee1baf072f3b01db6c1fec05456876229f1ac462019d2cedc8a990056c4fd2df4a8eb930504c2af7dc2a5d776f7072491558140000000000000000000000 // with uncompressed public key diff --git a/lib/ain-dftx/tests/data/icxsubmitdfchtlc.txt b/lib/ain-dftx/tests/data/icxsubmitdfchtlc.txt new file mode 100644 index 00000000000..eef34e1ec0c --- /dev/null +++ b/lib/ain-dftx/tests/data/icxsubmitdfchtlc.txt @@ -0,0 +1,3 @@ +6a4c514466547833d13ee165fbd163c95d2dff1a36d80d5e342603fb5640e4657719476d313d704900ca9a3b0000000020521a24e5418c971da262215bd30bd79f52611a63e038295b603f64fdc07f95a0050000 +6a4c514466547833d13ee165fbd163c95d2dff1a36d80d5e342603fb5640e4657719476d313d7049009435770000000020521a24e5418c971da262215bd30bd79f52611a63e038295b603f64fdc07f95a0050000 +6a4c514466547833d13ee165fbd163c95d2dff1a36d80d5e342603fb5640e4657719476d313d704900286bee0000000020521a24e5418c971da262215bd30bd79f52611a63e038295b603f64fdc07f9528000000 diff --git a/lib/ain-dftx/tests/data/icxsubmitexthtlc.txt b/lib/ain-dftx/tests/data/icxsubmitexthtlc.txt new file mode 100644 index 00000000000..1d41587c0ed --- /dev/null +++ b/lib/ain-dftx/tests/data/icxsubmitexthtlc.txt @@ -0,0 +1,3 @@ +6a4c96446654783491470f554ca0816c2a11ed75a8e5939e915dbb62234ea51ac186ab2f8688e1db809698000000000020521a24e5418c971da262215bd30bd79f52611a63e038295b603f64fdc07f95223133734a51397742576838737369684855674161436d4e574a62424147354872394e21036494e7c9467c8c7ff3bf29e841907fb0fa24241866569944ea422479ec0e625218000000 +6a4c96446654783491470f554ca0816c2a11ed75a8e5939e915dbb62234ea51ac186ab2f8688e1db009435770000000020521a24e5418c971da262215bd30bd79f52611a63e038295b603f64fdc07f95223133734a51397742576838737369684855674161436d4e574a62424147354872394e21036494e7c9467c8c7ff3bf29e841907fb0fa24241866569944ea422479ec0e625218000000 +6a4cb6446654783491470f554ca0816c2a11ed75a8e5939e915dbb62234ea51ac186ab2f8688e1db00286bee0000000020521a24e5418c971da262215bd30bd79f52611a63e038295b603f64fdc07f95223133734a51397742576838737369684855674161436d4e574a62424147354872394e41046494e7c9467c8c7ff3bf29e841907fb0fa24241866569944ea422479ec0e62526494e7c9467c8c7ff3bf29e841907fb0fa24241866569944ea422479ec0e625218000000 diff --git a/lib/ain-dftx/tests/data/paybackloan.txt b/lib/ain-dftx/tests/data/paybackloan.txt new file mode 100644 index 00000000000..1d38c111778 --- /dev/null +++ b/lib/ain-dftx/tests/data/paybackloan.txt @@ -0,0 +1,3 @@ +6a4944665478485123be76c3265a7e9e4df38846f31c6e78417b106be2e3d6a6c49d8e9a7fe23f160014c9fc3eba0fd4ea8a1bc744e2a9b4bcb8cfbc27780102000000008d380c01000000 +6a4c5544665478489199d45bdd1a746f4c899b06b79fadbf61cf88078004cdbc72ab8534406852f916001476060adc229ddaef9e2fea605e3c42954f8605b50202000000006d7c4d00000000030000000046c32300000000 +6a494466547848b5ae61eb821ae6d618d9aab2547eb510a4bee2f61233d3439f333fae7cb87c861600141b3a8f3e1536a96d88f47e8331a58df7ba577e9f0102000000005ed0b200000000 diff --git a/lib/ain-dftx/tests/data/paybackloanv2.txt b/lib/ain-dftx/tests/data/paybackloanv2.txt new file mode 100644 index 00000000000..44e65869ab8 --- /dev/null +++ b/lib/ain-dftx/tests/data/paybackloanv2.txt @@ -0,0 +1,3 @@ +6a4b446654786bb756ced82eb0c343887f04823dee7964ddc290f7b0f720abcf7211d4aacc9b43160014b36814fd26190b321aa985809293a41273cfe15e0101010000000000e40b5402000000 +6a4c59446654786b47295a3a528c038afce93967e37c032d5187e661be04d599d8f809da393c6428160014b36814fd26190b321aa985809293a41273cfe15e0201010000000000e40b540200000002010000000000e40b5402000000 +6a4b446654786ba799baecdb4bf81c43246808da0b5e38cbbd1d84fb13c6e0fd24e419b3c14f12160014b36814fd26190b321aa985809293a41273cfe15e0101010200000000e1f50500000000 diff --git a/lib/ain-dftx/tests/data/placeauctionbid.txt b/lib/ain-dftx/tests/data/placeauctionbid.txt new file mode 100644 index 00000000000..79dba89018e --- /dev/null +++ b/lib/ain-dftx/tests/data/placeauctionbid.txt @@ -0,0 +1,3 @@ +6a494466547849857123da26a73086020f3ec021fb60483819a0cfd6162908b91455370132448900000000160014899d56a326466d9f20c648db501188a3528425bd02006d3e390c000000 +6a4944665478497bdc5dead3afeb11113c510888b73189952f8c060cbb082b0a24dd6e3e600e070100000016001495c1c1048e35b6770334394af830bafc57e047500200d20b570c000000 +6a494466547849ba0d06e93becc4ad24b2a6643bdf130e916745f3407cbf1972efd60fdd20618b00000000160014800b725df95d15cd7bb955132594aa33cdbebc02020037d9740c000000 diff --git a/lib/ain-dftx/tests/data/pooladdliquidity.txt b/lib/ain-dftx/tests/data/pooladdliquidity.txt new file mode 100644 index 00000000000..38530f48a01 --- /dev/null +++ b/lib/ain-dftx/tests/data/pooladdliquidity.txt @@ -0,0 +1,6 @@ +6a4c4f446654786c0117a914055f1a204428e2a826f7555bb1194cb5ea44ce74870200000000d2956e220000000002000000c68900000000000017a914055f1a204428e2a826f7555bb1194cb5ea44ce7487 +6a4c53446654786c011976a9147742abf9be1e2a9e42d665faf9c982c65f41315988ac0200000000fb3f0000000000000200000001000000000000001976a9147742abf9be1e2a9e42d665faf9c982c65f41315988ac +6a4c53446654786c011976a9147742abf9be1e2a9e42d665faf9c982c65f41315988ac0200000000d6ff0100000000000200000008000000000000001976a9147742abf9be1e2a9e42d665faf9c982c65f41315988ac +6a4c4f446654786c0117a9140f759c57d1a3672d3300872b0b0629ebf7a7d4b7870200000000d18cec0b0000000002000000b62f00000000000017a9140f759c57d1a3672d3300872b0b0629ebf7a7d4b787 +6a4c4f446654786c0117a914f197ccd0e95bf4192e98644bb20ca986fbf638028702000000004a76130000000000020000004e0000000000000017a914f197ccd0e95bf4192e98644bb20ca986fbf6380287 +6a4c4f446654786c0117a914c6a4764aa915067e76d48af5a5470c1943bea392870200000000badc2a6a0000000002000000c9a801000000000017a914c6a4764aa915067e76d48af5a5470c1943bea39287 diff --git a/lib/ain-dftx/tests/data/poolcreatepair.txt b/lib/ain-dftx/tests/data/poolcreatepair.txt new file mode 100644 index 00000000000..b5f6fdf176d --- /dev/null +++ b/lib/ain-dftx/tests/data/poolcreatepair.txt @@ -0,0 +1,17 @@ +6a2a44665478700700400d03000000000017a914f78ca7530bd35fff6af98a49522a34f7508ab64e87010000 +6a2c44665478700900400d0300000000001976a9148f83f4f005ba70f0c5d7a59d4696daee13a6e43b88ac010000 +6a2c44665478700b00400d0300000000001976a9148f83f4f005ba70f0c5d7a59d4696daee13a6e43b88ac010000 +6a2b44665478700200400d0300000000001976a9148f83f4f005ba70f0c5d7a59d4696daee13a6e43b88ac0100 +6a2b44665478700100400d0300000000001976a9148f83f4f005ba70f0c5d7a59d4696daee13a6e43b88ac0100 +6a2b44665478700300400d0300000000001976a9148f83f4f005ba70f0c5d7a59d4696daee13a6e43b88ac0100 +6a2a4466547870000200e1f5050000000017a914462093ba56448f9b6d1d22584b3236e2555432d487010000 +6a2a44665478700004000000000000000017a914462093ba56448f9b6d1d22584b3236e2555432d487010000 +6a2a4466547870000100e1f5050000000017a91498f93e07509b6cb0d32557d1e0c2becc1a3e732d87010000 +6a2a4466547870000300e1f5050000000017a91498f93e07509b6cb0d32557d1e0c2becc1a3e732d87010000 +6a2a4466547870000580f0fa020000000017a91498f93e07509b6cb0d32557d1e0c2becc1a3e732d87010000 +6a2a4466547870000780f0fa020000000017a914809a32165e7eb9544f7415f3ad0cb817a1eeb0bb87010000 +6a2a4466547870000880f0fa020000000017a914809a32165e7eb9544f7415f3ad0cb817a1eeb0bb87000000 +6a2a4466547870000b00e1f5050000000017a914809a32165e7eb9544f7415f3ad0cb817a1eeb0bb87010000 +6a364466547870000500e1f5050000000017a9147c5bb84ff74b5df9f4354c812f2be90cbea3d5038701000100000000c02a641000000000 +6a424466547870000d00e1f5050000000017a91498f93e07509b6cb0d32557d1e0c2becc1a3e732d870100020000000000e1f505000000000d00000000a3e11100000000 +6a484466547870000f00e1f5050000000017a91498f93e07509b6cb0d32557d1e0c2becc1a3e732d8701064446492d5356020000000000e1f505000000000d00000000a3e11100000000 diff --git a/lib/ain-dftx/tests/data/poolremoveliquidity.txt b/lib/ain-dftx/tests/data/poolremoveliquidity.txt new file mode 100644 index 00000000000..8e5eaa096f8 --- /dev/null +++ b/lib/ain-dftx/tests/data/poolremoveliquidity.txt @@ -0,0 +1,10 @@ +6a2844665478721976a91402241c4fbe4ea2dbb8d655ea64076d134a852b3b88ac0603572dc918000000 +6a26446654787217a914f5fe3eba6fc3fb484eadf4ee6d3364a7c9bec19487053fd0317001000000 +6a26446654787217a914bbf8a34b35c82638a185bc782954c5f6b3676bbb8706402543971d000000 +6a26446654787217a9146cfc56cf3303a155f1ae6ca157169e7b42a07bf087044614d91100000000 +6a26446654787217a9140164e31629342622b35bc134c8e4fe7c45c42e438705c088058601000000 +6a26446654787217a9140dd111af010f5254516ed2498e75cbd11bb8b2e7870c55a4230500000000 +6a26446654787217a9143abf0fbb5a88323815b06fe793794e01484cf42f87067a76dbf41b000000 +6a26446654787217a9143abf0fbb5a88323815b06fe793794e01484cf42f8706668e2a690b000000 +6a26446654787217a9143abf0fbb5a88323815b06fe793794e01484cf42f8706b82356c305000000 +6a26446654787217a9143abf0fbb5a88323815b06fe793794e01484cf42f87067d3f3c0318000000 diff --git a/lib/ain-dftx/tests/data/poolswap.txt b/lib/ain-dftx/tests/data/poolswap.txt new file mode 100644 index 00000000000..caac9e2163d --- /dev/null +++ b/lib/ain-dftx/tests/data/poolswap.txt @@ -0,0 +1,13 @@ +6a4c4f446654787317a9140806eb42b6d5bb69726909fb6da34a9152afdf048701c7b3240d0000000017a9140806eb42b6d5bb69726909fb6da34a9152afdf048700ffffffffffffff7fffffffffffffff7f +6a4c4f446654787317a914c34ca9c54dc87e7e875b212ec6ba0704be3de587870000d6117e0300000017a914c34ca9c54dc87e7e875b212ec6ba0704be3de58787022fe28e7915000080ffcf430300000000 +6a4c4f446654787317a914635794bb3db157b6dac4dcb7467710a10f03c6ac8700809698000000000017a914582328ee9beebc3fb5844964302cc0fdbb27e04c87022fe28e7915000080ffcf430300000000 +6a4c4f446654787317a9148646fc3d44c92e190c18db1cf08f430e421dba9887005671518a0000000017a9148646fc3d44c92e190c18db1cf08f430e421dba988707a0860100000000000000000000000000 +6a4c4f446654787317a9140c1ff6de17f73dad607a2b03b5bd77b4e57327e58707d3e2a0470000000017a9140c1ff6de17f73dad607a2b03b5bd77b4e57327e587002fe28e7915000080ffcf430300000000 +6a4c4f446654787317a914094b5e971325dee0161beccc7a78592f95c27100870080397a120000000017a914094b5e971325dee0161beccc7a78592f95c2710087022fe28e7915000080ffcf430300000000 +6a4c4f446654787317a914f64714403dd1b872494851ca4ed8d5071af79ea6870087b4104d0200000017a914f64714403dd1b872494851ca4ed8d5071af79ea68707a0860100000000000000000000000000 +6a4c5144665478731976a9140b7127e943eaa3f28536c3f046ddbdeb790f691e88ac0080889e2a0100000017a914b3a65aa3fd9c60860bebd231d71b5bc5749ff5be87022fe28e7915000080ffcf430300000000 +6a4c4f446654787317a9140164e31629342622b35bc134c8e4fe7c45c42e43870205fd0b030000000017a9140164e31629342622b35bc134c8e4fe7c45c42e4387002fe28e7915000080ffcf430300000000 +6a4c4f446654787317a914963a12667d64728009567ad5eb26777e1673c479870000db7d2e0000000017a914963a12667d64728009567ad5eb26777e1673c47987022fe28e7915000080ffcf430300000000 +6a4c4f446654787317a91437243b861c6b234a65f52fe288e01188c1e1d5f28700010000000000000017a91437243b861c6b234a65f52fe288e01188c1e1d5f28702ffffffffffffff7fffffffffffffff7f +6a4c4f446654787317a91437243b861c6b234a65f52fe288e01188c1e1d5f28700010000000000000017a91437243b861c6b234a65f52fe288e01188c1e1d5f28702ffffffffffffff7fffffffffffffff7f4c4f446654787317a91437243b861c6b234a65f52fe288e01188c1e1d5f28700010000000000000017a91437243b861c6b234a65f52fe288e01188c1e1d5f28702ffffffffffffff7fffffffffffffff7f +6a0444665478001b2382040000000017a91494bef08bed0a05f40e87f44b1ec8d24b2c05a23387000247304402202e44173f7e17bddaee068957911e06be3ff21a3ecc91926c7ae8cba66fe5a546022051d83a8917d44649b7cd5f4e6a0b332e4642b03b98d5f06cb4b3e792f6915e330121027664df34364aedd50d608d528034d34466bce2fbeda08c41a6446e909f41164800000000 diff --git a/lib/ain-dftx/tests/data/poolupdatepair.txt b/lib/ain-dftx/tests/data/poolupdatepair.txt new file mode 100644 index 00000000000..f8c494d08fd --- /dev/null +++ b/lib/ain-dftx/tests/data/poolupdatepair.txt @@ -0,0 +1,7 @@ +6a144466547875020000000100e1f505000000000000 +6a2b44665478750200000000ffffffffffffffff17a91440d54b7a72387cb5c6d0125f2890eabf052f01908700 +6a2c44665478750200000000ffffffffffffffff00020000000000e1f505000000000100000000a3e11100000000 +6a2044665478750200000000ffffffffffffffff0001000000000008af2f00000000 +6a434466547875020000000120a107000000000017a914fd190704714762e6c30eb5b39071c1a52e6130ad87020000000000ca9a3b00000000010000000094357700000000 +6a2a44665478750300000001c0cf6a000000000017a9141205616a55fbbdd91ec97e222fae709acc4fd2c887 +6a204466547875e500000001ffffffffffffffff0001ffffffffffffffffffffff7f diff --git a/lib/ain-dftx/tests/data/removeoracle.txt b/lib/ain-dftx/tests/data/removeoracle.txt new file mode 100644 index 00000000000..bcab663726e --- /dev/null +++ b/lib/ain-dftx/tests/data/removeoracle.txt @@ -0,0 +1 @@ +6a254466547868061d35948925528b2025c4b84ea6f4899bab6efbcaf63776258186d7728424d1 diff --git a/lib/ain-dftx/tests/data/resignmasternode.txt b/lib/ain-dftx/tests/data/resignmasternode.txt new file mode 100644 index 00000000000..e81f59f932a --- /dev/null +++ b/lib/ain-dftx/tests/data/resignmasternode.txt @@ -0,0 +1,2 @@ +6a254466547852bea590236c7d994fbc2283a0e84934022afc1adb8472e409c35ef9a7aa9920a3 +6a2544665478525fe549cb230b0ec515de27d0bb7ae5642d47bfeb08b4210d9d2a5ddf2ef71f81 diff --git a/lib/ain-dftx/tests/data/scriptbalances.txt b/lib/ain-dftx/tests/data/scriptbalances.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ain-dftx/tests/data/setcollateraltoken.txt b/lib/ain-dftx/tests/data/setcollateraltoken.txt new file mode 100644 index 00000000000..30677c43487 --- /dev/null +++ b/lib/ain-dftx/tests/data/setcollateraltoken.txt @@ -0,0 +1,3 @@ +6a1d446654786301809698000000000006546f6b656e310355534400000000 +6a1d446654786301809698000000000006546f6b656e310355534400000000 +6a1d446654786302002d31010000000006546f6b656e320355534400000000 diff --git a/lib/ain-dftx/tests/data/setdefaultloanscheme.txt b/lib/ain-dftx/tests/data/setdefaultloanscheme.txt new file mode 100644 index 00000000000..f6358d3c763 --- /dev/null +++ b/lib/ain-dftx/tests/data/setdefaultloanscheme.txt @@ -0,0 +1 @@ +6a0d446654786407736368656d6532 diff --git a/lib/ain-dftx/tests/data/setgovernance.txt b/lib/ain-dftx/tests/data/setgovernance.txt new file mode 100644 index 00000000000..39d1d80819e --- /dev/null +++ b/lib/ain-dftx/tests/data/setgovernance.txt @@ -0,0 +1,13 @@ +6a284466547847 +6a284466547847094c505f53504c4954530202000000809698000000000004000000804a5d0500000000 +6a214466547847134c505f4441494c595f4446495f52455741524400204aa9d1010000 +6a444466547847094c505f53504c495453020200000080c3c9010000000004000000801d2c0400000000134c505f4441494c595f4446495f524557415244c01c3d0900000000 +6a444466547847094c505f53504c4954530202000000809698000000000004000000804a5d0500000000134c505f4441494c595f4446495f52455741524400204aa9d1010000 +// {"txid": "cc3f29069763eb53d938adf7fceaf433ff3cb1cd73b04873fadcc0de4f590a55","type": "SetGovVariable","valid": true,"results": {"ATTRIBUTES": {"v0/token/34/dex_in_fee_pct": "0.001","v0/token/34/dex_out_fee_pct": "0.001","v0/token/37/dex_in_fee_pct": "0.001","v0/token/37/dex_out_fee_pct": "0.001","v0/token/49/dex_in_fee_pct": "0.001","v0/token/49/dex_out_fee_pct": "0.001","v0/token/50/dex_in_fee_pct": "0.001","v0/token/50/dex_out_fee_pct": "0.001","v0/token/51/dex_in_fee_pct": "0.001","v0/token/51/dex_out_fee_pct": "0.001","v0/token/52/dex_in_fee_pct": "0.001","v0/token/52/dex_out_fee_pct": "0.001","v0/token/57/dex_in_fee_pct": "0.001","v0/token/57/dex_out_fee_pct": "0.001","v0/token/58/dex_in_fee_pct": "0.001","v0/token/58/dex_out_fee_pct": "0.001","v0/token/59/dex_in_fee_pct": "0.001","v0/token/59/dex_out_fee_pct": "0.001","v0/token/60/dex_in_fee_pct": "0.001","v0/token/60/dex_out_fee_pct": "0.001"}}} +6a4dc90144665478470a41545452494255544553140000000074220000006501000000a0860100000000000000000074220000006601000000a0860100000000000000000074250000006501000000a0860100000000000000000074250000006601000000a0860100000000000000000074310000006501000000a0860100000000000000000074310000006601000000a0860100000000000000000074320000006501000000a0860100000000000000000074320000006601000000a0860100000000000000000074330000006501000000a0860100000000000000000074330000006601000000a0860100000000000000000074340000006501000000a0860100000000000000000074340000006601000000a0860100000000000000000074390000006501000000a0860100000000000000000074390000006601000000a08601000000000000000000743a0000006501000000a08601000000000000000000743a0000006601000000a08601000000000000000000743b0000006501000000a08601000000000000000000743b0000006601000000a08601000000000000000000743c0000006501000000a08601000000000000000000743c0000006601000000a086010000000000 +// {'ATTRIBUTES': {'v0/locks/token/6': 'false'}} +6a2044665478470a4154545249425554455301000000004c63000000060000000000 +//"ATTRIBUTES": { "v0/token/3/dex_in_fee_pct": "0.02" } +6a2744665478470a4154545249425554455301000000007403000000650100000080841e0000000000 +// {"ATTRIBUTES": {"v0/token/0/fixed_interval_price_id": DFI/USD"}} +6a2744665478470a415454524942555445530100000000740000000068040000000344464903555344 diff --git a/lib/ain-dftx/tests/data/setgovernanceheight.txt b/lib/ain-dftx/tests/data/setgovernanceheight.txt new file mode 100644 index 00000000000..5010f7c3958 --- /dev/null +++ b/lib/ain-dftx/tests/data/setgovernanceheight.txt @@ -0,0 +1,8 @@ +6a2c446654786a094c505f53504c4954530202000000809698000000000004000000804a5d050000000078563412 +6a25446654786a134c505f4441494c595f4446495f52455741524400204aa9d101000078563412 +// '{txid:e4624d61d490acca9018ca23205b7f89eaefeb9918ea6abc2c8151c716207fe7,type:SetGovVariableHeight,valid:true,results:{LP_LOAN_TOKEN_SPLITS:{17:0.5,18:0.070357,25:0.030819,32:0.016884,33:0.027171,35:0.019166,36:0.036801,38:0.079318,39:0.049913,40:0.005233,41:0.007097,42:0.021566,43:0.007155,44:0.005367,45:0.010153,46:0.009777,53:0.010496,54:0.027875,55:0.036803,56:0.028049},startHeight:1585500}}' +6a4cd3446654786a144c505f4c4f414e5f544f4b454e5f53504c495453141180f0fa020000000012345b6b000000000019ac062f00000000002050c319000000000021ac7529000000000023b83e1d00000000002464273800000000002698077900000000002744294c00000000002824fc0700000000002944d40a00000000002a38e82000000000002becea0a00000000002c7c300800000000002d047e0f00000000002e24eb0e000000000035000410000000000036ac882a0000000000372c2838000000000038a4cc2a00000000005c311800 +// {"txid": "65498b9b2018347a174f8dbd45a14af6a9773c96f511342d85f01b778aa2cdab","type": "SetGovVariableHeight","valid": true,"results": {"LP_LOAN_TOKEN_SPLITS": {"17": 0.50000000,"18": 0.04912800,"25": 0.03596300,"32": 0.01265500,"33": 0.01911500,"35": 0.01447000,"36": 0.02635000,"38": 0.06581900,"39": 0.03898200,"40": 0.00869200,"41": 0.00438200,"42": 0.01455700,"43": 0.00786900,"44": 0.00504600,"45": 0.00827100,"46": 0.00797400,"53": 0.00811600,"54": 0.02210300,"55": 0.03050900,"56": 0.01589400,"61": 0.01890200,"62": 0.01420800,"63": 0.00758400,"64": 0.02009300,"69": 0.00758700,"70": 0.00810800,"71": 0.01659000,"72": 0.01103300},"startHeight": 1766000}} +6a4d1b01446654786a144c505f4c4f414e5f544f4b454e5f53504c4954531c1180f0fa020000000012a0f64a0000000000190ce0360000000000205c4f13000000000021cc2a1d000000000023581416000000000024f834280000000000268c6e64000000000027587b3b00000000002850430d000000000029b8af0600000000002a54361600000000002bd4010c00000000002c18b30700000000002ddc9e0c00000000002ed82a0c00000000003550620c000000000036fcb921000000000037948d2e00000000003898401800000000003d98d71c00000000003e00ae1500000000003f80920b000000000040d4a81e000000000045ac930b000000000046305f0c000000000047785019000000000048c4d510000000000070f21a00 +// {"ATTRIBUTES": {"v0/poolpairs/17/token_a_fee_pct": "0.005"},"startHeight": 1896000} +6a2b446654786a0a4154545249425554455301000000007011000000610100000020a107000000000040ee1c diff --git a/lib/ain-dftx/tests/data/setloanscheme.txt b/lib/ain-dftx/tests/data/setloanscheme.txt new file mode 100644 index 00000000000..4da3efbad38 --- /dev/null +++ b/lib/ain-dftx/tests/data/setloanscheme.txt @@ -0,0 +1,3 @@ +6a20446654784cc800000000c817a80400000006736368656d650000000000000000 +6a20446654784cc800000000c817a80400000006736368656d65c800000000000000 +6a20446654784c2c01000000ac23fc0600000006736368656d652c01000000000000 diff --git a/lib/ain-dftx/tests/data/setloantoken.txt b/lib/ain-dftx/tests/data/setloantoken.txt new file mode 100644 index 00000000000..fc716f704af --- /dev/null +++ b/lib/ain-dftx/tests/data/setloantoken.txt @@ -0,0 +1,3 @@ +6a27446654786706546f6b656e3106546f6b656e3106546f6b656e3103555344010000000000000000 +6a27446654786706546f6b656e3206546f6b656e3206546f6b656e3203555344000000000000000000 +6a27446654786706546f6b656e3306546f6b656e3306546f6b656e3303555344017802964900000000 diff --git a/lib/ain-dftx/tests/data/setoracledata.txt b/lib/ain-dftx/tests/data/setoracledata.txt new file mode 100644 index 00000000000..e91e2b4302a --- /dev/null +++ b/lib/ain-dftx/tests/data/setoracledata.txt @@ -0,0 +1 @@ +6a414466547879061d35948925528b2025c4b84ea6f4899bab6efbcaf63776258186d7728424d1bc29a7600000000001055445534c41010355534400e1f50500000000 diff --git a/lib/ain-dftx/tests/data/takeloan.txt b/lib/ain-dftx/tests/data/takeloan.txt new file mode 100644 index 00000000000..5678618c39e --- /dev/null +++ b/lib/ain-dftx/tests/data/takeloan.txt @@ -0,0 +1,3 @@ +6a3344665478581690a45a4cfe5735f346ed2c7df334f39f72c68ced1f30568f000e7063f55b6f00010200000000286bee00000000 +6a3f44665478581690a45a4cfe5735f346ed2c7df334f39f72c68ced1f30568f000e7063f55b6f00020200000000286bee000000000300000000286bee00000000 +6a4944665478581690a45a4cfe5735f346ed2c7df334f39f72c68ced1f30568f000e7063f55b6f1600149d04d9764bdd97432f13411fe9753f808dc27926010200000000286bee00000000 diff --git a/lib/ain-dftx/tests/data/tokenbalance.txt b/lib/ain-dftx/tests/data/tokenbalance.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/ain-dftx/tests/data/tokenburn.txt b/lib/ain-dftx/tests/data/tokenburn.txt new file mode 100644 index 00000000000..638a141e256 --- /dev/null +++ b/lib/ain-dftx/tests/data/tokenburn.txt @@ -0,0 +1,3 @@ +6a454466547846010100000000e1f505000000001600142aeb22d24f75e4daceaf48d15c41b6f46c6e3b6400000000001600142aeb22d24f75e4daceaf48d15c41b6f46c6e3b64 +6a454466547846010100000000e9a43500000000160014080371d2d8ed3834e00487eca91004bd7f2430270000000000160014080371d2d8ed3834e00487eca91004bd7f243027 +6a2f446654784601010000000065cd1d00000000160014ce52ee5f9b20d909702f714dc552ce2422337d9d000000000000 diff --git a/lib/ain-dftx/tests/data/tokencreate.txt b/lib/ain-dftx/tests/data/tokencreate.txt new file mode 100644 index 00000000000..e25f7d08ecb --- /dev/null +++ b/lib/ain-dftx/tests/data/tokencreate.txt @@ -0,0 +1,8 @@ +6a1b44665478540342544307426974636f696e08000000000000000003 +6a19446654785404474f4c4404476f6c6408000000000000000003 +6a224466547854035753420e77616c6c7374726565746265747308000000000000000003 +6a174466547854034748490347484908000000000000000004 +6a174466547854034a4b4c034a4b4c08000000000000000000 +6a174466547854034d4e4f034d4e4f08000000000000000001 +6a174466547854035051520350515208000000000000000007 +6a174466547854034142430341424308000000000000000005 diff --git a/lib/ain-dftx/tests/data/tokenmint.txt b/lib/ain-dftx/tests/data/tokenmint.txt new file mode 100644 index 00000000000..9d1179ac2c6 --- /dev/null +++ b/lib/ain-dftx/tests/data/tokenmint.txt @@ -0,0 +1,4 @@ +6a13446654784d010200000000ca9a3b0000000000 +6a13446654784d010200000000ea56fa0000000000 +6a29446654784d010100000000e1f50500000000160014dd527be30bedb3de69fee5ebe32af430686cfe3f +6a12446654784d01020000000046c32300000000 diff --git a/lib/ain-dftx/tests/data/tokenupdate.txt b/lib/ain-dftx/tests/data/tokenupdate.txt new file mode 100644 index 00000000000..e4f642e1146 --- /dev/null +++ b/lib/ain-dftx/tests/data/tokenupdate.txt @@ -0,0 +1 @@ +6a26446654784effe50b27cd4325e9a87401e833a9caccf256e0b4ea37b6c4fb038bedc1cb247100 diff --git a/lib/ain-dftx/tests/data/tokenupdateany.txt b/lib/ain-dftx/tests/data/tokenupdateany.txt new file mode 100644 index 00000000000..f0cb73bde92 --- /dev/null +++ b/lib/ain-dftx/tests/data/tokenupdateany.txt @@ -0,0 +1,3 @@ +6a37446654786ed819f622ced3616e3c02e5337b54cbf921c364e182a80925219e1f60461ee5fc034341540343415408000000000000000001 +6a38446654786effe50b27cd4325e9a87401e833a9caccf256e0b4ea37b6c4fb038bedc1cb2471044f57574c034f574c08000000000000000007 +6a39446654786effe50b27cd4325e9a87401e833a9caccf256e0b4ea37b6c4fb038bedc1cb2471034f574c054e4947485408000000000000000007 diff --git a/lib/ain-dftx/tests/data/transferdomain.txt b/lib/ain-dftx/tests/data/transferdomain.txt new file mode 100644 index 00000000000..04c930f45c9 --- /dev/null +++ b/lib/ain-dftx/tests/data/transferdomain.txt @@ -0,0 +1,2 @@ +6a4d9e014466547838011976a914b36814fd26190b321aa985809293a41273cfe15e88ac0015cd5b07000000000200166014897e03dda17125f022a853c1a4d84021f44a8a9b0015cd5b070000000003fd4f01f9014c808502540be400830186a094000000000000000000000000000000000000030280b8e4d57b28260000000000000000000000000a06de8abc3f15359ec0dfe32394c8b8f09e828f0000000000000000000000009b8a4af42140d8a4c153a822f02571a1dd037e89000000000000000000000000000000000000000000000000112210f4768db400000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000226d77735a77386e4637704b78574838656f4b4c39745078547061466b7a3751654c550000000000000000000000000000000000000000000000000000000000008208fda0575c288a449935a857409f96b0e655f917d383f02ae7a71ec7b9433534ac22eda05e7063b07c9816334e36251ccdd3eca8d360b3adb12078fe605ee30d32e15a12 +6a4d9e01446654783801166014897e03dda17125f022a853c1a4d84021f44a8a9b0015cd5b070000000003fd4f01f9014c808502540be400830186a094df0000000000000000000000000000000000000180b8e4d57b28260000000000000000000000009b8a4af42140d8a4c153a822f02571a1dd037e89000000000000000000000000df00000000000000000000000000000000000001000000000000000000000000000000000000000000000000112210f4768db400000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000226d77735a77386e4637704b78574838656f4b4c39745078547061466b7a3751654c550000000000000000000000000000000000000000000000000000000000008208fda0bbde8a695f9a1851de608627014eab97d4e649a0782bac21bcff78d93122d3e1a056dc98b61aff3d7bf0fb99a542373f2797dffd6e8f06e53377b3cfe7305f63241976a914b36814fd26190b321aa985809293a41273cfe15e88ac0015cd5b07000000000200 diff --git a/lib/ain-dftx/tests/data/updateloantoken.txt b/lib/ain-dftx/tests/data/updateloantoken.txt new file mode 100644 index 00000000000..03fb48b93e9 --- /dev/null +++ b/lib/ain-dftx/tests/data/updateloantoken.txt @@ -0,0 +1,3 @@ +6a47446654787806546f6b656e3206546f6b656e3206546f6b656e3203555344010000000000000000133d7a00d1068bf596729f9ae883c1c8b0d186a1a1bf0685e5467ea7dcb67f20 +6a47446654787806546f6b656e3306546f6b656e3306546f6b656e3303555344000000000000000000133d7a00d1068bf596729f9ae883c1c8b0d186a1a1bf0685e5467ea7dcb67f20 +6a47446654787806546f6b656e3406546f6b656e3406546f6b656e3403555344017802964900000000133d7a00d1068bf596729f9ae883c1c8b0d186a1a1bf0685e5467ea7dcb67f20 diff --git a/lib/ain-dftx/tests/data/updatemasternode.txt b/lib/ain-dftx/tests/data/updatemasternode.txt new file mode 100644 index 00000000000..f702c90d4a1 --- /dev/null +++ b/lib/ain-dftx/tests/data/updatemasternode.txt @@ -0,0 +1,9 @@ +6a3d446654786d2319bc7b76b6916d0b61ee7a408d47d33380be746d11a5702bd87bbee5f8d3bd010104141db4d4d5e7d01091545e5573494b2fd1e91215d9 +6a3d446654786d2319bc7b76b6916d0b61ee7a408d47d33380be746d11a5702bd87bbee5f8d3bd010204141db4d4d5e7d01091545e5573494b2fd1e91215d9 +6a3d446654786d2319bc7b76b6916d0b61ee7a408d47d33380be746d11a5702bd87bbee5f8d3bd010304141db4d4d5e7d01091545e5573494b2fd1e91215d9 +6a4c6b446654786d2319bc7b76b6916d0b61ee7a408d47d33380be746d11a5702bd87bbee5f8d3bd030104141db4d4d5e7d01091545e5573494b2fd1e91215d902041476e76cdb4de312861ce893f307e7e2bd40a8ac2d030414b188e161a83571c5acd9dd40b316796a47c606d1 +6a3d446654786d2319bc7b76b6916d0b61ee7a408d47d33380be746d11a5702bd87bbee5f8d3bd010101141db4d4d5e7d01091545e5573494b2fd1e91215d9 +6a3d446654786d2319bc7b76b6916d0b61ee7a408d47d33380be746d11a5702bd87bbee5f8d3bd010201141db4d4d5e7d01091545e5573494b2fd1e91215d9 +6a3d446654786d2319bc7b76b6916d0b61ee7a408d47d33380be746d11a5702bd87bbee5f8d3bd010301141db4d4d5e7d01091545e5573494b2fd1e91215d9 +6a4c6b446654786d2319bc7b76b6916d0b61ee7a408d47d33380be746d11a5702bd87bbee5f8d3bd030101141db4d4d5e7d01091545e5573494b2fd1e91215d902011476e76cdb4de312861ce893f307e7e2bd40a8ac2d030114b188e161a83571c5acd9dd40b316796a47c606d1 +6a29446654786d2319bc7b76b6916d0b61ee7a408d47d33380be746d11a5702bd87bbee5f8d3bd01040000 diff --git a/lib/ain-dftx/tests/data/updateoracle.txt b/lib/ain-dftx/tests/data/updateoracle.txt new file mode 100644 index 00000000000..7fb717497ea --- /dev/null +++ b/lib/ain-dftx/tests/data/updateoracle.txt @@ -0,0 +1 @@ +6a4c5f4466547874061d35948925528b2025c4b84ea6f4899bab6efbcaf63776258186d7728424d11976a914ad1eaafdd6edcf2260f28cb31e24117c240681ca88ac0503055445534c4103455552055445534c41034a5059055445534c4103555344 diff --git a/lib/ain-dftx/tests/data/updatevault.txt b/lib/ain-dftx/tests/data/updatevault.txt new file mode 100644 index 00000000000..9f6a326f8f2 --- /dev/null +++ b/lib/ain-dftx/tests/data/updatevault.txt @@ -0,0 +1,3 @@ +6a44446654787676e0d85846482f6844b2e76511269f02a592eb6fa6230f41bd428ce375836c4916001455a7c9d2eec68395402477e31782104533ac809a07736368656d6531 +6a44446654787616e909cf35183387be09c76af375d677dcc58bb8ad37e9cff1b32da58eaabf93160014adc8f20a9e94802cac3fb110603764a9c77d92cc07736368656d6532 +6a44446654787616e909cf35183387be09c76af375d677dcc58bb8ad37e9cff1b32da58eaabf93160014adc8f20a9e94802cac3fb110603764a9c77d92cc07736368656d6532 diff --git a/lib/ain-dftx/tests/data/utxostoaccount.txt b/lib/ain-dftx/tests/data/utxostoaccount.txt new file mode 100644 index 00000000000..7daf52ebeec --- /dev/null +++ b/lib/ain-dftx/tests/data/utxostoaccount.txt @@ -0,0 +1,10 @@ +6a2b44665478550117a91445903c2015cce2e8c3ac5fc13db388ccfd23d56387010000000059b8fa4004000000 +6a2b44665478550117a91445903c2015cce2e8c3ac5fc13db388ccfd23d5638701000000004e32624204000000 +6a2b44665478550117a914ea0e3fde9a9d281e348b3d05bc83d7da95eb631e8701000000004b44140000000000 +6a2d4466547855011976a9142d34be7852e3741b974bec9c49e3b99ee08b89d888ac0100000000d705140b00000000 +6a2b44665478550117a914462633e915dc1670f353568b8774da38c555bc2b87010000000074cab42901000000 +6a2b44665478550117a914f5fe3eba6fc3fb484eadf4ee6d3364a7c9bec194870100000000afce935200000000 +6a2b44665478550117a91469d2048d15b991eeebdd1e6b8391b5414da3ece58701000000009c81a20100000000 +6a2b44665478550117a91491b76ba9a57e3821ab4b623265f20ef551e6c4cd8701000000006fd1190000000000 +6a2b44665478550117a914a6adde29e5ebe8592cbf83fca196c0b363ad9278870100000000bcdc41eb04000000 +6a2b44665478550117a914a6adde29e5ebe8592cbf83fca196c0b363ad92788701000000005fa6480000000000 diff --git a/lib/ain-dftx/tests/data/vote.txt b/lib/ain-dftx/tests/data/vote.txt new file mode 100644 index 00000000000..10644564cd2 --- /dev/null +++ b/lib/ain-dftx/tests/data/vote.txt @@ -0,0 +1,3 @@ +6a46446654784f680aaa128c5f016b04f1a496ada226a99f5a18ead478a2ac6a665620b0987869b45fd5be75bde9dda6f11bb58e386a29834aa452413f3123f40acc6178026ce801 +6a46446654784fe91d11fb83d2b533dff7681007e2e4fa071e9d43b447ab01e37ed9351d270d2ab45fd5be75bde9dda6f11bb58e386a29834aa452413f3123f40acc6178026ce802 +6a46446654784f82e2059745d5e2c886b07b25dce73e2fb803aec8cb0f9adcbecd43e8dd879603b45fd5be75bde9dda6f11bb58e386a29834aa452413f3123f40acc6178026ce803 diff --git a/lib/ain-dftx/tests/data/withdrawfromvault.txt b/lib/ain-dftx/tests/data/withdrawfromvault.txt new file mode 100644 index 00000000000..3a9ad8071f1 --- /dev/null +++ b/lib/ain-dftx/tests/data/withdrawfromvault.txt @@ -0,0 +1,3 @@ +6a45446654784aaec2e44aa7a618b4b8d911c3e270616553debabf90199c8147d5038f55b059ed16001488d52b9b1dded932272e0c9bebb0dccdd46ecf99000010a5d4e8000000 +6a45446654784aaec2e44aa7a618b4b8d911c3e270616553debabf90199c8147d5038f55b059ed16001488d52b9b1dded932272e0c9bebb0dccdd46ecf990100e1f50500000000 +6a45446654784a1f6556382e79003f3020c4e30a4f23eba007c2c5038c57bd23397fdee085e6a9160014ab833c2bf1be8430cf75e4f67dd66c341685c1820200e1f50500000000 diff --git a/lib/ain-dftx/tests/evmtx.rs b/lib/ain-dftx/tests/evmtx.rs new file mode 100644 index 00000000000..b75ac86fa37 --- /dev/null +++ b/lib/ain-dftx/tests/evmtx.rs @@ -0,0 +1,5 @@ +use ain_macros::test_dftx_serialization; + +#[test] +#[test_dftx_serialization] +fn test_evm_tx() {} diff --git a/lib/ain-dftx/tests/governance.rs b/lib/ain-dftx/tests/governance.rs new file mode 100644 index 00000000000..d6d5d5c60df --- /dev/null +++ b/lib/ain-dftx/tests/governance.rs @@ -0,0 +1,21 @@ +use ain_macros::test_dftx_serialization; + +#[test] +#[test_dftx_serialization] +fn test_set_governance() {} + +#[test] +#[test_dftx_serialization] +fn test_set_governance_height() {} + +#[test] +#[test_dftx_serialization] +fn test_create_cfp() {} + +#[test] +#[test_dftx_serialization] +fn test_create_voc() {} + +#[test] +#[test_dftx_serialization] +fn test_vote() {} diff --git a/lib/ain-dftx/tests/icxorderbook.rs b/lib/ain-dftx/tests/icxorderbook.rs new file mode 100644 index 00000000000..0acc9050d98 --- /dev/null +++ b/lib/ain-dftx/tests/icxorderbook.rs @@ -0,0 +1,29 @@ +use ain_macros::test_dftx_serialization; + +#[test] +#[test_dftx_serialization] +fn test_icx_create_order() {} + +#[test] +#[test_dftx_serialization] +fn test_icx_make_offer() {} + +#[test] +#[test_dftx_serialization] +fn test_icx_submit_dfc_htlc() {} + +#[test] +#[test_dftx_serialization] +fn test_icx_submit_ext_htlc() {} + +#[test] +#[test_dftx_serialization] +fn test_icx_claim_dfc_htlc() {} + +#[test] +#[test_dftx_serialization] +fn test_icx_close_order() {} + +#[test] +#[test_dftx_serialization] +fn test_icx_close_offer() {} diff --git a/lib/ain-dftx/tests/loans.rs b/lib/ain-dftx/tests/loans.rs new file mode 100644 index 00000000000..b9395513983 --- /dev/null +++ b/lib/ain-dftx/tests/loans.rs @@ -0,0 +1,37 @@ +use ain_macros::test_dftx_serialization; + +#[test] +#[test_dftx_serialization] +fn test_set_loan_scheme() {} + +#[test] +#[test_dftx_serialization] +fn test_destroy_loan_scheme() {} + +#[test] +#[test_dftx_serialization] +fn test_set_default_loan_scheme() {} + +#[test] +#[test_dftx_serialization] +fn test_set_collateral_token() {} + +#[test] +#[test_dftx_serialization] +fn test_set_loan_token() {} + +#[test] +#[test_dftx_serialization] +fn test_update_loan_token() {} + +#[test] +#[test_dftx_serialization] +fn test_take_loan() {} + +#[test] +#[test_dftx_serialization] +fn test_payback_loan() {} + +#[test] +#[test_dftx_serialization] +fn test_payback_loan_v2() {} diff --git a/lib/ain-dftx/tests/masternode.rs b/lib/ain-dftx/tests/masternode.rs new file mode 100644 index 00000000000..8a2fe1693fc --- /dev/null +++ b/lib/ain-dftx/tests/masternode.rs @@ -0,0 +1,13 @@ +use ain_macros::test_dftx_serialization; + +#[test] +#[test_dftx_serialization] +fn test_create_masternode() {} + +#[test] +#[test_dftx_serialization] +fn test_resign_masternode() {} + +#[test] +#[test_dftx_serialization] +fn test_update_masternode() {} diff --git a/lib/ain-dftx/tests/oracles.rs b/lib/ain-dftx/tests/oracles.rs new file mode 100644 index 00000000000..4216bc715e9 --- /dev/null +++ b/lib/ain-dftx/tests/oracles.rs @@ -0,0 +1,75 @@ +use ain_dftx::{ + types::{ + oracles::{RemoveOracle, SetOracleData}, + price::{TokenAmount, TokenPrice}, + }, + DfTx, COIN, +}; +use ain_macros::test_dftx_serialization; +use bitcoin::consensus::deserialize; + +#[test] +#[test_dftx_serialization] +fn test_set_oracle_data() { + let fixtures = [ + ("6a414466547879061d35948925528b2025c4b84ea6f4899bab6efbcaf63776258186d7728424d1bc29a7600000000001055445534c41010355534400e1f50500000000", + SetOracleData { + oracle_id: "d1248472d78681257637f6cafb6eab9b89f4a64eb8c425208b52258994351d06" + .parse() + .unwrap(), + timestamp: 1621567932, + token_prices: vec![ + TokenPrice { + token: String::from("TESLA"), + prices: vec![ + TokenAmount { + currency: String::from("USD"), + amount: 1 * COIN + } + ].into() + } + ].into() + } + )]; + + for (raw, expected_data) in fixtures { + let hex = hex::decode(raw).unwrap(); + let dftx = deserialize::(&hex[2..]).unwrap(); + assert!(std::matches!(dftx, DfTx::SetOracleData(_))); + + if let DfTx::SetOracleData(data) = dftx { + assert_eq!(data, expected_data); + } + } +} + +#[test] +#[test_dftx_serialization] +fn test_remove_oracle() { + let fixtures = [( + "6a254466547868061d35948925528b2025c4b84ea6f4899bab6efbcaf63776258186d7728424d1", + RemoveOracle { + oracle_id: "d1248472d78681257637f6cafb6eab9b89f4a64eb8c425208b52258994351d06" + .parse() + .unwrap(), + }, + )]; + + for (raw, expected_data) in fixtures { + let hex = hex::decode(raw).unwrap(); + let dftx = deserialize::(&hex[2..]).unwrap(); + assert!(std::matches!(dftx, DfTx::RemoveOracle(_))); + + if let DfTx::RemoveOracle(data) = dftx { + assert_eq!(data, expected_data); + } + } +} + +#[test] +#[test_dftx_serialization] +fn test_appoint_oracle() {} + +#[test] +#[test_dftx_serialization] +fn test_update_oracle() {} diff --git a/lib/ain-dftx/tests/pool.rs b/lib/ain-dftx/tests/pool.rs new file mode 100644 index 00000000000..d3cb10f2b2f --- /dev/null +++ b/lib/ain-dftx/tests/pool.rs @@ -0,0 +1,25 @@ +use ain_macros::test_dftx_serialization; + +#[test] +#[test_dftx_serialization] +fn test_pool_swap() {} + +#[test] +#[test_dftx_serialization] +fn test_composite_swap() {} + +#[test] +#[test_dftx_serialization] +fn test_pool_add_liquidity() {} + +#[test] +#[test_dftx_serialization] +fn test_pool_remove_liquidity() {} + +#[test] +#[test_dftx_serialization] +fn test_pool_create_pair() {} + +#[test] +#[test_dftx_serialization] +fn test_pool_update_pair() {} diff --git a/lib/ain-dftx/tests/token.rs b/lib/ain-dftx/tests/token.rs new file mode 100644 index 00000000000..4f23cb23f36 --- /dev/null +++ b/lib/ain-dftx/tests/token.rs @@ -0,0 +1,21 @@ +use ain_macros::test_dftx_serialization; + +#[test] +#[test_dftx_serialization] +fn test_token_mint() {} + +#[test] +#[test_dftx_serialization] +fn test_token_create() {} + +#[test] +#[test_dftx_serialization] +fn test_token_update() {} + +#[test] +#[test_dftx_serialization] +fn test_token_update_any() {} + +#[test] +#[test_dftx_serialization] +fn test_token_burn() {} diff --git a/lib/ain-dftx/tests/vault.rs b/lib/ain-dftx/tests/vault.rs new file mode 100644 index 00000000000..09252ed1466 --- /dev/null +++ b/lib/ain-dftx/tests/vault.rs @@ -0,0 +1,25 @@ +use ain_macros::test_dftx_serialization; + +#[test] +#[test_dftx_serialization] +fn test_create_vault() {} + +#[test] +#[test_dftx_serialization] +fn test_update_vault() {} + +#[test] +#[test_dftx_serialization] +fn test_deposit_to_vault() {} + +#[test] +#[test_dftx_serialization] +fn test_withdraw_from_vault() {} + +#[test] +#[test_dftx_serialization] +fn test_close_vault() {} + +#[test] +#[test_dftx_serialization] +fn test_place_auction_bid() {} diff --git a/lib/ain-macros/src/lib.rs b/lib/ain-macros/src/lib.rs index 5f8bf923646..d880dde9ac2 100644 --- a/lib/ain-macros/src/lib.rs +++ b/lib/ain-macros/src/lib.rs @@ -2,7 +2,9 @@ extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; -use syn::{parse_macro_input, Attribute, DeriveInput, ItemFn, LitStr, ReturnType, Type}; +use syn::{ + parse_macro_input, Attribute, Data, DeriveInput, Fields, ItemFn, LitStr, ReturnType, Type, +}; #[proc_macro_attribute] pub fn ffi_fallible(_attr: TokenStream, item: TokenStream) -> TokenStream { @@ -177,3 +179,71 @@ pub fn ocean_endpoint(_attr: TokenStream, item: TokenStream) -> TokenStream { TokenStream::from(expanded) } + +#[proc_macro_attribute] +pub fn test_dftx_serialization(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input_fn = parse_macro_input!(item as ItemFn); + let fn_name = &input_fn.sig.ident; + let test_name = fn_name.to_string().replace("_", ""); + + let path = format!("./tests/data/{}.txt", &test_name[4..].to_lowercase()); + + let fn_body = &input_fn.block; + + let output = quote! { + fn #fn_name() { + #fn_body + let s = std::fs::read_to_string(#path).unwrap(); + for line in s.lines() { + if line.starts_with("//") { + continue; + } + let l = line.split(' ').next().unwrap(); + let hex = &hex::decode(l).unwrap(); + + let offset = 1 + match hex[1] { + 0x4c => 2, + 0x4d => 3, + 0x4e => 4, + _ => 1, + }; + + let raw_tx = &hex[offset..]; + + let dftx = bitcoin::consensus::deserialize::(&raw_tx).unwrap(); + let ser = bitcoin::consensus::serialize::(&dftx); + assert_eq!(ser, raw_tx); + } + } + }; + + TokenStream::from(output) +} + +#[proc_macro_derive(ConsensusEncoding)] +pub fn consensus_encoding_derive(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let name = input.ident; + + let fields = if let Data::Struct(data) = input.data { + if let Fields::Named(fields) = data.fields { + fields + .named + .into_iter() + .map(|f| f.ident) + .collect::>() + } else { + Vec::new() + } + } else { + Vec::new() + }; + + let field_names = fields.iter().filter_map(|f| f.as_ref()).collect::>(); + + let expanded = quote! { + impl_consensus_encoding!(#name, #(#field_names),*); + }; + + TokenStream::from(expanded) +} diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index 8cbd797d0a9..b9f9888df78 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -20,7 +20,7 @@ serde.workspace = true serde_with.workspace = true thiserror.workspace = true hex.workspace = true -dftx-rs.workspace = true +ain-dftx.workspace = true bitcoin = { workspace = true, features = ["serde"] } tokio = { version = "1", features = ["full"] } serde_json = "1.0" diff --git a/lib/ain-ocean/src/indexer/auction.rs b/lib/ain-ocean/src/indexer/auction.rs index 2c460620147..d75c3e75b0f 100644 --- a/lib/ain-ocean/src/indexer/auction.rs +++ b/lib/ain-ocean/src/indexer/auction.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use dftx_rs::vault::PlaceAuctionBid; +use ain_dftx::vault::PlaceAuctionBid; use log::debug; use super::Context; diff --git a/lib/ain-ocean/src/indexer/masternode.rs b/lib/ain-ocean/src/indexer/masternode.rs index 950b0620535..cafe96d2345 100644 --- a/lib/ain-ocean/src/indexer/masternode.rs +++ b/lib/ain-ocean/src/indexer/masternode.rs @@ -1,7 +1,7 @@ use std::sync::Arc; +use ain_dftx::masternode::*; use bitcoin::{hashes::Hash, PubkeyHash, ScriptBuf, WPubkeyHash}; -use dftx_rs::masternode::*; use log::debug; use rust_decimal::{prelude::FromPrimitive, Decimal}; diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 05c3ee3089b..bb6ae3ba5c8 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -7,8 +7,8 @@ pub mod tx_result; use std::{sync::Arc, time::Instant}; +use ain_dftx::{deserialize, DfTx, Stack}; use defichain_rpc::json::blockchain::{Block, Transaction}; -use dftx_rs::{deserialize, DfTx, Stack}; use log::debug; use crate::{ diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index 48b25311060..c4cf0957a9d 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use dftx_rs::oracles::*; +use ain_dftx::oracles::*; use super::Context; use crate::{ diff --git a/lib/ain-ocean/src/indexer/pool.rs b/lib/ain-ocean/src/indexer/pool.rs index 8f933e73fe2..61599b8e4a9 100644 --- a/lib/ain-ocean/src/indexer/pool.rs +++ b/lib/ain-ocean/src/indexer/pool.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use dftx_rs::pool::*; +use ain_dftx::pool::*; use log::debug; use super::Context; diff --git a/lib/ain-ocean/src/model/tx_result.rs b/lib/ain-ocean/src/model/tx_result.rs index 435dba120a7..77d5c529db1 100644 --- a/lib/ain-ocean/src/model/tx_result.rs +++ b/lib/ain-ocean/src/model/tx_result.rs @@ -1,4 +1,4 @@ -use dftx_rs::custom_tx::CustomTxType; +use ain_dftx::custom_tx::CustomTxType; use serde::{Deserialize, Serialize}; #[repr(C)] diff --git a/lib/ain-rs-exports/Cargo.toml b/lib/ain-rs-exports/Cargo.toml index 1f6ab201780..4a6616e1df2 100644 --- a/lib/ain-rs-exports/Cargo.toml +++ b/lib/ain-rs-exports/Cargo.toml @@ -14,7 +14,7 @@ ain-evm = { path = "../ain-evm" } ain-grpc = { path = "../ain-grpc" } ain-ocean = { path = "../ain-ocean" } ain-contracts = { path = "../ain-contracts" } -ain-macros = { path = "../ain-macros" } +ain-macros.workspace = true ain-cpp-imports = { path = "../ain-cpp-imports" } ethereum.workspace = true From b7a951d32cf4169661ae34ebc6078eabd25f71ce Mon Sep 17 00:00:00 2001 From: jouzo Date: Fri, 23 Feb 2024 21:31:31 +0100 Subject: [PATCH 062/185] Restore clippy --- lib/Makefile.am | 4 +++ lib/ain-db/src/lib.rs | 3 +- lib/ain-dftx/src/lib.rs | 30 ------------------- lib/ain-evm/src/storage/db.rs | 2 +- lib/ain-grpc/build.rs | 2 ++ lib/ain-grpc/src/lib.rs | 2 +- lib/ain-macros/src/lib.rs | 4 +-- lib/ain-ocean/src/api/common.rs | 2 +- lib/ain-ocean/src/api/governance.rs | 2 +- lib/ain-ocean/src/api/path.rs | 6 ++-- lib/ain-ocean/src/api/response.rs | 2 +- .../src/api/stats/{stats.rs => cache.rs} | 29 +++++++++--------- lib/ain-ocean/src/api/stats/mod.rs | 8 ++--- lib/ain-ocean/src/api/stats/subsidy.rs | 1 + lib/ain-ocean/src/api/tokens.rs | 8 ++--- lib/ain-ocean/src/api/transactions.rs | 2 +- lib/ain-ocean/src/error.rs | 2 +- lib/ain-ocean/src/indexer/masternode.rs | 2 +- lib/ain-ocean/src/indexer/mod.rs | 4 +-- lib/ain-ocean/src/indexer/oracle.rs | 16 +++++----- lib/ain-ocean/src/indexer/pool.rs | 4 +-- lib/ain-ocean/src/indexer/transaction.rs | 2 +- lib/ain-ocean/src/model/script_activity.rs | 18 ----------- lib/ain-ocean/src/model/transaction_vin.rs | 6 ++-- lib/ain-ocean/src/repository/mod.rs | 9 +++--- .../repository/vault_auction_batch_history.rs | 22 +++++++------- lib/ain-ocean/src/storage/columns/mod.rs | 2 +- lib/ain-rs-exports/src/ocean.rs | 4 +-- 28 files changed, 75 insertions(+), 123 deletions(-) rename lib/ain-ocean/src/api/stats/{stats.rs => cache.rs} (93%) diff --git a/lib/Makefile.am b/lib/Makefile.am index 39e5255d6eb..917309aa17a 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -71,6 +71,10 @@ check: test: $(CARGO) test $(CARGO_MANIFEST_ARG) $(CARGO_EXTRA_ARGS) +.PHONY: clippy +clippy: + $(CARGO) clippy $(CARGO_MANIFEST_ARG) $(CARGO_EXTRA_ARGS) -- -Dwarnings + .PHONY: doc doc: $(CARGO) doc $(CARGO_MANIFEST_ARG) diff --git a/lib/ain-db/src/lib.rs b/lib/ain-db/src/lib.rs index 60d7ade7405..82318d63892 100644 --- a/lib/ain-db/src/lib.rs +++ b/lib/ain-db/src/lib.rs @@ -7,7 +7,6 @@ use std::{ }; use anyhow::format_err; -use bincode; use rocksdb::{ BlockBasedOptions, Cache, ColumnFamily, ColumnFamilyDescriptor, DBIterator, Direction, IteratorMode, Options, DB, @@ -51,7 +50,7 @@ pub struct Rocks(DB); impl Rocks { pub fn open(path: &PathBuf, cf_names: &[&'static str]) -> Result { let cf_descriptors = cf_names - .into_iter() + .iter() .map(|cf_name| ColumnFamilyDescriptor::new(*cf_name, Options::default())); let db_opts = get_db_options(); diff --git a/lib/ain-dftx/src/lib.rs b/lib/ain-dftx/src/lib.rs index 652674c5af3..8de5dbc801a 100644 --- a/lib/ain-dftx/src/lib.rs +++ b/lib/ain-dftx/src/lib.rs @@ -1,7 +1,6 @@ pub mod custom_tx; pub mod types; -use anyhow::format_err; pub use bitcoin::{ consensus::{deserialize, serialize}, Block, Transaction, TxIn, TxOut, @@ -9,33 +8,4 @@ pub use bitcoin::{ pub use crate::types::*; -const OP_PUSHDATA1: u8 = 0x4c; -const OP_PUSHDATA2: u8 = 0x4d; -const OP_PUSHDATA4: u8 = 0x4e; -const OP_RETURN: u8 = 0x6a; pub const COIN: i64 = 100_000_000; - -fn get_dftx_data(data: &[u8]) -> std::result::Result<&[u8], anyhow::Error> { - if data[0] != OP_RETURN { - return Err(format_err!("Should start with op return")); - } - validate_buffer_len(data[1], data[2..].len())?; - - Ok(&data[2..]) -} - -fn validate_buffer_len(v: u8, len: usize) -> std::result::Result<(), anyhow::Error> { - let marker = match len { - 0..=75 => len as u8, - 76..=255 => OP_PUSHDATA1, - 256..=65535 => OP_PUSHDATA2, - 65536..=16777215 => OP_PUSHDATA4, - _ => return Err(format_err!("OP_PUSHDATA buffer is larger than 16777215")), - }; - - if v != marker { - return Err(format_err!("OP_PUSHDATA is not between 0x01 or 0x4e")); - }; - - Ok(()) -} diff --git a/lib/ain-evm/src/storage/db.rs b/lib/ain-evm/src/storage/db.rs index a5977f87b7e..9308df4efbb 100644 --- a/lib/ain-evm/src/storage/db.rs +++ b/lib/ain-evm/src/storage/db.rs @@ -85,7 +85,7 @@ impl ColumnName for columns::BlockDeployedCodeHashes { const NAME: &'static str = BLOCK_DEPLOYED_CODES_CF; } -pub const COLUMN_NAMES: [&'static str; 8] = [ +pub const COLUMN_NAMES: [&str; 8] = [ columns::Blocks::NAME, columns::Transactions::NAME, columns::Receipts::NAME, diff --git a/lib/ain-grpc/build.rs b/lib/ain-grpc/build.rs index 2f7ed5f6445..878131905a3 100644 --- a/lib/ain-grpc/build.rs +++ b/lib/ain-grpc/build.rs @@ -266,6 +266,8 @@ fn compile_proto_and_generate_services( // There's no way to compile protos using custom generator in tonic, // so we're left with creating a prost config and using that for codegen. let mut config = Config::new(); + println!("protoc_include : {:?}", protoc_include); + println!("dir : {:?}", dir); config.protoc_arg("--experimental_allow_proto3_optional"); config.out_dir(out_dir); config.service_generator(Box::new(gen)); diff --git a/lib/ain-grpc/src/lib.rs b/lib/ain-grpc/src/lib.rs index 9c2ce3c16f6..105a5489ef9 100644 --- a/lib/ain-grpc/src/lib.rs +++ b/lib/ain-grpc/src/lib.rs @@ -130,7 +130,7 @@ pub async fn init_ocean_server(addr: String) -> Result<()> { .await?, ); - let ocean_router = ain_ocean::ocean_router(&*OCEAN_SERVICES, client).await?; + let ocean_router = ain_ocean::ocean_router(&OCEAN_SERVICES, client).await?; let server_handle = runtime.tokio_runtime.spawn(async move { if let Err(e) = axum::serve(listener, ocean_router).await { diff --git a/lib/ain-macros/src/lib.rs b/lib/ain-macros/src/lib.rs index d880dde9ac2..cc609eec038 100644 --- a/lib/ain-macros/src/lib.rs +++ b/lib/ain-macros/src/lib.rs @@ -115,7 +115,7 @@ pub fn repository_derive(input: TokenStream) -> TokenStream { Ok(self.col.delete(id)?) } - fn list<'a>(&'a self, from: Option<#key_type_ident>, dir: crate::storage::SortOrder) -> Result> + 'a>> + fn list<'a>(&'a self, from: Option<#key_type_ident>, dir: crate::storage::SortOrder) -> crate::repository::ListResult<#key_type_ident, #value_type_ident> { let it = self.col.iter(from, dir.into())?; Ok(Box::new(it)) @@ -184,7 +184,7 @@ pub fn ocean_endpoint(_attr: TokenStream, item: TokenStream) -> TokenStream { pub fn test_dftx_serialization(_attr: TokenStream, item: TokenStream) -> TokenStream { let input_fn = parse_macro_input!(item as ItemFn); let fn_name = &input_fn.sig.ident; - let test_name = fn_name.to_string().replace("_", ""); + let test_name = fn_name.to_string().replace('_', ""); let path = format!("./tests/data/{}.txt", &test_name[4..].to_lowercase()); diff --git a/lib/ain-ocean/src/api/common.rs b/lib/ain-ocean/src/api/common.rs index f1906e98f3a..915f0b0ac5b 100644 --- a/lib/ain-ocean/src/api/common.rs +++ b/lib/ain-ocean/src/api/common.rs @@ -62,7 +62,7 @@ pub fn find_token_balance(tokens: Vec, symbol: &str) -> Decimal { .iter() .find_map(|t| { t.ends_with(symbol) - .then(|| t.split("@").next().and_then(|v| v.parse::().ok())) + .then(|| t.split('@').next().and_then(|v| v.parse::().ok())) .flatten() }) .unwrap_or_default() diff --git a/lib/ain-ocean/src/api/governance.rs b/lib/ain-ocean/src/api/governance.rs index 9870ab347f4..35a4bbee022 100644 --- a/lib/ain-ocean/src/api/governance.rs +++ b/lib/ain-ocean/src/api/governance.rs @@ -103,7 +103,7 @@ async fn list_gov_proposal_votes( let len = votes.len(); Ok(ApiPagedResponse::of(votes, size, |_| { if let Some(next) = start { - return next + len; + next + len } else { len - 1 } diff --git a/lib/ain-ocean/src/api/path.rs b/lib/ain-ocean/src/api/path.rs index 3e288b8b67e..26142753f50 100644 --- a/lib/ain-ocean/src/api/path.rs +++ b/lib/ain-ocean/src/api/path.rs @@ -27,7 +27,7 @@ where let error = match rejection { PathRejection::FailedToDeserializePathParams(inner) => { let kind = inner.into_kind(); - let error = match &kind { + match &kind { ErrorKind::WrongNumberOfParameters { .. } => ApiError::new( StatusCode::BAD_REQUEST, kind.to_string(), @@ -79,9 +79,7 @@ where format!("Unhandled deserialization error: {kind}"), parts.uri.to_string(), ), - }; - - error + } } PathRejection::MissingPathParams(error) => ApiError::new( StatusCode::INTERNAL_SERVER_ERROR, diff --git a/lib/ain-ocean/src/api/response.rs b/lib/ain-ocean/src/api/response.rs index 76341239fcb..41bbc15db9b 100644 --- a/lib/ain-ocean/src/api/response.rs +++ b/lib/ain-ocean/src/api/response.rs @@ -86,7 +86,7 @@ impl ApiPagedResponse { } pub fn of(data: Vec, limit: usize, next_provider: impl Fn(&T) -> U) -> Self { - if data.len() == limit && data.len() > 0 && limit > 0 { + if data.len() == limit && !data.is_empty() && limit > 0 { let next = next_provider(&data[limit - 1]).to_string(); Self::next(data, Some(next)) } else { diff --git a/lib/ain-ocean/src/api/stats/stats.rs b/lib/ain-ocean/src/api/stats/cache.rs similarity index 93% rename from lib/ain-ocean/src/api/stats/stats.rs rename to lib/ain-ocean/src/api/stats/cache.rs index aa4e2f80d0a..8412dd035f7 100644 --- a/lib/ain-ocean/src/api/stats/stats.rs +++ b/lib/ain-ocean/src/api/stats/cache.rs @@ -2,8 +2,7 @@ use std::{collections::HashMap, sync::Arc}; use cached::proc_macro::cached; use defichain_rpc::{ - defichain_rpc_json::{poolpair::PoolPairPagination, token::TokenPagination}, - AccountRPC, Client, LoanRPC, PoolPairRPC, TokenRPC, + defichain_rpc_json::token::TokenPagination, AccountRPC, Client, LoanRPC, TokenRPC, }; use rust_decimal::{ prelude::{FromPrimitive, Zero}, @@ -120,7 +119,7 @@ lazy_static::lazy_static! { pub async fn get_burned_total(client: &Client) -> Result { let network = ain_cpp_imports::get_network(); let burn_address = BURN_ADDRESS.get(network.as_str()).unwrap(); - let mut tokens = client.get_account(&burn_address, None, Some(true)).await?; + let mut tokens = client.get_account(burn_address, None, Some(true)).await?; let burn_info = client.get_burn_info().await?; let utxo = Decimal::from_f64(burn_info.amount).ok_or(Error::DecimalError)?; @@ -271,18 +270,18 @@ pub struct Tvl { convert = r#"{ format!("tvl") }"# )] pub async fn get_tvl(ctx: &Arc) -> Result { - let mut dex = 0f64; - let pairs = ctx - .client - .list_pool_pairs( - Some(PoolPairPagination { - including_start: true, - start: 0, - limit: 1000, - }), - Some(true), - ) - .await; + // let mut dex = 0f64; + // let pairs = ctx + // .client + // .list_pool_pairs( + + // including_start: true, + // start: 0, + // limit: 1000, + // }), + // Some(true), + // ) + // .await; let loan = get_loan(&ctx.client).await?; diff --git a/lib/ain-ocean/src/api/stats/mod.rs b/lib/ain-ocean/src/api/stats/mod.rs index 6ad1690ebce..3d1cfa53a34 100644 --- a/lib/ain-ocean/src/api/stats/mod.rs +++ b/lib/ain-ocean/src/api/stats/mod.rs @@ -1,5 +1,5 @@ +mod cache; mod distribution; -mod stats; mod subsidy; use std::sync::Arc; @@ -15,15 +15,15 @@ use rust_decimal_macros::dec; use serde::{Deserialize, Serialize}; use self::{ - distribution::get_block_reward_distribution, - stats::{ + cache::{ get_burned, get_count, get_emission, get_loan, get_masternodes, get_tvl, Burned, Count, Emission, Loan, Masternodes, Tvl, }, + distribution::get_block_reward_distribution, }; use super::{response::Response, AppContext}; use crate::{ - api::stats::{stats::get_burned_total, subsidy::BLOCK_SUBSIDY}, + api::stats::{cache::get_burned_total, subsidy::BLOCK_SUBSIDY}, error::{ApiError, Error}, Result, }; diff --git a/lib/ain-ocean/src/api/stats/subsidy.rs b/lib/ain-ocean/src/api/stats/subsidy.rs index 57c3121351b..d958ca4e54c 100644 --- a/lib/ain-ocean/src/api/stats/subsidy.rs +++ b/lib/ain-ocean/src/api/stats/subsidy.rs @@ -17,6 +17,7 @@ pub struct CoinbaseSubsidyOptions { emission_reduction_interval: u64, } +#[allow(dead_code)] pub static MAIN_NET_COINBASE_SUBSIDY_OPTIONS: CoinbaseSubsidyOptions = CoinbaseSubsidyOptions { eunos_height: 894000, genesis_block_subsidy: 59100003000000000, diff --git a/lib/ain-ocean/src/api/tokens.rs b/lib/ain-ocean/src/api/tokens.rs index bb72529eb8b..dad83b2d29c 100644 --- a/lib/ain-ocean/src/api/tokens.rs +++ b/lib/ain-ocean/src/api/tokens.rs @@ -119,11 +119,9 @@ async fn get_token( ) -> Result>> { let mut v: TokenResult = ctx.client.call("gettoken", &[id.as_str().into()]).await?; - let res = if let Some(token) = v.0.remove(&id) { - Some(TokenData::from_with_id(id, token)) - } else { - None - }; + let res = + v.0.remove(&id) + .map(|token| TokenData::from_with_id(id, token)); Ok(Response::new(res)) } diff --git a/lib/ain-ocean/src/api/transactions.rs b/lib/ain-ocean/src/api/transactions.rs index b9b52aa92bf..a1a955be1d5 100644 --- a/lib/ain-ocean/src/api/transactions.rs +++ b/lib/ain-ocean/src/api/transactions.rs @@ -42,7 +42,7 @@ async fn get_vins( .list(None, SortOrder::Descending)? .take(query.size) .map(|item| { - let (txid, id) = item?; + let (txid, _) = item?; let b = ctx .services .transaction diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index c3fd95034ce..7a885c2f51b 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -116,7 +116,7 @@ impl Error { e if e.message.contains("Cannot find existing loan scheme") => { format!("{}", Error::NotFound(NotFoundKind::Scheme)) } - _ => format!("{}", e.message), + _ => e.message.to_string(), }, ) } diff --git a/lib/ain-ocean/src/indexer/masternode.rs b/lib/ain-ocean/src/indexer/masternode.rs index cafe96d2345..c147e3e2863 100644 --- a/lib/ain-ocean/src/indexer/masternode.rs +++ b/lib/ain-ocean/src/indexer/masternode.rs @@ -54,7 +54,7 @@ impl Index for CreateMasternode { .by_height .put(&(ctx.block.height, txid), &0)?; - index_stats(&self, services, ctx, collateral) + index_stats(self, services, ctx, collateral) } fn invalidate(&self, services: &Arc, ctx: &Context) -> Result<()> { diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index bb6ae3ba5c8..c668fd258dd 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -86,7 +86,7 @@ pub fn index_block(services: &Arc, block: Block) -> Resul DfTx::PlaceAuctionBid(data) => data.index(services, &ctx)?, _ => (), } - log_elapsed(start, &format!("Indexed dftx")); + log_elapsed(start, "Indexed dftx"); } } } @@ -126,6 +126,6 @@ pub fn index_block(services: &Arc, block: Block) -> Resul Ok(()) } -pub fn invalidate_block(block: Block) -> Result<()> { +pub fn invalidate_block(_block: Block) -> Result<()> { Ok(()) } diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index c4cf0957a9d..a2417a42304 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -9,41 +9,41 @@ use crate::{ }; impl Index for AppointOracle { - fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { + fn index(&self, _services: &Arc, _ctx: &Context) -> Result<()> { todo!() } - fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { + fn invalidate(&self, _services: &Arc, _context: &Context) -> Result<()> { todo!() } } impl Index for RemoveOracle { - fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { + fn index(&self, _services: &Arc, _ctx: &Context) -> Result<()> { todo!() } - fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { + fn invalidate(&self, _services: &Arc, _context: &Context) -> Result<()> { todo!() } } impl Index for UpdateOracle { - fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { + fn index(&self, _services: &Arc, _ctx: &Context) -> Result<()> { todo!() } - fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { + fn invalidate(&self, _services: &Arc, _context: &Context) -> Result<()> { todo!() } } impl Index for SetOracleData { - fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { + fn index(&self, _services: &Arc, _ctx: &Context) -> Result<()> { todo!() } - fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { + fn invalidate(&self, _services: &Arc, _context: &Context) -> Result<()> { todo!() } } diff --git a/lib/ain-ocean/src/indexer/pool.rs b/lib/ain-ocean/src/indexer/pool.rs index 61599b8e4a9..14238e8f76d 100644 --- a/lib/ain-ocean/src/indexer/pool.rs +++ b/lib/ain-ocean/src/indexer/pool.rs @@ -26,7 +26,7 @@ impl Index for PoolSwap { let swap = model::PoolSwap { id: format!("{}-{}", pool_id, txid), sort: format!("{}-{}", ctx.block.height, idx), - txid: txid, + txid, txno: idx, from_amount: self.from_amount, from_token_id: self.from_token_id.0, @@ -77,7 +77,7 @@ impl Index for CompositeSwap { let swap = model::PoolSwap { id: format!("{}-{}", pool_id, txid), sort: format!("{}-{}", ctx.block.height, ctx.tx_idx), - txid: txid, + txid, txno: ctx.tx_idx, from_amount: self.pool_swap.from_amount, from_token_id: self.pool_swap.from_token_id.0, diff --git a/lib/ain-ocean/src/indexer/transaction.rs b/lib/ain-ocean/src/indexer/transaction.rs index 5d99adf295d..edaef7d1aa2 100644 --- a/lib/ain-ocean/src/indexer/transaction.rs +++ b/lib/ain-ocean/src/indexer/transaction.rs @@ -28,7 +28,7 @@ pub fn index_transaction(services: &Arc, ctx: Context) -> Result<()> { // Index transaction vout for (vout_idx, vout) in ctx.tx.vout.into_iter().enumerate() { let tx_vout = TransactionVout { - txid: txid, + txid, n: vout_idx, value: vout.value, token_id: 0, diff --git a/lib/ain-ocean/src/model/script_activity.rs b/lib/ain-ocean/src/model/script_activity.rs index 16feb1bc1df..03aa22afb82 100644 --- a/lib/ain-ocean/src/model/script_activity.rs +++ b/lib/ain-ocean/src/model/script_activity.rs @@ -7,30 +7,12 @@ pub enum ScriptActivityType { Vout, } -impl ScriptActivityType { - pub fn as_str(&self) -> &'static str { - match self { - ScriptActivityType::Vin => "vin", - ScriptActivityType::Vout => "vout", - } - } -} - #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum ScriptActivityTypeHex { Vin, Vout, } -impl ScriptActivityTypeHex { - pub fn as_str(&self) -> &'static str { - match self { - ScriptActivityTypeHex::Vin => "00", - ScriptActivityTypeHex::Vout => "01", - } - } -} - #[derive(Debug, Serialize, Deserialize)] pub struct ScriptActivity { diff --git a/lib/ain-ocean/src/model/transaction_vin.rs b/lib/ain-ocean/src/model/transaction_vin.rs index 9ee25d4c85d..08acc9234e2 100644 --- a/lib/ain-ocean/src/model/transaction_vin.rs +++ b/lib/ain-ocean/src/model/transaction_vin.rs @@ -16,11 +16,11 @@ pub struct TransactionVin { } impl TransactionVin { - pub fn from_vin_and_txid(vin: Vin, txid: Txid, vouts: &Vec) -> Self { + pub fn from_vin_and_txid(vin: Vin, txid: Txid, vouts: &[TransactionVout]) -> Self { match vin { Vin::Coinbase(v) => Self { id: format!("{}00", txid), - txid: txid, + txid, coinbase: Some(v.coinbase), sequence: v.sequence, vout: None, @@ -37,7 +37,7 @@ impl TransactionVin { }); Self { id: format!("{}{}{:x}", txid, v.txid, v.vout), - txid: txid, + txid, sequence: v.sequence, vout, script: v.script_sig.hex, diff --git a/lib/ain-ocean/src/repository/mod.rs b/lib/ain-ocean/src/repository/mod.rs index 0ddf3600f25..a4fa5193c17 100644 --- a/lib/ain-ocean/src/repository/mod.rs +++ b/lib/ain-ocean/src/repository/mod.rs @@ -44,13 +44,12 @@ pub use transaction_vout::*; pub use tx_result::*; pub use vault_auction_batch_history::*; +pub type ListResult<'a, K, V> = + Result> + 'a>>; + pub trait RepositoryOps { fn get(&self, key: &K) -> Result>; fn put(&self, key: &K, masternode: &V) -> Result<()>; fn delete(&self, key: &K) -> Result<()>; - fn list<'a>( - &'a self, - from: Option, - dir: SortOrder, - ) -> Result> + 'a>>; + fn list(&self, from: Option, dir: SortOrder) -> ListResult; } diff --git a/lib/ain-ocean/src/repository/vault_auction_batch_history.rs b/lib/ain-ocean/src/repository/vault_auction_batch_history.rs index b429b7dc704..e6d1fca3194 100644 --- a/lib/ain-ocean/src/repository/vault_auction_batch_history.rs +++ b/lib/ain-ocean/src/repository/vault_auction_batch_history.rs @@ -6,7 +6,7 @@ use ain_macros::Repository; use super::RepositoryOps; use crate::{ model::{AuctionHistoryByHeightKey, AuctionHistoryKey, VaultAuctionBatchHistory}, - storage::{columns, ocean_store::OceanStore, SortOrder}, + storage::{columns, ocean_store::OceanStore}, Result, }; @@ -43,14 +43,14 @@ impl AuctionHistoryByHeightRepository { } impl AuctionHistoryByHeightRepository { - pub fn get_latest(&self) -> Result> { - match self.list(None, SortOrder::Descending)?.next() { - None => Ok(None), - Some(Ok((_, id))) => { - let col = self.store.column::(); - Ok(col.get(&id)?) - } - Some(Err(e)) => Err(e.into()), - } - } + // pub fn get_latest(&self) -> Result> { + // match self.list(None::Descending)?.next() { + // None => Ok(None), + // Some(Ok((_, id))) => { + // let col = self.store.column::(); + // Ok(col.get(&id)?) + // } + // Some(Err(e)) => Err(e.into()), + // } + // } } diff --git a/lib/ain-ocean/src/storage/columns/mod.rs b/lib/ain-ocean/src/storage/columns/mod.rs index d8d573889a6..76ad06047e6 100644 --- a/lib/ain-ocean/src/storage/columns/mod.rs +++ b/lib/ain-ocean/src/storage/columns/mod.rs @@ -43,7 +43,7 @@ pub use transaction_vout::*; pub use tx_result::*; pub use vault_auction_history::*; -pub const COLUMN_NAMES: [&'static str; 25] = [ +pub const COLUMN_NAMES: [&str; 25] = [ block::Block::NAME, block::BlockByHeight::NAME, masternode_stats::MasternodeStats::NAME, diff --git a/lib/ain-rs-exports/src/ocean.rs b/lib/ain-rs-exports/src/ocean.rs index 585326c6466..a1748ae8076 100644 --- a/lib/ain-rs-exports/src/ocean.rs +++ b/lib/ain-rs-exports/src/ocean.rs @@ -10,7 +10,7 @@ use crate::{ #[ffi_fallible] pub fn ocean_index_block(block_str: String) -> Result<()> { let block: Block = serde_json::from_str(&block_str)?; - ain_ocean::index_block(&*ain_ocean::SERVICES, block) + ain_ocean::index_block(&ain_ocean::SERVICES, block) } #[ffi_fallible] @@ -21,5 +21,5 @@ pub fn ocean_invalidate_block(block_str: String) -> Result<()> { #[ffi_fallible] fn ocean_try_set_tx_result(tx_type: u8, tx_hash: [u8; 32], result_ptr: usize) -> Result<()> { - ain_ocean::tx_result::index(&*ain_ocean::SERVICES, tx_type, tx_hash, result_ptr) + ain_ocean::tx_result::index(&ain_ocean::SERVICES, tx_type, tx_hash, result_ptr) } From a6188820f63d56ba973b1ae37cd5320e5f5b4c63 Mon Sep 17 00:00:00 2001 From: jouzo Date: Fri, 23 Feb 2024 22:56:19 +0100 Subject: [PATCH 063/185] Clippy --- lib/ain-dftx/tests/block.rs | 5 ++--- lib/ain-dftx/tests/oracles.rs | 2 +- lib/ain-macros/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/ain-dftx/tests/block.rs b/lib/ain-dftx/tests/block.rs index db3ced0ddd5..20f6b2cead2 100644 --- a/lib/ain-dftx/tests/block.rs +++ b/lib/ain-dftx/tests/block.rs @@ -2,12 +2,11 @@ use ain_dftx::{deserialize, Block, DfTx}; #[test] fn test_block() { - let path = format!("./tests/data/block.txt"); - let s = std::fs::read_to_string(&path).unwrap(); + let s = std::fs::read_to_string("./tests/data/block.txt").unwrap(); for line in s.lines() { let l = line.split(' ').next().unwrap(); - let hex = &hex::decode(l).unwrap(); + let hex = hex::decode(l).unwrap(); let block = deserialize::(&hex).unwrap(); for tx in block.txdata { diff --git a/lib/ain-dftx/tests/oracles.rs b/lib/ain-dftx/tests/oracles.rs index 4216bc715e9..24675696b61 100644 --- a/lib/ain-dftx/tests/oracles.rs +++ b/lib/ain-dftx/tests/oracles.rs @@ -24,7 +24,7 @@ fn test_set_oracle_data() { prices: vec![ TokenAmount { currency: String::from("USD"), - amount: 1 * COIN + amount: COIN } ].into() } diff --git a/lib/ain-macros/Cargo.toml b/lib/ain-macros/Cargo.toml index a218da36c8d..98b004c2df7 100644 --- a/lib/ain-macros/Cargo.toml +++ b/lib/ain-macros/Cargo.toml @@ -9,6 +9,6 @@ proc-macro = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -syn.workspace = true +syn = { workspace = true, default-features = false, features = ["proc-macro", "full", "derive"] } quote.workspace = true proc-macro2.workspace = true From 5af42b54261c790269df25da201daf14476e400d Mon Sep 17 00:00:00 2001 From: jouzo Date: Sat, 24 Feb 2024 10:47:09 +0100 Subject: [PATCH 064/185] Clippy tests --- lib/ain-ocean/src/api/response.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ain-ocean/src/api/response.rs b/lib/ain-ocean/src/api/response.rs index 41bbc15db9b..23f2eddc868 100644 --- a/lib/ain-ocean/src/api/response.rs +++ b/lib/ain-ocean/src/api/response.rs @@ -97,8 +97,9 @@ impl ApiPagedResponse { #[cfg(test)] mod tests { - use super::{ApiPage, ApiPagedResponse}; + use super::ApiPagedResponse; + #[allow(dead_code)] #[derive(Clone, Debug)] struct Item { id: String, From c05401969b39f04b97921ef9ed7c8866793df4b0 Mon Sep 17 00:00:00 2001 From: jouzo Date: Mon, 26 Feb 2024 08:33:32 +0100 Subject: [PATCH 065/185] Fix RepositoryOps trait arg names --- lib/ain-ocean/src/repository/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ain-ocean/src/repository/mod.rs b/lib/ain-ocean/src/repository/mod.rs index a4fa5193c17..522e5bc798c 100644 --- a/lib/ain-ocean/src/repository/mod.rs +++ b/lib/ain-ocean/src/repository/mod.rs @@ -49,7 +49,7 @@ pub type ListResult<'a, K, V> = pub trait RepositoryOps { fn get(&self, key: &K) -> Result>; - fn put(&self, key: &K, masternode: &V) -> Result<()>; + fn put(&self, key: &K, value: &V) -> Result<()>; fn delete(&self, key: &K) -> Result<()>; - fn list(&self, from: Option, dir: SortOrder) -> ListResult; + fn list(&self, from: Option, direction: SortOrder) -> ListResult; } From 42c7898705cea039ccbed9fd4e0167e563e025e7 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Mon, 26 Feb 2024 17:29:32 +0800 Subject: [PATCH 066/185] Fix: ocean api tx getvins (#2833) * typo * revert and mv 7e50b03 + 01abcc8 to dedicated resp struct * wip getvins * wip getvouts * Use Decimal for total_vout_value calc * fix getvins --------- Co-authored-by: jouzo --- lib/ain-ocean/src/api/block.rs | 52 +++++++++++++++++++-- lib/ain-ocean/src/api/transactions.rs | 59 ++++++++++++++---------- lib/ain-ocean/src/indexer/transaction.rs | 10 ++-- lib/ain-ocean/src/model/transaction.rs | 10 ++-- 4 files changed, 92 insertions(+), 39 deletions(-) diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 2504e2d8990..1badb22a67a 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -3,8 +3,10 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; use anyhow::format_err; use axum::{extract::Path, routing::get, Extension, Router}; -use bitcoin::BlockHash; -use serde::{Deserialize, Deserializer}; +use bitcoin::{BlockHash, Txid}; +use rust_decimal::Decimal; +use serde::{Deserialize, Deserializer, Serialize}; +use serde_with::serde_as; use super::{ query::{PaginationQuery, Query}, @@ -14,7 +16,7 @@ use super::{ use crate::{ api::common::Paginate, error::{ApiError, Error}, - model::{Block, Transaction}, + model::{Block, BlockContext, Transaction}, repository::RepositoryOps, storage::SortOrder, Result, @@ -41,6 +43,46 @@ impl<'de> Deserialize<'de> for HashOrHeight { } } +#[serde_as] +#[derive(Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct TransactionResponse { + pub id: Txid, + pub txid: Txid, + pub order: usize, // tx order + pub block: BlockContext, + pub hash: String, + pub version: u32, + pub size: u64, + pub v_size: u64, + pub weight: u64, + #[serde(with = "rust_decimal::serde::str")] + pub total_vout_value: Decimal, + pub lock_time: u64, + pub vin_count: usize, + pub vout_count: usize, +} + +impl From for TransactionResponse { + fn from(v: Transaction) -> Self { + TransactionResponse { + id: v.id, + txid: v.id, + order: v.order, + block: v.block, + hash: v.hash, + version: v.version, + size: v.size, + v_size: v.v_size, + weight: v.weight, + total_vout_value: v.total_vout_value, + lock_time: v.lock_time, + vin_count: v.vin_count, + vout_count: v.vout_count, + } + } +} + #[ocean_endpoint] async fn list_blocks( Query(query): Query, @@ -103,7 +145,7 @@ async fn get_transactions( Path(hash): Path, Query(query): Query, Extension(ctx): Extension>, -) -> Result> { +) -> Result> { let next = query.next.as_ref().map_or(Ok((hash, 0)), |q| { let height = q .parse::() @@ -130,7 +172,7 @@ async fn get_transactions( .get(&id)? .ok_or("Missing tx index")?; - Ok(tx) + Ok(tx.into()) }) .collect::>>()?; diff --git a/lib/ain-ocean/src/api/transactions.rs b/lib/ain-ocean/src/api/transactions.rs index a1a955be1d5..02b1569d138 100644 --- a/lib/ain-ocean/src/api/transactions.rs +++ b/lib/ain-ocean/src/api/transactions.rs @@ -7,6 +7,7 @@ use serde::Deserialize; use super::{path::Path, query::PaginationQuery, response::ApiPagedResponse, AppContext}; use crate::{ + api::common::Paginate, api::response::Response, error::ApiError, model::{Transaction, TransactionVin, TransactionVout}, @@ -32,65 +33,73 @@ async fn get_transaction( #[ocean_endpoint] async fn get_vins( + Path(TransactionId { id }): Path, Query(query): Query, Extension(ctx): Extension>, ) -> Result> { - let transaction_list = ctx + let next = query.next.clone().unwrap_or(format!("{}00", id)); + + let list = ctx .services .transaction .vin_by_id - .list(None, SortOrder::Descending)? - .take(query.size) + .list(Some(next), SortOrder::Descending)? + .paginate(&query) + .take_while(|item| match item { + Ok((_, vin)) => vin.txid == id, + _ => true, + }) .map(|item| { - let (txid, _) = item?; - let b = ctx + let (id, _) = item?; + let v = ctx .services .transaction .vin_by_id - .get(&txid)? - .ok_or("Missing block index")?; + .get(&id)? + .ok_or("Missing vin index")?; - Ok(b) + Ok(v) }) .collect::>>()?; - Ok(ApiPagedResponse::of( - transaction_list, - query.size, - |transaction_list| transaction_list.id.clone(), - )) + Ok(ApiPagedResponse::of(list, query.size, |each| { + each.id.clone() + })) } //get list of vout transaction, by passing id which contains txhash + vout_idx #[ocean_endpoint] async fn get_vouts( + Path(TransactionId { id }): Path, Query(query): Query, Extension(ctx): Extension>, ) -> Result> { - let transaction_list = ctx + let list = ctx .services .transaction .vout_by_id .list(None, SortOrder::Descending)? - .take(query.size) + .paginate(&query) + .take_while(|item| match item { + Ok((_, vout)) => vout.txid == id, + _ => true, + }) .map(|item| { - let (txid, _) = item?; - let b = ctx + let (id, _) = item?; + let v = ctx .services .transaction .vout_by_id - .get(&txid)? - .ok_or("Missing block index")?; + .get(&id)? + .ok_or("Missing vout index")?; - Ok(b) + Ok(v) }) .collect::>>()?; - Ok(ApiPagedResponse::of( - transaction_list, - query.size, - |transaction_list| transaction_list.txid.to_string(), - )) + Ok(ApiPagedResponse::of(list, query.size, |each| { + each.n.to_string() + })) } pub fn router(ctx: Arc) -> Router { diff --git a/lib/ain-ocean/src/indexer/transaction.rs b/lib/ain-ocean/src/indexer/transaction.rs index edaef7d1aa2..4254db82f81 100644 --- a/lib/ain-ocean/src/indexer/transaction.rs +++ b/lib/ain-ocean/src/indexer/transaction.rs @@ -3,9 +3,14 @@ use std::sync::Arc; use bitcoin::{hashes::Hash, Txid}; use defichain_rpc::json::blockchain::{Transaction, Vin}; use log::debug; +use rust_decimal::{ + prelude::{FromPrimitive, Zero}, + Decimal, +}; use super::Context; use crate::{ + error::Error, indexer::Result, model::{ Transaction as TransactionMapper, TransactionVin, TransactionVout, TransactionVoutScript, @@ -23,7 +28,7 @@ pub fn index_transaction(services: &Arc, ctx: Context) -> Result<()> { let vin_count = ctx.tx.vin.len(); let vout_count = ctx.tx.vout.len(); - let mut total_vout_value = 0f64; + let mut total_vout_value = Decimal::zero(); let mut vouts = Vec::with_capacity(vout_count); // Index transaction vout for (vout_idx, vout) in ctx.tx.vout.into_iter().enumerate() { @@ -42,7 +47,7 @@ pub fn index_transaction(services: &Arc, ctx: Context) -> Result<()> { .vout_by_id .put(&(txid, vout_idx), &tx_vout)?; - total_vout_value += vout.value; + total_vout_value += Decimal::from_f64(vout.value).ok_or(Error::DecimalError)?; vouts.push(tx_vout); } @@ -60,7 +65,6 @@ pub fn index_transaction(services: &Arc, ctx: Context) -> Result<()> { let tx = TransactionMapper { id: txid, - txid, order, hash: ctx.tx.hash.clone(), block: ctx.block.clone(), diff --git a/lib/ain-ocean/src/model/transaction.rs b/lib/ain-ocean/src/model/transaction.rs index bbe713b54e9..d9147a9a393 100644 --- a/lib/ain-ocean/src/model/transaction.rs +++ b/lib/ain-ocean/src/model/transaction.rs @@ -1,17 +1,15 @@ use bitcoin::{BlockHash, Txid}; +use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; -use serde_with::{serde_as, DisplayFromStr}; use super::BlockContext; pub type TransactionByBlockHashKey = (BlockHash, usize); -#[serde_as] #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Transaction { - pub id: Txid, // unique id of the transaction, same as the txid - pub txid: Txid, + pub id: Txid, pub order: usize, // tx order pub block: BlockContext, pub hash: String, @@ -19,8 +17,8 @@ pub struct Transaction { pub size: u64, pub v_size: u64, pub weight: u64, - #[serde_as(as = "DisplayFromStr")] - pub total_vout_value: f64, + #[serde(with = "rust_decimal::serde::str")] + pub total_vout_value: Decimal, pub lock_time: u64, pub vin_count: usize, pub vout_count: usize, From dbb21cc0df78b9aca0fff9362489eb316a32723a Mon Sep 17 00:00:00 2001 From: canonbrother Date: Tue, 27 Feb 2024 15:41:55 +0800 Subject: [PATCH 067/185] Ocean: Use custom axum path extractor (#2836) --- lib/ain-ocean/src/api/address.rs | 3 ++- lib/ain-ocean/src/api/block.rs | 3 ++- lib/ain-ocean/src/api/governance.rs | 3 ++- lib/ain-ocean/src/api/loan.rs | 3 ++- lib/ain-ocean/src/api/oracle.rs | 3 ++- lib/ain-ocean/src/api/prices.rs | 3 ++- lib/ain-ocean/src/api/rawtx.rs | 2 +- lib/ain-ocean/src/api/tokens.rs | 3 ++- 8 files changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/ain-ocean/src/api/address.rs b/lib/ain-ocean/src/api/address.rs index 9bce516afb3..7a9df60ef80 100644 --- a/lib/ain-ocean/src/api/address.rs +++ b/lib/ain-ocean/src/api/address.rs @@ -1,8 +1,9 @@ use std::sync::Arc; -use axum::{extract::Path, routing::get, Router}; +use axum::{routing::get, Router}; use defichain_rpc::{Client, RpcApi}; use serde::Deserialize; +use super::path::Path; #[derive(Deserialize)] struct Address { diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 1badb22a67a..2c83915e75b 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -2,13 +2,14 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; use anyhow::format_err; -use axum::{extract::Path, routing::get, Extension, Router}; +use axum::{routing::get, Extension, Router}; use bitcoin::{BlockHash, Txid}; use rust_decimal::Decimal; use serde::{Deserialize, Deserializer, Serialize}; use serde_with::serde_as; use super::{ + path::Path, query::{PaginationQuery, Query}, response::{ApiPagedResponse, Response}, AppContext, diff --git a/lib/ain-ocean/src/api/governance.rs b/lib/ain-ocean/src/api/governance.rs index 35a4bbee022..cbb78aba701 100644 --- a/lib/ain-ocean/src/api/governance.rs +++ b/lib/ain-ocean/src/api/governance.rs @@ -1,12 +1,13 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; -use axum::{extract::Path, routing::get, Extension, Router}; +use axum::{routing::get, Extension, Router}; use bitcoin::Txid; use defichain_rpc::{json::governance::*, GovernanceRPC}; use serde::Deserialize; use super::{ + path::Path, query::{PaginationQuery, Query}, response::{ApiPagedResponse, Response}, AppContext, diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index a820f328b64..174d0938003 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; -use axum::{extract::Path, routing::get, Extension, Router}; +use axum::{routing::get, Extension, Router}; use bitcoin::Txid; use defichain_rpc::{ defichain_rpc_json::{ @@ -17,6 +17,7 @@ use serde::Serialize; use super::{ cache::get_token_cached, common::Paginate, + path::Path, query::{PaginationQuery, Query}, response::{ApiPagedResponse, Response}, tokens::TokenData, diff --git a/lib/ain-ocean/src/api/oracle.rs b/lib/ain-ocean/src/api/oracle.rs index 95655d6f74e..19d8116e543 100644 --- a/lib/ain-ocean/src/api/oracle.rs +++ b/lib/ain-ocean/src/api/oracle.rs @@ -1,7 +1,8 @@ use std::sync::Arc; -use axum::{extract::Path, routing::get, Router}; +use axum::{routing::get, Router}; use defichain_rpc::{Client, RpcApi}; +use super::path::Path; async fn list_oracles() -> String { "List of oracles".to_string() diff --git a/lib/ain-ocean/src/api/prices.rs b/lib/ain-ocean/src/api/prices.rs index b38aaf43de4..d2b8b8132bd 100644 --- a/lib/ain-ocean/src/api/prices.rs +++ b/lib/ain-ocean/src/api/prices.rs @@ -1,8 +1,9 @@ use std::sync::Arc; -use axum::{extract::Path, routing::get, Router}; +use axum::{routing::get, Router}; use defichain_rpc::{Client, RpcApi}; use serde::Deserialize; +use super::path::Path; #[derive(Deserialize)] struct PriceKey { diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index 1902d46c2e8..d412441a689 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -1,11 +1,11 @@ use std::sync::Arc; use axum::{ - extract::Path, routing::{get, post}, Router, }; use defichain_rpc::{Client, RpcApi}; +use super::path::Path; async fn send_rawtx() -> String { "Sending raw transaction".to_string() diff --git a/lib/ain-ocean/src/api/tokens.rs b/lib/ain-ocean/src/api/tokens.rs index dad83b2d29c..f044095e577 100644 --- a/lib/ain-ocean/src/api/tokens.rs +++ b/lib/ain-ocean/src/api/tokens.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; -use axum::{extract::Path, routing::get, Extension, Router}; +use axum::{routing::get, Extension, Router}; use defichain_rpc::{ json::token::{TokenInfo, TokenResult}, RpcApi, @@ -11,6 +11,7 @@ use serde_json::json; use super::{ common::parse_display_symbol, + path::Path, query::{PaginationQuery, Query}, response::{ApiPagedResponse, Response}, AppContext, From 025640b71c515b9ddfcf2f74af7af9ffcdd04085 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Tue, 27 Feb 2024 11:38:15 +0100 Subject: [PATCH 068/185] Ocean: Cleanup data acess (#2837) --- lib/ain-macros/src/lib.rs | 5 +- lib/ain-ocean/src/api/block.rs | 59 +++++++------------ lib/ain-ocean/src/api/masternode.rs | 21 ++----- lib/ain-ocean/src/api/transactions.rs | 28 +++------ lib/ain-ocean/src/error.rs | 2 + lib/ain-ocean/src/repository/block.rs | 17 +++++- lib/ain-ocean/src/repository/masternode.rs | 15 ++++- lib/ain-ocean/src/repository/mod.rs | 20 +++++-- lib/ain-ocean/src/repository/transaction.rs | 25 +++++++- .../src/repository/transaction_vin.rs | 16 ++++- 10 files changed, 119 insertions(+), 89 deletions(-) diff --git a/lib/ain-macros/src/lib.rs b/lib/ain-macros/src/lib.rs index cc609eec038..9dd5437fc91 100644 --- a/lib/ain-macros/src/lib.rs +++ b/lib/ain-macros/src/lib.rs @@ -103,6 +103,8 @@ pub fn repository_derive(input: TokenStream) -> TokenStream { // Generate the implementation let expanded = quote! { impl RepositoryOps<#key_type_ident, #value_type_ident> for #name { + type ListItem = std::result::Result<(#key_type_ident, #value_type_ident), ain_db::DBError>; + fn get(&self, id: &#key_type_ident) -> Result> { Ok(self.col.get(id)?) } @@ -115,8 +117,7 @@ pub fn repository_derive(input: TokenStream) -> TokenStream { Ok(self.col.delete(id)?) } - fn list<'a>(&'a self, from: Option<#key_type_ident>, dir: crate::storage::SortOrder) -> crate::repository::ListResult<#key_type_ident, #value_type_ident> - { + fn list<'a>(&'a self, from: Option<#key_type_ident>, dir: crate::storage::SortOrder) -> Result + 'a>> { let it = self.col.iter(from, dir.into())?; Ok(Box::new(it)) } diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 2c83915e75b..7a6df07fee7 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -18,7 +18,9 @@ use crate::{ api::common::Paginate, error::{ApiError, Error}, model::{Block, BlockContext, Transaction}, - repository::RepositoryOps, + repository::{ + InitialKeyProvider, RepositoryOps, SecondaryIndex, TransactionByBlockHashRepository, + }, storage::SortOrder, Result, }; @@ -100,23 +102,11 @@ async fn list_blocks( }) .transpose()?; - let blocks = ctx - .services - .block - .by_height + let repository = &ctx.services.block.by_height; + let blocks = repository .list(next, SortOrder::Descending)? .paginate(&query) - .map(|item| { - let (_, id) = item?; - let b = ctx - .services - .block - .by_id - .get(&id)? - .ok_or("Missing block index")?; - - Ok(b) - }) + .map(|e| repository.retrieve_primary_value(e)) .collect::>>()?; Ok(ApiPagedResponse::of(blocks, query.size, |block| { @@ -147,34 +137,27 @@ async fn get_transactions( Query(query): Query, Extension(ctx): Extension>, ) -> Result> { - let next = query.next.as_ref().map_or(Ok((hash, 0)), |q| { - let height = q - .parse::() - .map_err(|_| format_err!("Invalid height"))?; - Ok::<(BlockHash, usize), Error>((hash, height)) - })?; - - let txs = ctx - .services - .transaction - .by_block_hash + let repository = &ctx.services.transaction.by_block_hash; + + let next = query.next.as_ref().map_or( + Ok(TransactionByBlockHashRepository::initial_key(hash)), + |q| { + let height = q + .parse::() + .map_err(|_| format_err!("Invalid height"))?; + Ok::<(BlockHash, usize), Error>((hash, height)) + }, + )?; + + let txs = repository .list(Some(next), SortOrder::Ascending)? .paginate(&query) .take_while(|item| match item { Ok(((h, _), _)) => h == &hash, _ => true, }) - .map(|item| { - let (_, id) = item?; - let tx = ctx - .services - .transaction - .by_id - .get(&id)? - .ok_or("Missing tx index")?; - - Ok(tx.into()) - }) + .map(|el| repository.retrieve_primary_value(el)) + .map(|v| v.map(TransactionResponse::from)) .collect::>>()?; Ok(ApiPagedResponse::of(txs, query.size, |tx| tx.order)) diff --git a/lib/ain-ocean/src/api/masternode.rs b/lib/ain-ocean/src/api/masternode.rs index 72c07ffbd49..24734ea5d1f 100644 --- a/lib/ain-ocean/src/api/masternode.rs +++ b/lib/ain-ocean/src/api/masternode.rs @@ -19,7 +19,7 @@ use crate::{ api::common::Paginate, error::{ApiError, Error, NotFoundKind}, model::Masternode, - repository::RepositoryOps, + repository::{RepositoryOps, SecondaryIndex}, storage::SortOrder, Result, }; @@ -105,6 +105,7 @@ async fn list_masternodes( Query(query): Query, Extension(ctx): Extension>, ) -> Result> { + let repository = &ctx.services.masternode.by_height; let next = query .next .as_ref() @@ -120,23 +121,11 @@ async fn list_masternodes( }) .transpose()?; - let masternodes = ctx - .services - .masternode - .by_height + let masternodes = repository .list(next, SortOrder::Descending)? .paginate(&query) - .map(|item| { - let ((_, id), _) = item?; - let mn = ctx - .services - .masternode - .by_id - .get(&id)? - .ok_or("Missing masternode index")?; - - Ok(mn.into()) - }) + .map(|el| repository.retrieve_primary_value(el)) + .map(|v| v.map(MasternodeData::from)) .collect::>>()?; Ok(ApiPagedResponse::of( diff --git a/lib/ain-ocean/src/api/transactions.rs b/lib/ain-ocean/src/api/transactions.rs index 02b1569d138..8c612d46ab5 100644 --- a/lib/ain-ocean/src/api/transactions.rs +++ b/lib/ain-ocean/src/api/transactions.rs @@ -7,11 +7,10 @@ use serde::Deserialize; use super::{path::Path, query::PaginationQuery, response::ApiPagedResponse, AppContext}; use crate::{ - api::common::Paginate, - api::response::Response, + api::{common::Paginate, response::Response}, error::ApiError, model::{Transaction, TransactionVin, TransactionVout}, - repository::RepositoryOps, + repository::{InitialKeyProvider, RepositoryOps, TransactionVinRepository}, storage::SortOrder, Result, }; @@ -37,7 +36,10 @@ async fn get_vins( Query(query): Query, Extension(ctx): Extension>, ) -> Result> { - let next = query.next.clone().unwrap_or(format!("{}00", id)); + let next = query + .next + .clone() + .unwrap_or(TransactionVinRepository::initial_key(id)); let list = ctx .services @@ -50,14 +52,7 @@ async fn get_vins( _ => true, }) .map(|item| { - let (id, _) = item?; - let v = ctx - .services - .transaction - .vin_by_id - .get(&id)? - .ok_or("Missing vin index")?; - + let (_, v) = item?; Ok(v) }) .collect::>>()?; @@ -85,14 +80,7 @@ async fn get_vouts( _ => true, }) .map(|item| { - let (id, _) = item?; - let v = ctx - .services - .transaction - .vout_by_id - .get(&id)? - .ok_or("Missing vout index")?; - + let (_, v) = item?; Ok(v) }) .collect::>>()?; diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 7a885c2f51b..64b640eb5da 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -44,6 +44,8 @@ pub enum Error { #[error("Unable to find {0:}")] NotFound(NotFoundKind), #[error("Decimal conversion error")] + SecondaryIndex, + #[error("Error fetching primary value")] DecimalError, #[error(transparent)] Other(#[from] anyhow::Error), diff --git a/lib/ain-ocean/src/repository/block.rs b/lib/ain-ocean/src/repository/block.rs index 6107ae6e7d7..bbe26505868 100644 --- a/lib/ain-ocean/src/repository/block.rs +++ b/lib/ain-ocean/src/repository/block.rs @@ -4,11 +4,11 @@ use ain_db::LedgerColumn; use ain_macros::Repository; use bitcoin::BlockHash; -use super::RepositoryOps; +use super::{RepositoryOps, SecondaryIndex}; use crate::{ model::Block, storage::{columns, ocean_store::OceanStore, SortOrder}, - Result, + Error, Result, }; #[derive(Repository)] @@ -55,3 +55,16 @@ impl BlockByHeightRepository { } } } + +impl SecondaryIndex for BlockByHeightRepository { + type Value = Block; + + fn retrieve_primary_value(&self, el: Self::ListItem) -> Result { + let (_, id) = el?; + + let col = self.store.column::(); + let tx = col.get(&id)?.ok_or(Error::SecondaryIndex)?; + + Ok(tx) + } +} diff --git a/lib/ain-ocean/src/repository/masternode.rs b/lib/ain-ocean/src/repository/masternode.rs index 13975bdbe91..42dbc3a7aa6 100644 --- a/lib/ain-ocean/src/repository/masternode.rs +++ b/lib/ain-ocean/src/repository/masternode.rs @@ -4,11 +4,11 @@ use ain_db::LedgerColumn; use ain_macros::Repository; use bitcoin::Txid; -use super::RepositoryOps; +use super::{RepositoryOps, SecondaryIndex}; use crate::{ model::Masternode, storage::{columns, ocean_store::OceanStore}, - Result, + Error, Result, }; #[derive(Repository)] @@ -44,3 +44,14 @@ impl MasternodeByHeightRepository { } } } + +impl SecondaryIndex for MasternodeByHeightRepository { + type Value = Masternode; + + fn retrieve_primary_value(&self, el: Self::ListItem) -> Result { + let ((_, id), _) = el?; + let col = self.store.column::(); + let tx = col.get(&id)?.ok_or(Error::SecondaryIndex)?; + Ok(tx) + } +} diff --git a/lib/ain-ocean/src/repository/mod.rs b/lib/ain-ocean/src/repository/mod.rs index 522e5bc798c..561ec673a4e 100644 --- a/lib/ain-ocean/src/repository/mod.rs +++ b/lib/ain-ocean/src/repository/mod.rs @@ -44,12 +44,24 @@ pub use transaction_vout::*; pub use tx_result::*; pub use vault_auction_batch_history::*; -pub type ListResult<'a, K, V> = - Result> + 'a>>; - pub trait RepositoryOps { + type ListItem; fn get(&self, key: &K) -> Result>; fn put(&self, key: &K, value: &V) -> Result<()>; fn delete(&self, key: &K) -> Result<()>; - fn list(&self, from: Option, direction: SortOrder) -> ListResult; + fn list<'a>( + &'a self, + from: Option, + direction: SortOrder, + ) -> Result + 'a>>; +} + +pub trait InitialKeyProvider: RepositoryOps { + type PartialKey; + fn initial_key(pk: Self::PartialKey) -> K; +} + +pub trait SecondaryIndex: RepositoryOps { + type Value; + fn retrieve_primary_value(&self, el: Self::ListItem) -> Result; } diff --git a/lib/ain-ocean/src/repository/transaction.rs b/lib/ain-ocean/src/repository/transaction.rs index 13582235394..51ad7295642 100644 --- a/lib/ain-ocean/src/repository/transaction.rs +++ b/lib/ain-ocean/src/repository/transaction.rs @@ -2,13 +2,13 @@ use std::sync::Arc; use ain_db::LedgerColumn; use ain_macros::Repository; -use bitcoin::Txid; +use bitcoin::{BlockHash, Txid}; -use super::RepositoryOps; +use super::{InitialKeyProvider, RepositoryOps, SecondaryIndex}; use crate::{ model::{Transaction, TransactionByBlockHashKey}, storage::{columns, ocean_store::OceanStore}, - Result, + Error, Result, }; #[derive(Repository)] @@ -42,3 +42,22 @@ impl TransactionByBlockHashRepository { } } } + +impl InitialKeyProvider for TransactionByBlockHashRepository { + type PartialKey = BlockHash; + + fn initial_key(pk: Self::PartialKey) -> TransactionByBlockHashKey { + (pk, 0) + } +} + +impl SecondaryIndex for TransactionByBlockHashRepository { + type Value = Transaction; + + fn retrieve_primary_value(&self, el: Self::ListItem) -> Result { + let (_, id) = el?; + let col = self.store.column::(); + let tx = col.get(&id)?.ok_or(Error::SecondaryIndex)?; + Ok(tx) + } +} diff --git a/lib/ain-ocean/src/repository/transaction_vin.rs b/lib/ain-ocean/src/repository/transaction_vin.rs index f1731ef135a..cb8e3552a88 100644 --- a/lib/ain-ocean/src/repository/transaction_vin.rs +++ b/lib/ain-ocean/src/repository/transaction_vin.rs @@ -2,11 +2,15 @@ use std::sync::Arc; use ain_db::LedgerColumn; use ain_macros::Repository; +use bitcoin::Txid; -use super::RepositoryOps; +use super::{InitialKeyProvider, RepositoryOps}; use crate::{ model::TransactionVin, - storage::{columns, ocean_store::OceanStore}, + storage::{ + columns::{self}, + ocean_store::OceanStore, + }, Result, }; @@ -25,3 +29,11 @@ impl TransactionVinRepository { } } } + +impl InitialKeyProvider for TransactionVinRepository { + type PartialKey = Txid; + + fn initial_key(pk: Self::PartialKey) -> String { + format!("{}00", pk) + } +} From 95d7b3f234dba6342692f1f6655e93e9f70219a7 Mon Sep 17 00:00:00 2001 From: Niven Date: Wed, 28 Feb 2024 16:02:29 +0800 Subject: [PATCH 069/185] Disable cache on build-dev --- .github/workflows/build-dev.yaml | 34 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build-dev.yaml b/.github/workflows/build-dev.yaml index 182bd66f46e..c38ce54f767 100644 --- a/.github/workflows/build-dev.yaml +++ b/.github/workflows/build-dev.yaml @@ -52,23 +52,23 @@ jobs: - name: Setup user dependencies run: ./make.sh ci-setup-user-deps - - name: Restore cpp build cache - id: cpp-cache-restore - uses: actions/cache/restore@v3 - with: - path: | - ./build/depends - ./build/src - ~/.ccache - key: cpp-${{ env.TARGET }}-${{ env.BUILD_TYPE }} - - - name: Rust build cache - uses: Swatinem/rust-cache@v2 - id: rust-cache-restore - with: - workspaces: lib -> ../build/lib/target - save-if: ${{ github.ref == 'refs/heads/master' }} - shared-key: ${{ env.TARGET }} + # - name: Restore cpp build cache + # id: cpp-cache-restore + # uses: actions/cache/restore@v3 + # with: + # path: | + # ./build/depends + # ./build/src + # ~/.ccache + # key: cpp-${{ env.TARGET }}-${{ env.BUILD_TYPE }} + + # - name: Rust build cache + # uses: Swatinem/rust-cache@v2 + # id: rust-cache-restore + # with: + # workspaces: lib -> ../build/lib/target + # save-if: ${{ github.ref == 'refs/heads/master' }} + # shared-key: ${{ env.TARGET }} - name: Build and package run: ./make.sh release From 851d0c5462853820540a06a1e90b60e5578635ba Mon Sep 17 00:00:00 2001 From: jouzo Date: Wed, 28 Feb 2024 09:21:22 +0100 Subject: [PATCH 070/185] Cleanup ocean deps --- lib/Cargo.lock | 31 ++----------------------------- lib/ain-ocean/Cargo.toml | 13 +++++++------ 2 files changed, 9 insertions(+), 35 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 400f4e042b8..43c6854c997 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -245,7 +245,6 @@ dependencies = [ "axum 0.7.4", "bincode", "bitcoin", - "bitcoin_hashes 0.12.0", "cached", "chrono", "defichain-rpc", @@ -682,7 +681,7 @@ dependencies = [ "bech32", "bitcoin-internals", "bitcoin-io", - "bitcoin_hashes 0.13.0", + "bitcoin_hashes", "hex-conservative", "hex_lit", "secp256k1 0.28.2", @@ -703,21 +702,6 @@ name = "bitcoin-io" version = "0.1.0" source = "git+https://github.com/Jouzo/rust-bitcoin.git#af64fe422669e2d4fc24fca93561566e22cce1df" -[[package]] -name = "bitcoin-private" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" - -[[package]] -name = "bitcoin_hashes" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" -dependencies = [ - "bitcoin-private", -] - [[package]] name = "bitcoin_hashes" version = "0.13.0" @@ -3085,7 +3069,6 @@ dependencies = [ "glob", "libc", "libz-sys", - "lz4-sys", "zstd-sys", ] @@ -3194,16 +3177,6 @@ dependencies = [ "hashbrown 0.14.3", ] -[[package]] -name = "lz4-sys" -version = "1.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "mach" version = "0.3.2" @@ -4731,7 +4704,7 @@ version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" dependencies = [ - "bitcoin_hashes 0.13.0", + "bitcoin_hashes", "rand 0.8.5", "secp256k1-sys 0.9.2", "serde", diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index b9f9888df78..6d8286f8d5b 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -22,17 +22,13 @@ thiserror.workspace = true hex.workspace = true ain-dftx.workspace = true bitcoin = { workspace = true, features = ["serde"] } -tokio = { version = "1", features = ["full"] } +tokio = { workspace = true, features = ["full"] } serde_json = "1.0" json = "0.12.4" futures = "0.3.29" jsonrpsee.workspace = true -rocksdb = "0.21.0" -tempdir = "0.3.7" -bitcoin_hashes = "0.12.0" -tempfile = "3.8.1" +rocksdb.workspace = true anyhow.workspace = true -chrono = "0.4.31" cached.workspace = true lazy_static.workspace = true bincode.workspace = true @@ -41,3 +37,8 @@ jsonrpc-async = "2.0.2" serde_urlencoded = "0.7" rust_decimal = { version = "1.34", features = ["serde", "serde-float", "serde-with-str"] } rust_decimal_macros = "1.34" + +[dev-dependencies] +tempdir.workspace = true +tempfile = "3.8.1" +chrono = "0.4.31" From 1c9b6a07b518e2c1768e16e9f2211e433dc03f43 Mon Sep 17 00:00:00 2001 From: Niven Date: Wed, 28 Feb 2024 16:46:37 +0800 Subject: [PATCH 071/185] Re-enable CI caching --- .github/workflows/build-dev.yaml | 34 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build-dev.yaml b/.github/workflows/build-dev.yaml index c38ce54f767..182bd66f46e 100644 --- a/.github/workflows/build-dev.yaml +++ b/.github/workflows/build-dev.yaml @@ -52,23 +52,23 @@ jobs: - name: Setup user dependencies run: ./make.sh ci-setup-user-deps - # - name: Restore cpp build cache - # id: cpp-cache-restore - # uses: actions/cache/restore@v3 - # with: - # path: | - # ./build/depends - # ./build/src - # ~/.ccache - # key: cpp-${{ env.TARGET }}-${{ env.BUILD_TYPE }} - - # - name: Rust build cache - # uses: Swatinem/rust-cache@v2 - # id: rust-cache-restore - # with: - # workspaces: lib -> ../build/lib/target - # save-if: ${{ github.ref == 'refs/heads/master' }} - # shared-key: ${{ env.TARGET }} + - name: Restore cpp build cache + id: cpp-cache-restore + uses: actions/cache/restore@v3 + with: + path: | + ./build/depends + ./build/src + ~/.ccache + key: cpp-${{ env.TARGET }}-${{ env.BUILD_TYPE }} + + - name: Rust build cache + uses: Swatinem/rust-cache@v2 + id: rust-cache-restore + with: + workspaces: lib -> ../build/lib/target + save-if: ${{ github.ref == 'refs/heads/master' }} + shared-key: ${{ env.TARGET }} - name: Build and package run: ./make.sh release From 3bd491d06631da37523cee4ced0b3d17d15b3eb7 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Fri, 1 Mar 2024 22:43:46 +0800 Subject: [PATCH 072/185] Fix: ocean api tx get vouts (#2834) * fix getvouts * fmt * refine query pattern * TransactionVoutKey * rm unuse --- lib/ain-ocean/src/api/transactions.rs | 4 ++- .../src/storage/columns/transaction_vout.rs | 25 ++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/ain-ocean/src/api/transactions.rs b/lib/ain-ocean/src/api/transactions.rs index 8c612d46ab5..87c3f5d97c1 100644 --- a/lib/ain-ocean/src/api/transactions.rs +++ b/lib/ain-ocean/src/api/transactions.rs @@ -69,11 +69,13 @@ async fn get_vouts( Query(query): Query, Extension(ctx): Extension>, ) -> Result> { + let next = query.next.as_deref().unwrap_or("0").parse::()?; + let list = ctx .services .transaction .vout_by_id - .list(None, SortOrder::Descending)? + .list(Some((id, next)), SortOrder::Descending)? .paginate(&query) .take_while(|item| match item { Ok((_, vout)) => vout.txid == id, diff --git a/lib/ain-ocean/src/storage/columns/transaction_vout.rs b/lib/ain-ocean/src/storage/columns/transaction_vout.rs index c79d29d91a9..741a5d1b19c 100644 --- a/lib/ain-ocean/src/storage/columns/transaction_vout.rs +++ b/lib/ain-ocean/src/storage/columns/transaction_vout.rs @@ -1,4 +1,6 @@ -use ain_db::{Column, ColumnName, TypedColumn}; +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, Txid}; use crate::model; #[derive(Debug)] @@ -10,6 +12,27 @@ impl ColumnName for TransactionVout { impl Column for TransactionVout { type Index = model::TransactionVoutKey; + + fn key(index: &Self::Index) -> Result, DBError> { + let (txid, txno) = index; + let mut vec = txid.as_byte_array().to_vec(); + vec.extend_from_slice(&txno.to_be_bytes()); + Ok(vec) + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + if raw_key.len() != 40 { + return Err(format_err!("length of the slice is not 40").into()); + } + let mut hash_array = [0u8; 32]; + hash_array.copy_from_slice(&raw_key[..32]); + let mut txno_array = [0u8; 8]; + txno_array.copy_from_slice(&raw_key[32..]); + + let txid = Txid::from_byte_array(hash_array); + let txno = usize::from_be_bytes(txno_array); + Ok((txid, txno)) + } } impl TypedColumn for TransactionVout { From 246b26f93923644ae8f92625e2f12f0b1aeba6bc Mon Sep 17 00:00:00 2001 From: jouzo Date: Mon, 4 Mar 2024 14:36:05 +0100 Subject: [PATCH 073/185] Set MACOSX_DEPLOYMENT_TARGET in macos cross compile --- .github/workflows/build-dev.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-dev.yaml b/.github/workflows/build-dev.yaml index 182bd66f46e..2700ca9a685 100644 --- a/.github/workflows/build-dev.yaml +++ b/.github/workflows/build-dev.yaml @@ -18,8 +18,8 @@ concurrency: env: BUILD_VERSION: latest # Computed DOCKER_HUB_USER: defi - # Note: We do not use debug build on CI for dev as well, since debug builds - # take 5x the amount of space and run the GitHub CI workers out of space. + # Note: We do not use debug build on CI for dev as well, since debug builds + # take 5x the amount of space and run the GitHub CI workers out of space. # make.sh still defaults to debug for local builds MAKE_DEBUG: 0 GIT_VERSION: 1 @@ -38,6 +38,7 @@ jobs: image: ${{ matrix.container }} env: TARGET: ${{matrix.target}} + MACOSX_DEPLOYMENT_TARGET: 10.14 steps: - uses: actions/checkout@v4 @@ -115,7 +116,7 @@ jobs: with: name: defichain-${{ env.BUILD_VERSION }}-${{ env.TARGET }} path: ./build/ - + - name: Unpack binaries run: tar -xvzf ./build/defichain-${{ env.BUILD_VERSION }}-${{ env.TARGET }}.${{ env.PKG_TYPE }} -C ./build/ From 700d2351facfa88e635c9f94702bbe8aa82b94b8 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Tue, 5 Mar 2024 08:59:24 +0100 Subject: [PATCH 074/185] Ocean cli (#2844) --- lib/Cargo.lock | 425 ++++++++++++++--------- lib/ain-db/src/lib.rs | 6 +- lib/ain-evm/src/storage/block_store.rs | 2 +- lib/ain-grpc/src/lib.rs | 3 +- lib/ain-ocean/Cargo.toml | 3 + lib/ain-ocean/src/api/mod.rs | 12 +- lib/ain-ocean/src/api/stats/cache.rs | 12 +- lib/ain-ocean/src/api/stats/mod.rs | 2 +- lib/ain-ocean/src/bin/cli.rs | 111 ++++++ lib/ain-ocean/src/indexer/auction.rs | 4 +- lib/ain-ocean/src/indexer/masternode.rs | 8 +- lib/ain-ocean/src/indexer/mod.rs | 4 +- lib/ain-ocean/src/indexer/oracle.rs | 8 +- lib/ain-ocean/src/indexer/pool.rs | 25 +- lib/ain-ocean/src/indexer/transaction.rs | 2 +- lib/ain-ocean/src/storage/ocean_store.rs | 2 +- 16 files changed, 435 insertions(+), 194 deletions(-) create mode 100644 lib/ain-ocean/src/bin/cli.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 43c6854c997..feba350049a 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.9" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "getrandom 0.2.12", @@ -216,7 +216,7 @@ dependencies = [ "serde_json", "serde_with", "sha3", - "syn 2.0.50", + "syn 2.0.52", "tokio", "tonic", "tonic-build", @@ -230,7 +230,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -247,7 +247,9 @@ dependencies = [ "bitcoin", "cached", "chrono", + "clap 4.5.1", "defichain-rpc", + "env_logger", "futures", "hex", "hyper 0.14.28", @@ -257,6 +259,7 @@ dependencies = [ "keccak-hash", "lazy_static", "log", + "num_cpus", "rocksdb", "rust_decimal", "rust_decimal_macros", @@ -339,6 +342,54 @@ dependencies = [ "winapi", ] +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "anyhow" version = "1.0.80" @@ -411,7 +462,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -427,13 +478,13 @@ dependencies = [ [[package]] name = "auto_impl" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "823b8bb275161044e2ac7a25879cb3e2480cb403e3943022c7c769c599b756aa" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -552,7 +603,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -655,7 +706,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -816,7 +867,7 @@ dependencies = [ "proc-macro-crate 2.0.2", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", "syn_derive", ] @@ -861,9 +912,9 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bstr" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", "serde", @@ -957,7 +1008,7 @@ version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "355face540df58778b96814c48abb3c2ed67c4878a8087ab1819c1fedeec505f" dependencies = [ - "ahash 0.8.9", + "ahash 0.8.11", "async-trait", "cached_proc_macro", "cached_proc_macro_types", @@ -989,10 +1040,11 @@ checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" [[package]] name = "cc" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730" +checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723" dependencies = [ + "jobserver", "libc", ] @@ -1029,7 +1081,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.3", + "windows-targets 0.52.4", ] [[package]] @@ -1068,6 +1120,46 @@ dependencies = [ "vec_map", ] +[[package]] +name = "clap" +version = "4.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim 0.11.0", +] + +[[package]] +name = "clap_derive" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -1078,11 +1170,17 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "const-hex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d59688ad0945eaf6b84cb44fedbe93484c81b48970e98f09db8a22832d7961" +checksum = "efbd12d49ab0eaf8193ba9175e45f56bbc2e4b27d57b8cfe62aa47942a46b9a9" dependencies = [ "cfg-if", "cpufeatures", @@ -1262,9 +1360,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.117" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c15f3b597018782655a05d417f28bac009f6eb60f4b6703eb818998c1aaa16a" +checksum = "2673ca5ae28334544ec2a6b18ebe666c42a2650abfb48abbd532ed409a44be2b" dependencies = [ "cc", "cxxbridge-flags", @@ -1274,9 +1372,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.117" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81699747d109bba60bd6f87e7cb24b626824b8427b32f199b95c7faa06ee3dc9" +checksum = "9df46fe0eb43066a332586114174c449a62c25689f85a08f28fdcc8e12c380b9" dependencies = [ "cc", "codespan-reporting", @@ -1284,36 +1382,36 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] name = "cxx-gen" -version = "0.7.117" +version = "0.7.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b629c0d006c7e44c1444dd17d18a458c9390d32276b758ac7abd21a75c99b0" +checksum = "a94f02b4e45d7d00ecabff7635833f71c786576067b3d4158c8bef65d0a8e38b" dependencies = [ "codespan-reporting", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] name = "cxxbridge-flags" -version = "1.0.117" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a7eb4c4fd18505f5a935f9c2ee77780350dcdb56da7cd037634e806141c5c43" +checksum = "886acf875df67811c11cd015506b3392b9e1820b1627af1a6f4e93ccdfc74d11" [[package]] name = "cxxbridge-macro" -version = "1.0.117" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d914fcc6452d133236ee067a9538be25ba6a644a450e1a6c617da84bf029854" +checksum = "1d151cc139c3080e07f448f93a1284577ab2283d2a44acd902c6fba9ec20b6de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -1328,12 +1426,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.7" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a5d17510e4a1a87f323de70b7b1eaac1ee0e37866c6720b2d279452d0edf389" +checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" dependencies = [ - "darling_core 0.20.7", - "darling_macro 0.20.7", + "darling_core 0.20.8", + "darling_macro 0.20.8", ] [[package]] @@ -1352,16 +1450,16 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.7" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a98eea36a7ff910fa751413d0895551143a8ea41d695d9798ec7d665df7f7f5e" +checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -1377,19 +1475,19 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.7" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6a366a3f90c5d59a4b91169775f88e52e8f71a0e7804cc98a8db2932cf4ed57" +checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ - "darling_core 0.20.7", + "darling_core 0.20.8", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] name = "defichain-rpc" version = "0.18.0" -source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#b69ac6600113d7869b1311381237de0b41debddc" +source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#fab7f5f9d38fe225b072087d621e8f0bf11706de" dependencies = [ "async-trait", "defichain-rpc-json", @@ -1402,7 +1500,7 @@ dependencies = [ [[package]] name = "defichain-rpc-json" version = "0.18.0" -source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#b69ac6600113d7869b1311381237de0b41debddc" +source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#fab7f5f9d38fe225b072087d621e8f0bf11706de" dependencies = [ "bitcoin", "serde", @@ -1447,12 +1545,6 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6e854126756c496b8c81dec88f9a706b15b875c5849d4097a3854476b9fdf94" -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - [[package]] name = "digest" version = "0.8.1" @@ -1554,9 +1646,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "ecdsa" @@ -2048,7 +2140,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -2164,7 +2256,7 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.5", + "regex-automata 0.4.6", "regex-syntax 0.8.2", ] @@ -2191,7 +2283,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.11", - "indexmap 2.2.3", + "indexmap 2.2.5", "slab", "tokio", "tokio-util", @@ -2210,7 +2302,7 @@ dependencies = [ "futures-sink", "futures-util", "http 1.0.0", - "indexmap 2.2.3", + "indexmap 2.2.5", "slab", "tokio", "tokio-util", @@ -2253,7 +2345,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.9", + "ahash 0.8.11", ] [[package]] @@ -2262,7 +2354,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.9", + "ahash 0.8.11", "allocator-api2", ] @@ -2292,9 +2384,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -2628,9 +2720,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.3" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -2661,7 +2753,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.6", + "hermit-abi 0.3.9", "libc", "windows-sys 0.48.0", ] @@ -2688,7 +2780,7 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi 0.3.6", + "hermit-abi 0.3.9", "libc", "windows-sys 0.52.0", ] @@ -2717,6 +2809,15 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +[[package]] +name = "jobserver" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.68" @@ -2983,31 +3084,33 @@ dependencies = [ [[package]] name = "lalrpop" -version = "0.20.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" +checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" dependencies = [ "ascii-canvas", "bit-set", - "diff", "ena", - "is-terminal", - "itertools 0.10.5", + "itertools 0.11.0", "lalrpop-util", "petgraph", "regex", - "regex-syntax 0.7.5", + "regex-syntax 0.8.2", "string_cache", "term", "tiny-keccak", "unicode-xid", + "walkdir", ] [[package]] name = "lalrpop-util" -version = "0.20.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" +checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" +dependencies = [ + "regex-automata 0.4.6", +] [[package]] name = "lazy_static" @@ -3032,12 +3135,12 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libloading" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +checksum = "2caa5afb8bf9f3a2652760ce7d4f62d21c4d5a423e68466fca30df82f2330164" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-targets 0.52.4", ] [[package]] @@ -3164,15 +3267,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "lru" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2c024b41519440580066ba82aab04092b333e09066a5eb86c7c4890df31f22" +checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" dependencies = [ "hashbrown 0.14.3", ] @@ -3314,9 +3417,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -3478,7 +3581,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.6", + "hermit-abi 0.3.9", "libc", ] @@ -3500,7 +3603,7 @@ dependencies = [ "proc-macro-crate 2.0.2", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -3538,9 +3641,9 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "open-fastrlp" @@ -3692,7 +3795,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.2.3", + "indexmap 2.2.5", ] [[package]] @@ -3725,7 +3828,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -3763,7 +3866,7 @@ checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -3829,7 +3932,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" dependencies = [ "proc-macro2", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -4139,9 +4242,9 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" dependencies = [ "either", "rayon-core", @@ -4203,7 +4306,7 @@ checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -4214,7 +4317,7 @@ checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.5", + "regex-automata 0.4.6", "regex-syntax 0.8.2", ] @@ -4229,9 +4332,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", @@ -4244,12 +4347,6 @@ version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" -[[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - [[package]] name = "regex-syntax" version = "0.8.2" @@ -4624,7 +4721,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" dependencies = [ - "ahash 0.8.9", + "ahash 0.8.11", "cfg-if", "hashbrown 0.13.2", ] @@ -4801,7 +4898,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -4847,7 +4944,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.3", + "indexmap 2.2.5", "serde", "serde_derive", "serde_json", @@ -4861,10 +4958,10 @@ version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "865f9743393e638991566a8b7a479043c2c8da94a33e0a31f18214c9cae0a64d" dependencies = [ - "darling 0.20.7", + "darling 0.20.8", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -4877,7 +4974,7 @@ dependencies = [ "cfg-if", "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", ] [[package]] @@ -4913,7 +5010,7 @@ dependencies = [ "cfg-if", "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", ] [[package]] @@ -5019,12 +5116,12 @@ checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -5125,7 +5222,7 @@ checksum = "f12dae7cf6c1e825d13ffd4ce16bd9309db7c539929d0302b4443ed451a9f4e5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -5219,7 +5316,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -5283,7 +5380,7 @@ version = "23.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf63ea90ffb5d61048d8fb2fac669114dac198fc2739e913e615f0fd2c36c3e7" dependencies = [ - "ahash 0.8.9", + "ahash 0.8.11", "hash-db 0.16.0", "hashbrown 0.13.2", "lazy_static", @@ -5405,13 +5502,19 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + [[package]] name = "structopt" version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" dependencies = [ - "clap", + "clap 2.34.0", "lazy_static", "structopt-derive", ] @@ -5448,7 +5551,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -5516,9 +5619,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.50" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -5534,7 +5637,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -5588,9 +5691,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", @@ -5644,7 +5747,7 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -5777,7 +5880,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -5828,7 +5931,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.2.5", "toml_datetime", "winnow", ] @@ -5839,7 +5942,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.2.5", "toml_datetime", "winnow", ] @@ -5967,7 +6070,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -6162,6 +6265,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "uuid" version = "1.7.0" @@ -6268,9 +6377,9 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -6318,7 +6427,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", "wasm-bindgen-shared", ] @@ -6352,7 +6461,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6580,7 +6689,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.3", + "windows-targets 0.52.4", ] [[package]] @@ -6607,7 +6716,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.3", + "windows-targets 0.52.4", ] [[package]] @@ -6642,17 +6751,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.52.3", - "windows_aarch64_msvc 0.52.3", - "windows_i686_gnu 0.52.3", - "windows_i686_msvc 0.52.3", - "windows_x86_64_gnu 0.52.3", - "windows_x86_64_gnullvm 0.52.3", - "windows_x86_64_msvc 0.52.3", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -6669,9 +6778,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -6687,9 +6796,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -6705,9 +6814,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -6723,9 +6832,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -6741,9 +6850,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -6759,9 +6868,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -6777,9 +6886,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.3" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "winnow" @@ -6832,7 +6941,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -6852,7 +6961,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] diff --git a/lib/ain-db/src/lib.rs b/lib/ain-db/src/lib.rs index 82318d63892..c57f1c16d74 100644 --- a/lib/ain-db/src/lib.rs +++ b/lib/ain-db/src/lib.rs @@ -15,7 +15,7 @@ use serde::{de::DeserializeOwned, Serialize}; pub type Result = result::Result; -fn get_db_options() -> Options { +fn get_db_default_options() -> Options { let mut options = Options::default(); options.create_if_missing(true); options.create_missing_column_families(true); @@ -48,12 +48,12 @@ fn get_db_options() -> Options { pub struct Rocks(DB); impl Rocks { - pub fn open(path: &PathBuf, cf_names: &[&'static str]) -> Result { + pub fn open(path: &PathBuf, cf_names: &[&'static str], opts: Option) -> Result { let cf_descriptors = cf_names .iter() .map(|cf_name| ColumnFamilyDescriptor::new(*cf_name, Options::default())); - let db_opts = get_db_options(); + let db_opts = opts.unwrap_or_else(get_db_default_options); let db = DB::open_cf_descriptors(&db_opts, path, cf_descriptors)?; Ok(Self(db)) diff --git a/lib/ain-evm/src/storage/block_store.rs b/lib/ain-evm/src/storage/block_store.rs index 7dec5d2ec85..ebb02a0af64 100644 --- a/lib/ain-evm/src/storage/block_store.rs +++ b/lib/ain-evm/src/storage/block_store.rs @@ -26,7 +26,7 @@ impl BlockStore { pub fn new(path: &Path) -> Result { let path = path.join("indexes"); fs::create_dir_all(&path)?; - let backend = Arc::new(Rocks::open(&path, &COLUMN_NAMES)?); + let backend = Arc::new(Rocks::open(&path, &COLUMN_NAMES, None)?); Ok(Self(backend)) } diff --git a/lib/ain-grpc/src/lib.rs b/lib/ain-grpc/src/lib.rs index a7ae19e75c3..747913eb9b4 100644 --- a/lib/ain-grpc/src/lib.rs +++ b/lib/ain-grpc/src/lib.rs @@ -127,8 +127,9 @@ pub async fn init_ocean_server(addr: String) -> Result<()> { ) .await?, ); + let network = ain_cpp_imports::get_network(); - let ocean_router = ain_ocean::ocean_router(&OCEAN_SERVICES, client).await?; + let ocean_router = ain_ocean::ocean_router(&*OCEAN_SERVICES, client, network).await?; let server_handle = runtime.tokio_runtime.spawn(async move { if let Err(e) = axum::serve(listener, ocean_router).await { diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index 6d8286f8d5b..c0a19ef07ef 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -35,8 +35,11 @@ bincode.workspace = true defichain-rpc.workspace = true jsonrpc-async = "2.0.2" serde_urlencoded = "0.7" +env_logger.workspace = true rust_decimal = { version = "1.34", features = ["serde", "serde-float", "serde-with-str"] } rust_decimal_macros = "1.34" +clap = { version = "4.5.0", features = ["derive"] } +num_cpus.workspace = true [dev-dependencies] tempdir.workspace = true diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index a0cf7f9e3b6..13f6ea62bc7 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -52,18 +52,22 @@ async fn not_found(req: Request) -> impl IntoResponse { pub struct AppContext { services: Arc, client: Arc, + network: String, // TODO Proper handling of network } -pub async fn ocean_router(services: &Arc, client: Arc) -> Result { +pub async fn ocean_router( + services: &Arc, + client: Arc, + network: String, +) -> Result { let context = Arc::new(AppContext { client, services: services.clone(), + network, }); - let network = ain_cpp_imports::get_network(); - Ok(Router::new().nest( - format!("/v0/{network}").as_str(), + format!("/v0/{}", context.network).as_str(), Router::new() // .nest("/address/", address::router(Arc::clone(&context))) .nest("/governance", governance::router(Arc::clone(&context))) diff --git a/lib/ain-ocean/src/api/stats/cache.rs b/lib/ain-ocean/src/api/stats/cache.rs index 8412dd035f7..a8ff7e4520e 100644 --- a/lib/ain-ocean/src/api/stats/cache.rs +++ b/lib/ain-ocean/src/api/stats/cache.rs @@ -116,11 +116,13 @@ lazy_static::lazy_static! { key = "String", convert = r#"{ format!("burned_total") }"# )] -pub async fn get_burned_total(client: &Client) -> Result { - let network = ain_cpp_imports::get_network(); - let burn_address = BURN_ADDRESS.get(network.as_str()).unwrap(); - let mut tokens = client.get_account(burn_address, None, Some(true)).await?; - let burn_info = client.get_burn_info().await?; +pub async fn get_burned_total(ctx: &AppContext) -> Result { + let burn_address = BURN_ADDRESS.get(ctx.network.as_str()).unwrap(); + let mut tokens = ctx + .client + .get_account(&burn_address, None, Some(true)) + .await?; + let burn_info = ctx.client.get_burn_info().await?; let utxo = Decimal::from_f64(burn_info.amount).ok_or(Error::DecimalError)?; let emission = Decimal::from_f64(burn_info.emissionburn).ok_or(Error::DecimalError)?; diff --git a/lib/ain-ocean/src/api/stats/mod.rs b/lib/ain-ocean/src/api/stats/mod.rs index 3d1cfa53a34..efcc3ed1689 100644 --- a/lib/ain-ocean/src/api/stats/mod.rs +++ b/lib/ain-ocean/src/api/stats/mod.rs @@ -164,7 +164,7 @@ async fn get_supply(Extension(ctx): Extension>) -> Result Result<()> { + env_logger::init(); + let cli = Cli::parse(); + + let store = Arc::new(OceanStore::new(&cli.datadir)?); + + let client = Arc::new(Client::new(&cli.rpcaddress, Auth::UserPass(cli.user, cli.pass)).await?); + + let services = Arc::new(Services::new(store)); + + let listener = tokio::net::TcpListener::bind(cli.bind_address).await?; + let ocean_router = ain_ocean::ocean_router(&services, client.clone(), cli.network).await?; + tokio::spawn(async move { axum::serve(listener, ocean_router).await.unwrap() }); + + let mut indexed_block = 0; + let mut next_block_hash = None; + let mut start_time = Instant::now(); + + loop { + let highest_block = services + .block + .by_height + .get_highest()? + .map_or(0, |b| b.height); + + let new_height = highest_block + 1; + let hash = if let Some(hash) = next_block_hash { + hash + } else { + match client.get_block_hash(new_height).await { + Ok(hash) => hash, + Err(e) => { + println!("e : {:?}", e); + // Out of range, sleep for 10s + std::thread::sleep(std::time::Duration::from_millis(10000)); + continue; + } + } + }; + + let block = match client.get_block(hash, 2).await { + Err(e) => { + println!("e : {:?}", e); + // Error getting block, sleep for 30s + std::thread::sleep(std::time::Duration::from_millis(30000)); + continue; + } + Ok(GetBlockResult::Full(block)) => block, + Ok(_) => return Err("Error deserializing block".into()), + }; + + next_block_hash = block.nextblockhash; + match index_block(&services, block) { + Ok(_) => (), + Err(e) => { + return Err(e); + } + } + + indexed_block += 1; + if indexed_block % cli.bench_frequency == 0 { + let elapsed = start_time.elapsed(); + println!("Processed {} blocks in {:?}", cli.bench_frequency, elapsed); + start_time = Instant::now(); + } + } + + Ok(()) +} diff --git a/lib/ain-ocean/src/indexer/auction.rs b/lib/ain-ocean/src/indexer/auction.rs index d75c3e75b0f..5c8683764c2 100644 --- a/lib/ain-ocean/src/indexer/auction.rs +++ b/lib/ain-ocean/src/indexer/auction.rs @@ -12,7 +12,7 @@ use crate::{ }; impl Index for PlaceAuctionBid { - fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { + fn index(self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[PlaceAuctionBid] Indexing..."); let auction = VaultAuctionBatchHistory { @@ -21,7 +21,7 @@ impl Index for PlaceAuctionBid { sort: format!("{}-{}", ctx.block.height, ctx.tx_idx), vault_id: self.vault_id, index: ctx.tx_idx, - from: self.from.clone(), + from: self.from, amount: self.token_amount.amount, token_id: self.token_amount.token.0, block: ctx.block.clone(), diff --git a/lib/ain-ocean/src/indexer/masternode.rs b/lib/ain-ocean/src/indexer/masternode.rs index c147e3e2863..1b3322adfc5 100644 --- a/lib/ain-ocean/src/indexer/masternode.rs +++ b/lib/ain-ocean/src/indexer/masternode.rs @@ -25,7 +25,7 @@ fn get_operator_script(hash: &PubkeyHash, r#type: u8) -> Result { } impl Index for CreateMasternode { - fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { + fn index(self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[CreateMasternode] Indexing..."); let txid = ctx.tx.txid; let Some(ref addresses) = ctx.tx.vout[1].script_pub_key.addresses else { @@ -54,7 +54,7 @@ impl Index for CreateMasternode { .by_height .put(&(ctx.block.height, txid), &0)?; - index_stats(self, services, ctx, collateral) + index_stats(&self, services, ctx, collateral) } fn invalidate(&self, services: &Arc, ctx: &Context) -> Result<()> { @@ -103,7 +103,7 @@ fn index_stats( } impl Index for UpdateMasternode { - fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { + fn index(self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[UpdateMasternode] Indexing..."); if let Some(mut mn) = services.masternode.by_id.get(&self.node_id)? { mn.history.push(HistoryItem { @@ -149,7 +149,7 @@ impl Index for UpdateMasternode { } impl Index for ResignMasternode { - fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { + fn index(self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[ResignMasternode] Indexing..."); if let Some(mn) = services.masternode.by_id.get(&self.node_id)? { services.masternode.by_id.put( diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index c668fd258dd..b14410c4e7c 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -19,7 +19,7 @@ use crate::{ }; pub(crate) trait Index { - fn index(&self, services: &Arc, ctx: &Context) -> Result<()>; + fn index(self, services: &Arc, ctx: &Context) -> Result<()>; fn invalidate(&self, services: &Arc, ctx: &Context) -> Result<()>; } @@ -73,7 +73,7 @@ pub fn index_block(services: &Arc, block: Block) -> Resul } Err(e) => return Err(e.into()), Ok(Stack { dftx, .. }) => { - match &dftx { + match dftx { DfTx::CreateMasternode(data) => data.index(services, &ctx)?, DfTx::UpdateMasternode(data) => data.index(services, &ctx)?, DfTx::ResignMasternode(data) => data.index(services, &ctx)?, diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index a2417a42304..45ba1e87c25 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -9,7 +9,7 @@ use crate::{ }; impl Index for AppointOracle { - fn index(&self, _services: &Arc, _ctx: &Context) -> Result<()> { + fn index(self, _services: &Arc, _ctx: &Context) -> Result<()> { todo!() } @@ -19,7 +19,7 @@ impl Index for AppointOracle { } impl Index for RemoveOracle { - fn index(&self, _services: &Arc, _ctx: &Context) -> Result<()> { + fn index(self, _services: &Arc, _ctx: &Context) -> Result<()> { todo!() } @@ -29,7 +29,7 @@ impl Index for RemoveOracle { } impl Index for UpdateOracle { - fn index(&self, _services: &Arc, _ctx: &Context) -> Result<()> { + fn index(self, _services: &Arc, _ctx: &Context) -> Result<()> { todo!() } @@ -39,7 +39,7 @@ impl Index for UpdateOracle { } impl Index for SetOracleData { - fn index(&self, _services: &Arc, _ctx: &Context) -> Result<()> { + fn index(self, _services: &Arc, _ctx: &Context) -> Result<()> { todo!() } diff --git a/lib/ain-ocean/src/indexer/pool.rs b/lib/ain-ocean/src/indexer/pool.rs index 14238e8f76d..e4e4ee4b3a9 100644 --- a/lib/ain-ocean/src/indexer/pool.rs +++ b/lib/ain-ocean/src/indexer/pool.rs @@ -1,5 +1,7 @@ use std::sync::Arc; +use anyhow::format_err; +use bitcoin::Address; use ain_dftx::pool::*; use log::debug; @@ -12,17 +14,22 @@ use crate::{ }; impl Index for PoolSwap { - fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { + fn index(self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[Poolswap] Indexing..."); let txid = ctx.tx.txid; let idx = ctx.tx_idx; let Some(TxResult::PoolSwap(PoolSwapResult { to_amount, pool_id })) = services.result.get(&txid)? else { + let address = Address::from_script(&self.to_script, bitcoin::Network::Bitcoin) + .map_err(|e| format_err!("Error getting address from script: {e}")); debug!("Missing swap result for {}", ctx.tx.txid.to_string()); return Err("Missing swap result".into()); }; + let from = self.from_script; + let to = self.to_script; + let swap = model::PoolSwap { id: format!("{}-{}", pool_id, txid), sort: format!("{}-{}", ctx.block.height, idx), @@ -33,8 +40,8 @@ impl Index for PoolSwap { to_token_id: self.to_token_id.0, to_amount, pool_id, - from: self.from_script.clone(), - to: self.to_script.clone(), + from, + to, block: ctx.block.clone(), }; debug!("swap : {:?}", swap); @@ -62,16 +69,21 @@ impl Index for PoolSwap { } impl Index for CompositeSwap { - fn index(&self, services: &Arc, ctx: &Context) -> Result<()> { + fn index(self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[CompositeSwap] Indexing..."); let txid = ctx.tx.txid; let Some(TxResult::PoolSwap(PoolSwapResult { to_amount, .. })) = services.result.get(&txid)? else { + let address = + Address::from_script(&self.pool_swap.to_script, bitcoin::Network::Bitcoin) + .map_err(|e| format_err!("Error getting address from script: {e}")); debug!("Missing swap result for {}", txid.to_string()); return Err("Missing swap result".into()); }; + let from = self.pool_swap.from_script; + let to = self.pool_swap.to_script; for pool in self.pools.as_ref() { let pool_id = pool.id.0 as u32; let swap = model::PoolSwap { @@ -84,11 +96,10 @@ impl Index for CompositeSwap { to_token_id: self.pool_swap.to_token_id.0, to_amount, pool_id, - from: self.pool_swap.from_script.clone(), - to: self.pool_swap.to_script.clone(), + from: from.clone(), + to: to.clone(), block: ctx.block.clone(), }; - debug!("swap : {:?}", swap); services .pool .by_id diff --git a/lib/ain-ocean/src/indexer/transaction.rs b/lib/ain-ocean/src/indexer/transaction.rs index 4254db82f81..b571c97a11c 100644 --- a/lib/ain-ocean/src/indexer/transaction.rs +++ b/lib/ain-ocean/src/indexer/transaction.rs @@ -66,7 +66,7 @@ pub fn index_transaction(services: &Arc, ctx: Context) -> Result<()> { let tx = TransactionMapper { id: txid, order, - hash: ctx.tx.hash.clone(), + hash: ctx.tx.hash, block: ctx.block.clone(), version: ctx.tx.version, size: ctx.tx.size, diff --git a/lib/ain-ocean/src/storage/ocean_store.rs b/lib/ain-ocean/src/storage/ocean_store.rs index 96eadf79516..e1f85a287d3 100644 --- a/lib/ain-ocean/src/storage/ocean_store.rs +++ b/lib/ain-ocean/src/storage/ocean_store.rs @@ -12,7 +12,7 @@ impl OceanStore { pub fn new(path: &Path) -> Result { let path = path.join("ocean"); fs::create_dir_all(&path)?; - let backend = Arc::new(Rocks::open(&path, &COLUMN_NAMES)?); + let backend = Arc::new(Rocks::open(&path, &COLUMN_NAMES, None)?); Ok(Self(backend)) } From dae2d1232a8ce1d0c9997e3ef1e017f0c9d87516 Mon Sep 17 00:00:00 2001 From: jouzo Date: Tue, 5 Mar 2024 09:50:04 +0100 Subject: [PATCH 075/185] Update rustc version to 1.76 --- doc/build-quick.md | 7 +++---- make.sh | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/doc/build-quick.md b/doc/build-quick.md index c8aac6cc287..bfc6b026aa6 100644 --- a/doc/build-quick.md +++ b/doc/build-quick.md @@ -1,6 +1,6 @@ # Quick build notes -DeFiChain is built with the same process as Bitcoin, but provides certain convenience steps to +DeFiChain is built with the same process as Bitcoin, but provides certain convenience steps to build it easily with the `./make.sh` file in the root directory. ``` @@ -89,7 +89,6 @@ an environment with correct arch and pre-requisites configured. (most pre-requisites can be installed with pkg-* commands). ``` - ## `TARGET` values ### Tier 1 @@ -145,7 +144,7 @@ but receives little to no testing. PYTHON_VENV_DIR=${PYTHON_VENV_DIR:-"${BUILD_DIR}/pyenv"} CLANG_DEFAULT_VERSION=${CLANG_DEFAULT_VERSION:-"15"} - RUST_DEFAULT_VERSION=${RUST_DEFAULT_VERSION:-"1.72"} + RUST_DEFAULT_VERSION=${RUST_DEFAULT_VERSION:-"1.76"} MAKE_DEBUG=${MAKE_DEBUG:-"1"} MAKE_USE_CLANG=${MAKE_USE_CLANG:-"$(get_default_use_clang)"} @@ -177,5 +176,5 @@ but receives little to no testing. Please read the `./make.sh` file for more details on the build helpers. [UNIX build process](./build-unix.md) should also have more info though using -`./make.sh` is recommended as it builds out-of-tree by default and supports +`./make.sh` is recommended as it builds out-of-tree by default and supports multiple targets. diff --git a/make.sh b/make.sh index 7ae297b2b95..6a0f1eda9fd 100755 --- a/make.sh +++ b/make.sh @@ -38,7 +38,7 @@ setup_vars() { PYTHON_VENV_DIR=${PYTHON_VENV_DIR:-"${BUILD_DIR}/pyenv"} CLANG_DEFAULT_VERSION=${CLANG_DEFAULT_VERSION:-"15"} - RUST_DEFAULT_VERSION=${RUST_DEFAULT_VERSION:-"1.72"} + RUST_DEFAULT_VERSION=${RUST_DEFAULT_VERSION:-"1.76"} MAKE_DEBUG=${MAKE_DEBUG:-"1"} MAKE_USE_CLANG=${MAKE_USE_CLANG:-"$(get_default_use_clang)"} From a95ceccd011bed46dac3021d97ece118b9f7276c Mon Sep 17 00:00:00 2001 From: jouzo Date: Tue, 5 Mar 2024 10:46:19 +0100 Subject: [PATCH 076/185] Add todo fallback poolswap comment --- lib/ain-ocean/src/indexer/pool.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/ain-ocean/src/indexer/pool.rs b/lib/ain-ocean/src/indexer/pool.rs index e4e4ee4b3a9..e9f8bd96f41 100644 --- a/lib/ain-ocean/src/indexer/pool.rs +++ b/lib/ain-ocean/src/indexer/pool.rs @@ -21,8 +21,9 @@ impl Index for PoolSwap { let Some(TxResult::PoolSwap(PoolSwapResult { to_amount, pool_id })) = services.result.get(&txid)? else { - let address = Address::from_script(&self.to_script, bitcoin::Network::Bitcoin) - .map_err(|e| format_err!("Error getting address from script: {e}")); + // TODO fallback through getaccounthistory when indexing against non-oceanarchive node + // let address = Address::from_script(&self.to_script, bitcoin::Network::Bitcoin) + // .map_err(|e| format_err!("Error getting address from script: {e}")); debug!("Missing swap result for {}", ctx.tx.txid.to_string()); return Err("Missing swap result".into()); }; @@ -75,9 +76,10 @@ impl Index for CompositeSwap { let Some(TxResult::PoolSwap(PoolSwapResult { to_amount, .. })) = services.result.get(&txid)? else { - let address = - Address::from_script(&self.pool_swap.to_script, bitcoin::Network::Bitcoin) - .map_err(|e| format_err!("Error getting address from script: {e}")); + // TODO fallback through getaccounthistory when indexing against non-oceanarchive node + // let address = + // Address::from_script(&self.pool_swap.to_script, bitcoin::Network::Bitcoin) + // .map_err(|e| format_err!("Error getting address from script: {e}")); debug!("Missing swap result for {}", txid.to_string()); return Err("Missing swap result".into()); }; From 30c645ba69d52459a8137a84ce031e28bea77a6e Mon Sep 17 00:00:00 2001 From: jouzo Date: Tue, 5 Mar 2024 10:49:12 +0100 Subject: [PATCH 077/185] Clippy --- lib/ain-evm/src/precompiles/mod.rs | 2 +- lib/ain-grpc/src/lib.rs | 2 +- lib/ain-ocean/src/api/stats/cache.rs | 2 +- lib/ain-ocean/src/bin/cli.rs | 3 --- lib/ain-ocean/src/indexer/pool.rs | 4 ++-- lib/ain-ocean/src/model/mod.rs | 26 +++++++++++++------------- lib/ain-ocean/src/repository/mod.rs | 22 ++++++++++------------ 7 files changed, 28 insertions(+), 33 deletions(-) diff --git a/lib/ain-evm/src/precompiles/mod.rs b/lib/ain-evm/src/precompiles/mod.rs index 4a73c9fab00..5f3507d9f3f 100644 --- a/lib/ain-evm/src/precompiles/mod.rs +++ b/lib/ain-evm/src/precompiles/mod.rs @@ -12,7 +12,7 @@ use ethereum_types::H160; use evm::executor::stack::IsPrecompileResult; pub use evm::{ executor::stack::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileSet}, - Context, ExitError, ExitRevert, ExitSucceed, Transfer, + ExitError, ExitSucceed, }; use modexp::Modexp; use simple::{ECRecover, Identity, Ripemd160, Sha256}; diff --git a/lib/ain-grpc/src/lib.rs b/lib/ain-grpc/src/lib.rs index 747913eb9b4..c81cbd969bc 100644 --- a/lib/ain-grpc/src/lib.rs +++ b/lib/ain-grpc/src/lib.rs @@ -129,7 +129,7 @@ pub async fn init_ocean_server(addr: String) -> Result<()> { ); let network = ain_cpp_imports::get_network(); - let ocean_router = ain_ocean::ocean_router(&*OCEAN_SERVICES, client, network).await?; + let ocean_router = ain_ocean::ocean_router(&OCEAN_SERVICES, client, network).await?; let server_handle = runtime.tokio_runtime.spawn(async move { if let Err(e) = axum::serve(listener, ocean_router).await { diff --git a/lib/ain-ocean/src/api/stats/cache.rs b/lib/ain-ocean/src/api/stats/cache.rs index a8ff7e4520e..9ddef3b7cf1 100644 --- a/lib/ain-ocean/src/api/stats/cache.rs +++ b/lib/ain-ocean/src/api/stats/cache.rs @@ -120,7 +120,7 @@ pub async fn get_burned_total(ctx: &AppContext) -> Result { let burn_address = BURN_ADDRESS.get(ctx.network.as_str()).unwrap(); let mut tokens = ctx .client - .get_account(&burn_address, None, Some(true)) + .get_account(burn_address, None, Some(true)) .await?; let burn_info = ctx.client.get_burn_info().await?; diff --git a/lib/ain-ocean/src/bin/cli.rs b/lib/ain-ocean/src/bin/cli.rs index 79baf7a0465..7a5e9bc03d1 100644 --- a/lib/ain-ocean/src/bin/cli.rs +++ b/lib/ain-ocean/src/bin/cli.rs @@ -3,7 +3,6 @@ use std::{net::SocketAddr, path::PathBuf, sync::Arc, time::Instant}; use ain_ocean::{index_block, storage::ocean_store::OceanStore, Result, Services}; use clap::Parser; use defichain_rpc::{json::blockchain::*, Auth, BlockchainRPC, Client}; -use env_logger; #[derive(Parser, Debug)] #[command( @@ -106,6 +105,4 @@ async fn main() -> Result<()> { start_time = Instant::now(); } } - - Ok(()) } diff --git a/lib/ain-ocean/src/indexer/pool.rs b/lib/ain-ocean/src/indexer/pool.rs index e9f8bd96f41..b12a9dd24bf 100644 --- a/lib/ain-ocean/src/indexer/pool.rs +++ b/lib/ain-ocean/src/indexer/pool.rs @@ -1,8 +1,8 @@ use std::sync::Arc; -use anyhow::format_err; -use bitcoin::Address; use ain_dftx::pool::*; +// use anyhow::format_err; +// use bitcoin::Address; use log::debug; use super::Context; diff --git a/lib/ain-ocean/src/model/mod.rs b/lib/ain-ocean/src/model/mod.rs index e40062f6941..276ed46dae2 100644 --- a/lib/ain-ocean/src/model/mod.rs +++ b/lib/ain-ocean/src/model/mod.rs @@ -24,20 +24,20 @@ mod vault_auction_batch_history; pub use block::*; pub use masternode::*; pub use masternode_stats::*; -pub use oracle::*; -pub use oracle_history::*; -pub use oracle_price_active::*; -pub use oracle_price_aggregated::*; -pub use oracle_price_aggregated_interval::*; -pub use oracle_price_feed::*; -pub use oracle_token_currency::*; +// pub use oracle::*; +// pub use oracle_history::*; +// pub use oracle_price_active::*; +// pub use oracle_price_aggregated::*; +// pub use oracle_price_aggregated_interval::*; +// pub use oracle_price_feed::*; +// pub use oracle_token_currency::*; pub use poolswap::*; -pub use poolswap_aggregated::*; -pub use price_ticker::*; -pub use raw_block::*; -pub use script_activity::*; -pub use script_aggregation::*; -pub use script_unspent::*; +// pub use poolswap_aggregated::*; +// pub use price_ticker::*; +// pub use raw_block::*; +// pub use script_activity::*; +// pub use script_aggregation::*; +// pub use script_unspent::*; pub use transaction::*; pub use transaction_vin::*; pub use transaction_vout::*; diff --git a/lib/ain-ocean/src/repository/mod.rs b/lib/ain-ocean/src/repository/mod.rs index 561ec673a4e..03ae76abcd9 100644 --- a/lib/ain-ocean/src/repository/mod.rs +++ b/lib/ain-ocean/src/repository/mod.rs @@ -15,7 +15,6 @@ mod raw_block; mod script_activity; mod script_aggregation; mod script_unspent; -mod test; mod transaction; mod transaction_vin; mod transaction_vout; @@ -25,19 +24,18 @@ mod vault_auction_batch_history; pub use block::*; pub use masternode::*; pub use masternode_stats::*; -pub use oracle_price_active::*; -pub use oracle_price_aggregated::*; -pub use oracle_price_aggregated_interval::*; -pub use oracle_price_feed::*; -pub use oracle_token_currency::*; +// pub use oracle_price_active::*; +// pub use oracle_price_aggregated::*; +// pub use oracle_price_aggregated_interval::*; +// pub use oracle_price_feed::*; +// pub use oracle_token_currency::*; pub use pool_swap::*; -pub use pool_swap_aggregated::*; -pub use price_ticker::*; +// pub use pool_swap_aggregated::*; +// pub use price_ticker::*; pub use raw_block::*; -pub use script_activity::*; -pub use script_aggregation::*; -pub use script_unspent::*; -pub use test::*; +// pub use script_activity::*; +// pub use script_aggregation::*; +// pub use script_unspent::*; pub use transaction::*; pub use transaction_vin::*; pub use transaction_vout::*; From 91821310f7205d338c8d4b2622eeea6a63689f9b Mon Sep 17 00:00:00 2001 From: jouzo Date: Tue, 5 Mar 2024 12:47:27 +0100 Subject: [PATCH 078/185] Add RUST_DEFAULT_VERSION and MACOSX_DEPLOYMENT_TARGET to ci_export_vars --- .github/workflows/build-dev.yaml | 1 - make.sh | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-dev.yaml b/.github/workflows/build-dev.yaml index 2700ca9a685..512b0d68d04 100644 --- a/.github/workflows/build-dev.yaml +++ b/.github/workflows/build-dev.yaml @@ -38,7 +38,6 @@ jobs: image: ${{ matrix.container }} env: TARGET: ${{matrix.target}} - MACOSX_DEPLOYMENT_TARGET: 10.14 steps: - uses: actions/checkout@v4 diff --git a/make.sh b/make.sh index 6a0f1eda9fd..5ef771473a7 100755 --- a/make.sh +++ b/make.sh @@ -1176,6 +1176,12 @@ ci_export_vars() { else echo "PKG_TYPE=tar.gz" >> "$GITHUB_ENV" fi + + if [[ "${TARGET}" =~ .*darwin.* ]]; then + echo "MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET:-10.14}" >> "$GITHUB_ENV" + fi + + echo "RUST_DEFAULT_VERSION=${RUST_DEFAULT_VERSION:-1.76}" >> "$GITHUB_ENV" fi } From 53a3ece681b08c5850f27e52924cf950071e6952 Mon Sep 17 00:00:00 2001 From: jouzo Date: Tue, 5 Mar 2024 13:01:25 +0100 Subject: [PATCH 079/185] Overwrite RUST_DEFAULT_VERSION --- make.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make.sh b/make.sh index 5ef771473a7..67e87c6e2b0 100755 --- a/make.sh +++ b/make.sh @@ -1181,7 +1181,7 @@ ci_export_vars() { echo "MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET:-10.14}" >> "$GITHUB_ENV" fi - echo "RUST_DEFAULT_VERSION=${RUST_DEFAULT_VERSION:-1.76}" >> "$GITHUB_ENV" + echo "RUST_DEFAULT_VERSION=1.76" >> "$GITHUB_ENV" fi } From 4df2c81e4f8d9d11b9f875e0260ef6585788a41f Mon Sep 17 00:00:00 2001 From: jouzo Date: Wed, 6 Mar 2024 10:35:11 +0100 Subject: [PATCH 080/185] Use defich/rust-defichain-rpc --- lib/Cargo.lock | 4 ++-- lib/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index feba350049a..4224af49162 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -1487,7 +1487,7 @@ dependencies = [ [[package]] name = "defichain-rpc" version = "0.18.0" -source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#fab7f5f9d38fe225b072087d621e8f0bf11706de" +source = "git+https://github.com/defich/rust-defichain-rpc.git#fab7f5f9d38fe225b072087d621e8f0bf11706de" dependencies = [ "async-trait", "defichain-rpc-json", @@ -1500,7 +1500,7 @@ dependencies = [ [[package]] name = "defichain-rpc-json" version = "0.18.0" -source = "git+https://github.com/Jouzo/rust-defichain-rpc.git#fab7f5f9d38fe225b072087d621e8f0bf11706de" +source = "git+https://github.com/defich/rust-defichain-rpc.git#fab7f5f9d38fe225b072087d621e8f0bf11706de" dependencies = [ "bitcoin", "serde", diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 51bc45f8ecf..ac4c7df4eb1 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -121,7 +121,7 @@ substrate-bn = "0.6" #### Ocean dependencies bitcoin = "0.31" cached = { version = "0.48", features = ["async"] } -defichain-rpc = { version = "0.18.0", git = "https://github.com/Jouzo/rust-defichain-rpc.git" } +defichain-rpc = { version = "0.18.0", git = "https://github.com/defich/rust-defichain-rpc.git" } ### Local crates ain-cpp-imports = { path = "./ain-cpp-imports" } From 5aff3e8bc22bcac369d13a6f4faf6ca01f3fc4bc Mon Sep 17 00:00:00 2001 From: Nagaraj <144004792+nagarajm22@users.noreply.github.com> Date: Mon, 18 Mar 2024 16:29:28 +0000 Subject: [PATCH 081/185] Network Type for ocean API (#2861) * added network type to ocean * added network type to ocean * Impl ToString for Network --------- Co-authored-by: jouzo --- lib/ain-ocean/src/bin/cli.rs | 7 ++++--- lib/ain-ocean/src/consts.rs | 34 ++++++++++++++++++++++++++++++++++ lib/ain-ocean/src/lib.rs | 2 +- 3 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 lib/ain-ocean/src/consts.rs diff --git a/lib/ain-ocean/src/bin/cli.rs b/lib/ain-ocean/src/bin/cli.rs index 7a5e9bc03d1..45847fb819b 100644 --- a/lib/ain-ocean/src/bin/cli.rs +++ b/lib/ain-ocean/src/bin/cli.rs @@ -1,6 +1,6 @@ use std::{net::SocketAddr, path::PathBuf, sync::Arc, time::Instant}; -use ain_ocean::{index_block, storage::ocean_store::OceanStore, Result, Services}; +use ain_ocean::{consts::Network, index_block, storage::ocean_store::OceanStore, Result, Services}; use clap::Parser; use defichain_rpc::{json::blockchain::*, Auth, BlockchainRPC, Client}; @@ -35,7 +35,7 @@ struct Cli { /// Sets Ocean network #[arg(long, value_name = "NETWORK", default_value = "mainnet")] - network: String, + network: Network, } #[tokio::main] @@ -50,7 +50,8 @@ async fn main() -> Result<()> { let services = Arc::new(Services::new(store)); let listener = tokio::net::TcpListener::bind(cli.bind_address).await?; - let ocean_router = ain_ocean::ocean_router(&services, client.clone(), cli.network).await?; + let ocean_router = + ain_ocean::ocean_router(&services, client.clone(), cli.network.to_string()).await?; tokio::spawn(async move { axum::serve(listener, ocean_router).await.unwrap() }); let mut indexed_block = 0; diff --git a/lib/ain-ocean/src/consts.rs b/lib/ain-ocean/src/consts.rs new file mode 100644 index 00000000000..9162f3429e7 --- /dev/null +++ b/lib/ain-ocean/src/consts.rs @@ -0,0 +1,34 @@ +#[derive(Debug, Clone)] +pub enum Network { + Mainnet, + Testnet, + Regtest, + Devnet, + Changi, +} + +impl std::str::FromStr for Network { + type Err = &'static str; + fn from_str(s: &str) -> Result { + match s { + "mainnet" => Ok(Network::Mainnet), + "testnet" => Ok(Network::Testnet), + "regtest" => Ok(Network::Regtest), + "devnet" => Ok(Network::Devnet), + "changi" => Ok(Network::Changi), + _ => Err("invalid network"), + } + } +} + +impl ToString for Network { + fn to_string(&self) -> String { + match self { + Network::Mainnet => String::from("mainnet"), + Network::Testnet => String::from("testnet"), + Network::Regtest => String::from("regtest"), + Network::Devnet => String::from("devnet"), + Network::Changi => String::from("changi"), + } + } +} diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 33ee035f8c4..57fa29993e6 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -1,6 +1,6 @@ +pub mod consts; pub mod error; mod indexer; - use std::{path::PathBuf, sync::Arc}; pub use api::ocean_router; From fd0539d66b011d33cb650bfb2f9efa3c97e692ee Mon Sep 17 00:00:00 2001 From: Nagaraj <144004792+nagarajm22@users.noreply.github.com> Date: Tue, 9 Apr 2024 13:48:09 +0000 Subject: [PATCH 082/185] Implementation of oracle indexing (#2862) * Implementation of oracle repo and storage for oracle api * Implementation for indexing oracle * formatting issue in vscode * fixed process_inner_values * added oracle get method API * fixed error handling * updated oracles history details * updated price oracles * oracles fmt * implemented price api methods and fixed price_ticker * fixed pagination for oracles and price and removal price_ticker_key * fixed invalidate and appointoracle pricefeed and currecny * fixed update and remove oracle * remove bigUint crate and fixed index_interval_mapper * rebase ocean archive * added price ticker * added price ticker * fixed error handling for oracle and invalidate method * format issue in vs_code * fixed oracle and added testcase appoint * implemented of setoracleInterval * added indexing setoraclinterval * added indexing setoraclinterval * added setinterval model * updated oracles remove oracle and invalidate method * fixed update and invalidate oracle * fixed update and invalidate oracle * fixed oracles api and price feeds for setoracles * removed num-bigint * removed num-bigint * removed num-bigint and fixed price api * merge setoracledatainterval into setoracledata * updated invalidate interval and index mapper * Restore opcode import * Remove num-traits * Clippy * fixed price_feed api and removed num-traits * fixed space * Revert src fmt changes --------- Co-authored-by: jouzo --- lib/ain-cpp-imports/src/lib.rs | 3 +- lib/ain-dftx/src/types/common.rs | 8 + lib/ain-evm/src/eventlistener.rs | 3 +- lib/ain-evm/src/precompiles/token_split.rs | 8 +- lib/ain-evm/src/storage/block_store.rs | 16 +- lib/ain-evm/src/storage/migration.rs | 3 +- lib/ain-ocean/Cargo.toml | 4 + lib/ain-ocean/src/api/mod.rs | 8 +- lib/ain-ocean/src/api/oracle.rs | 113 ++- lib/ain-ocean/src/api/prices.rs | 270 +++++- lib/ain-ocean/src/bin/cli.rs | 3 +- lib/ain-ocean/src/error.rs | 2 + lib/ain-ocean/src/indexer/mod.rs | 17 +- lib/ain-ocean/src/indexer/oracle.rs | 882 +++++++++++++++++- lib/ain-ocean/src/indexer/oracle_test.rs | 91 ++ lib/ain-ocean/src/lib.rs | 87 +- lib/ain-ocean/src/model/mod.rs | 31 +- lib/ain-ocean/src/model/oracle.rs | 7 +- lib/ain-ocean/src/model/oracle_history.rs | 21 +- .../src/model/oracle_price_active.rs | 8 +- .../src/model/oracle_price_aggregated.rs | 13 +- .../model/oracle_price_aggregated_interval.rs | 23 +- lib/ain-ocean/src/model/oracle_price_feed.rs | 14 +- .../src/model/oracle_token_currency.rs | 12 +- lib/ain-ocean/src/model/price_ticker.rs | 8 +- lib/ain-ocean/src/model/prices.rs | 14 + lib/ain-ocean/src/repository/mod.rs | 16 +- lib/ain-ocean/src/repository/oracle.rs | 28 + .../src/repository/oracle_history.rs | 43 + .../src/repository/oracle_price_active.rs | 42 + .../src/repository/oracle_price_aggregated.rs | 42 + .../oracle_price_aggregated_interval.rs | 51 + .../src/repository/oracle_price_feed.rs | 42 + .../src/repository/oracle_token_currency.rs | 42 + lib/ain-ocean/src/repository/price_ticker.rs | 26 + lib/ain-ocean/src/storage/columns/mod.rs | 9 +- lib/ain-ocean/src/storage/columns/oracle.rs | 19 + .../src/storage/columns/oracle_history.rs | 21 +- .../storage/columns/oracle_price_active.rs | 21 +- .../columns/oracle_price_aggregated.rs | 20 +- .../oracle_price_aggregated_interval.rs | 21 +- .../src/storage/columns/oracle_price_feed.rs | 21 +- .../storage/columns/oracle_token_currency.rs | 19 +- .../src/storage/columns/price_ticker.rs | 8 +- 44 files changed, 1986 insertions(+), 174 deletions(-) create mode 100644 lib/ain-ocean/src/indexer/oracle_test.rs create mode 100644 lib/ain-ocean/src/model/prices.rs create mode 100644 lib/ain-ocean/src/repository/oracle.rs create mode 100644 lib/ain-ocean/src/repository/oracle_history.rs create mode 100644 lib/ain-ocean/src/storage/columns/oracle.rs diff --git a/lib/ain-cpp-imports/src/lib.rs b/lib/ain-cpp-imports/src/lib.rs index 48126c71669..6224fc71ec1 100644 --- a/lib/ain-cpp-imports/src/lib.rs +++ b/lib/ain-cpp-imports/src/lib.rs @@ -150,8 +150,7 @@ mod ffi { } } -pub use ffi::Attributes; -pub use ffi::TokenAmount; +pub use ffi::{Attributes, TokenAmount}; /// Returns the chain ID of the current network. pub fn get_chain_id() -> Result> { diff --git a/lib/ain-dftx/src/types/common.rs b/lib/ain-dftx/src/types/common.rs index a6360a2a18c..32acc7d7302 100644 --- a/lib/ain-dftx/src/types/common.rs +++ b/lib/ain-dftx/src/types/common.rs @@ -1,3 +1,5 @@ +use std::slice::Iter; + use bitcoin::{ consensus::{Decodable, Encodable}, io::{self, ErrorKind}, @@ -169,3 +171,9 @@ impl Decodable for VarInt { Ok(VarInt(n)) } } + +impl CompactVec { + pub fn iter(&self) -> Iter<'_, T> { + self.0.iter() + } +} diff --git a/lib/ain-evm/src/eventlistener.rs b/lib/ain-evm/src/eventlistener.rs index 4d23ba0a2dc..006fc990716 100644 --- a/lib/ain-evm/src/eventlistener.rs +++ b/lib/ain-evm/src/eventlistener.rs @@ -1,6 +1,5 @@ use std::collections::{HashMap, HashSet, VecDeque}; -use crate::opcode; use ethereum_types::{H160, H256}; use evm::gasometer::tracing::{Event as GasEvent, EventListener as GasEventListener}; use evm_runtime::{ @@ -9,6 +8,8 @@ use evm_runtime::{ }; use log::debug; +use crate::opcode; + #[derive(Clone, Debug)] pub struct ExecutionStep { pub pc: usize, diff --git a/lib/ain-evm/src/precompiles/token_split.rs b/lib/ain-evm/src/precompiles/token_split.rs index 7d77db50d16..655eccb9291 100644 --- a/lib/ain-evm/src/precompiles/token_split.rs +++ b/lib/ain-evm/src/precompiles/token_split.rs @@ -2,13 +2,16 @@ use std::collections::BTreeMap; use ain_contracts::{dst20_address_from_token_id, validate_split_tokens_input, TokenSplitParams}; use ain_cpp_imports::{split_tokens_from_evm, TokenAmount}; +use anyhow::format_err; use ethereum_types::{H160, H256, U256}; use evm::{ backend::Apply, executor::stack::{PrecompileFailure, PrecompileHandle, PrecompileOutput}, ExitError, ExitSucceed, }; +use log::debug; +use super::DVMStatePrecompile; use crate::{ contract::{get_address_storage_index, u256_to_h256}, precompiles::PrecompileResult, @@ -16,11 +19,6 @@ use crate::{ Result, }; -use anyhow::format_err; -use log::debug; - -use super::DVMStatePrecompile; - pub struct TokenSplit; impl TokenSplit { diff --git a/lib/ain-evm/src/storage/block_store.rs b/lib/ain-evm/src/storage/block_store.rs index 026f6a2f8c1..29925e571ff 100644 --- a/lib/ain-evm/src/storage/block_store.rs +++ b/lib/ain-evm/src/storage/block_store.rs @@ -1,14 +1,17 @@ -use ain_db::version::{DBVersionControl, Migration}; -use ain_db::{Column, ColumnName, LedgerColumn, Rocks, TypedColumn}; -use anyhow::format_err; -use ethereum::{BlockAny, TransactionV2}; -use ethereum_types::{H160, H256, U256}; -use log::debug; use std::{ collections::HashMap, fmt::Write, fs, marker::PhantomData, path::Path, str::FromStr, sync::Arc, time::Instant, }; +use ain_db::{ + version::{DBVersionControl, Migration}, + Column, ColumnName, LedgerColumn, Result as DBResult, Rocks, TypedColumn, +}; +use anyhow::format_err; +use ethereum::{BlockAny, TransactionV2}; +use ethereum_types::{H160, H256, U256}; +use log::debug; + use super::{ migration::MigrationV1, traits::{BlockStorage, FlushableStorage, ReceiptStorage, Rollback, TransactionStorage}, @@ -22,7 +25,6 @@ use crate::{ }, EVMError, Result, }; -use ain_db::Result as DBResult; #[derive(Debug, Clone)] pub struct BlockStore(Arc); diff --git a/lib/ain-evm/src/storage/migration.rs b/lib/ain-evm/src/storage/migration.rs index aeba029607b..1f88c92c251 100644 --- a/lib/ain-evm/src/storage/migration.rs +++ b/lib/ain-evm/src/storage/migration.rs @@ -1,10 +1,9 @@ -use ain_db::{version::Migration, DBError}; +use ain_db::{version::Migration, DBError, Result as DBResult}; use anyhow::format_err; use rayon::prelude::*; use super::{block_store::BlockStore, db::columns}; use crate::Result; -use ain_db::Result as DBResult; /// Migration for version 1. /// Context: diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index c0a19ef07ef..e447dee4eed 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -7,6 +7,10 @@ edition = "2021" [profile.test] debug = true +[profile.dev] +opt-level = 0 +debug = true + [dependencies] ain-cpp-imports.workspace = true ain-db.workspace = true diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index 13f6ea62bc7..570dafbbbe4 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -8,9 +8,9 @@ mod fee; mod governance; mod loan; mod masternode; -// mod oracle; +mod oracle; // mod poolpairs; -// mod prices; +pub mod prices; // mod rawtx; mod cache; mod common; @@ -65,7 +65,7 @@ pub async fn ocean_router( services: services.clone(), network, }); - + println!("{:?}", context.network); Ok(Router::new().nest( format!("/v0/{}", context.network).as_str(), Router::new() @@ -74,7 +74,7 @@ pub async fn ocean_router( .nest("/loans", loan::router(Arc::clone(&context))) .nest("/fee", fee::router(Arc::clone(&context))) .nest("/masternodes", masternode::router(Arc::clone(&context))) - // .nest("/oracles", oracle::router(Arc::clone(&context))) + .nest("/oracles", oracle::router(Arc::clone(&context))) // .nest("/poolpairs", poolpairs::router(Arc::clone(&context))) // .nest("/prices", prices::router(Arc::clone(&context))) // .nest("/rawtx", rawtx::router(Arc::clone(&context))) diff --git a/lib/ain-ocean/src/api/oracle.rs b/lib/ain-ocean/src/api/oracle.rs index 19d8116e543..d46d674642c 100644 --- a/lib/ain-ocean/src/api/oracle.rs +++ b/lib/ain-ocean/src/api/oracle.rs @@ -1,19 +1,111 @@ -use std::sync::Arc; +use std::{str::FromStr, sync::Arc}; -use axum::{routing::get, Router}; -use defichain_rpc::{Client, RpcApi}; -use super::path::Path; +use ain_macros::ocean_endpoint; +use axum::{ + extract::{Path, Query}, + routing::get, + Extension, Router, +}; +use bitcoin::Txid; -async fn list_oracles() -> String { - "List of oracles".to_string() +use super::{ + query::PaginationQuery, + response::{ApiPagedResponse, Response}, + AppContext, +}; +use crate::{ + error::{ApiError, Error, NotFoundKind}, + model::{Oracle, OraclePriceFeed}, + repository::RepositoryOps, + storage::SortOrder, + Result, +}; + +#[ocean_endpoint] +async fn list_oracles( + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let oracles_result: Result> = ctx + .services + .oracle + .by_id + .list(None, SortOrder::Descending)? + .take(query.size) + .map(|item| { + let (id, oracle) = item?; + Ok((id, oracle)) + }) + .collect(); + let oracles = oracles_result?; + let oracles: Vec = oracles.into_iter().map(|(_, oracle)| oracle).collect(); + + Ok(ApiPagedResponse::of(oracles, query.size, |oracles| { + oracles.id + })) +} +#[ocean_endpoint] +async fn get_price_feed( + Path((oracle_id, key)): Path<(String, String)>, + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let txid = Txid::from_str(&oracle_id)?; + let (token, currency) = split_key(&key); + let oracle_price_feed = ctx + .services + .oracle_price_feed + .by_key + .list(Some((token, currency, txid)), SortOrder::Descending)? + .take(query.size) + .map(|item| { + let (_, id) = item?; + let b = ctx + .services + .oracle_price_feed + .by_id + .get(&id)? + .ok_or("Missing price feed index")?; + + Ok(b) + }) + .collect::>>()?; + Ok(ApiPagedResponse::of(oracle_price_feed, 2, |price_feed| { + price_feed.sort.clone() + })) } -async fn get_price_feed(Path((oracle_id, key)): Path<(String, String)>) -> String { - format!("Price feed for oracle ID {} and key {}", oracle_id, key) +#[ocean_endpoint] +async fn get_oracle_by_address( + Path(address): Path, + Extension(ctx): Extension>, +) -> Result> { + format!("Oracle details for address {}", address); + let (_, oracle) = ctx + .services + .oracle + .by_id + .list(None, SortOrder::Descending)? + .filter_map(|item| { + let (id, oracle) = item.ok()?; + if oracle.owner_address == address { + Some((id, oracle)) + } else { + None + } + }) + .next() + .ok_or(Error::NotFound(NotFoundKind::Oracle))?; + Ok(Response::new(oracle)) } -async fn get_oracle_by_address(Path(address): Path) -> String { - format!("Oracle details for address {}", address) +fn split_key(key: &str) -> (String, String) { + let parts: Vec<&str> = key.split('-').collect(); + if parts.len() == 2 { + (parts[0].to_owned(), parts[1].to_owned()) + } else { + (String::new(), String::new()) + } } pub fn router(ctx: Arc) -> Router { @@ -21,4 +113,5 @@ pub fn router(ctx: Arc) -> Router { .route("/", get(list_oracles)) .route("/:oracleId/:key/feed", get(get_price_feed)) .route("/:address", get(get_oracle_by_address)) + .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/api/prices.rs b/lib/ain-ocean/src/api/prices.rs index d2b8b8132bd..f384da3631c 100644 --- a/lib/ain-ocean/src/api/prices.rs +++ b/lib/ain-ocean/src/api/prices.rs @@ -1,45 +1,257 @@ use std::sync::Arc; -use axum::{routing::get, Router}; -use defichain_rpc::{Client, RpcApi}; -use serde::Deserialize; -use super::path::Path; - -#[derive(Deserialize)] -struct PriceKey { - key: String, -} +use ain_macros::ocean_endpoint; +use axum::{ + extract::{Path, Query}, + routing::get, + Extension, Router, +}; -#[derive(Deserialize)] -struct FeedWithInterval { - key: String, - interval: i64, -} +use super::{ + query::PaginationQuery, + response::{ApiPagedResponse, Response}, + AppContext, +}; +use crate::{ + error::{ApiError, Error, NotFoundKind}, + model::{ + OracleIntervalSeconds, OraclePriceActive, OraclePriceAggregated, + OraclePriceAggregatedInterval, OraclePriceAggregatedIntervalAggregated, + OracleTokenCurrency, PriceTicker, + }, + repository::RepositoryOps, + storage::SortOrder, + Result, +}; -async fn list_prices() -> String { - "List of prices".to_string() -} +#[ocean_endpoint] +async fn list_prices( + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + "List of prices".to_string(); + let prices = ctx + .services + .price_ticker + .by_id + .list(None, SortOrder::Descending)? + .take(query.size) + .map(|item| { + let (id, priceticker) = item?; + Ok((id, priceticker)) + }) + .collect::>>()?; -async fn get_price(Path(PriceKey { key }): Path) -> String { - format!("Details of price with key {}", key) -} + let prices: Vec = prices + .into_iter() + .map(|(_, price_ticker)| price_ticker) + .collect(); -async fn get_feed_active(Path(PriceKey { key }): Path) -> String { - format!("Active feed for price with key {}", key) + Ok(ApiPagedResponse::of(prices, query.size, |price| { + price.sort.to_string() + })) +} +#[ocean_endpoint] +async fn get_price( + Path(token): Path, + Path(curreny): Path, + Extension(ctx): Extension>, +) -> Result> { + let price_ticker_id = (token, curreny); + if let Some(price_ticker) = ctx.services.price_ticker.by_id.get(&price_ticker_id)? { + Ok(Response::new(price_ticker)) + } else { + Err(Error::NotFound(NotFoundKind::Oracle)) + } } -async fn get_feed(Path(PriceKey { key }): Path) -> String { - format!("Feed for price with key {}", key) +#[ocean_endpoint] +async fn get_feed( + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let next = query + .next + .map(|q| { + let parts: Vec<&str> = q.split('-').collect(); + if parts.len() != 2 { + return Err("Invalid query format"); + } + let token = parts[0].parse::().map_err(|_| "Invalid token")?; + let currency = parts[1].parse::().map_err(|_| "Invalid currency")?; + Ok((token, currency)) + }) + .transpose()?; + let aggregated = ctx + .services + .oracle_price_aggregated + .by_key + .list(next, SortOrder::Descending)? + .take(query.size) + .map(|item| { + let (_, id) = item?; + let b = ctx + .services + .oracle_price_aggregated + .by_id + .get(&id)? + .ok_or("Missing price_aggregated index")?; + + Ok(b) + }) + .collect::>>()?; + + Ok(ApiPagedResponse::of(aggregated, query.size, |aggre| { + aggre.sort.to_string() + })) } +#[ocean_endpoint] +async fn get_feed_active( + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let next = query + .next + .map(|q| { + let parts: Vec<&str> = q.split('-').collect(); + if parts.len() != 2 { + return Err("Invalid query format"); + } + let token = parts[0].parse::().map_err(|_| "Invalid token")?; + let currency = parts[1].parse::().map_err(|_| "Invalid currency")?; + Ok((token, currency)) + }) + .transpose()?; + let price_active = ctx + .services + .oracle_price_active + .by_key + .list(next, SortOrder::Descending)? + .take(query.size) + .map(|item| { + let (_, id) = item?; + let b = ctx + .services + .oracle_price_active + .by_id + .get(&id)? + .ok_or("Missing price active index")?; + Ok(b) + }) + .collect::>>()?; + Ok(ApiPagedResponse::of( + price_active, + query.size, + |price_active| price_active.sort.to_string(), + )) +} +#[ocean_endpoint] async fn get_feed_with_interval( - Path(FeedWithInterval { key, interval }): Path, -) -> String { - format!("Feed for price with key {} over interval {}", key, interval) + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let next = query + .next + .map(|q| { + let parts: Vec<&str> = q.split('-').collect(); + if parts.len() != 3 { + return Err("Invalid query format"); + } + let token = parts[0].parse::().map_err(|_| "Invalid token")?; + let currency = parts[1].parse::().map_err(|_| "Invalid currency")?; + let interval = match parts[2] { + "900" => OracleIntervalSeconds::FifteenMinutes, + "3600" => OracleIntervalSeconds::OneHour, + "86400" => OracleIntervalSeconds::OneDay, + _ => return Err("Invalid interval"), + }; + Ok((token, currency, interval)) + }) + .transpose()?; + let items = ctx + .services + .oracle_price_aggregated_interval + .by_key + .list(next.clone(), SortOrder::Descending)? + .take(query.size) + .map(|item| { + let (_, id) = item?; + let price_agrregated_interval = ctx + .services + .oracle_price_aggregated_interval + .by_id + .get(&id)? + .ok_or("Missing oracle price aggregated interval index")?; + Ok(price_agrregated_interval) + }) + .collect::>>()?; + + let mapped: Vec = items + .into_iter() + .map(|item| { + let _start = + item.block.median_time - (item.block.median_time % next.clone().unwrap().2 as i64); + OraclePriceAggregatedInterval { + id: item.id, + key: item.key, + sort: item.sort, + token: item.token, + currency: item.currency, + aggregated: OraclePriceAggregatedIntervalAggregated { + amount: item.aggregated.amount, + weightage: item.aggregated.weightage, + count: item.aggregated.count, + oracles: item.aggregated.oracles, + }, + block: item.block, + } + }) + .collect(); + + Ok(ApiPagedResponse::of(mapped, query.size, |item| { + item.sort.clone() + })) } -async fn get_oracles(Path(PriceKey { key }): Path) -> String { - format!("Oracles for price with key {}", key) +#[ocean_endpoint] +async fn get_oracles( + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let next = query + .next + .map(|q| { + let parts: Vec<&str> = q.split('-').collect(); + if parts.len() != 2 { + return Err("Invalid query format"); + } + let token = parts[0].parse::().map_err(|_| "Invalid token")?; + let currency = parts[1].parse::().map_err(|_| "Invalid currency")?; + Ok((token, currency)) + }) + .transpose()?; + let items = ctx + .services + .oracle_token_currency + .by_key + .list(next, SortOrder::Descending)? + .take(query.size) + .map(|item| { + let (_, id) = item?; + let b = ctx + .services + .oracle_token_currency + .by_id + .get(&id)? + .ok_or("Missing token-currency index")?; + Ok(b) + }) + .collect::>>()?; + + Ok(ApiPagedResponse::of(items, query.size, |item| { + item.oracle_id.to_string() + })) } pub fn router(ctx: Arc) -> Router { diff --git a/lib/ain-ocean/src/bin/cli.rs b/lib/ain-ocean/src/bin/cli.rs index 45847fb819b..c839e9a127f 100644 --- a/lib/ain-ocean/src/bin/cli.rs +++ b/lib/ain-ocean/src/bin/cli.rs @@ -64,7 +64,7 @@ async fn main() -> Result<()> { .by_height .get_highest()? .map_or(0, |b| b.height); - + println!("current height in {:?}", highest_block); let new_height = highest_block + 1; let hash = if let Some(hash) = next_block_hash { hash @@ -79,7 +79,6 @@ async fn main() -> Result<()> { } } }; - let block = match client.get_block(hash, 2).await { Err(e) => { println!("e : {:?}", e); diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 64b640eb5da..153e22d599a 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -19,6 +19,8 @@ pub enum NotFoundKind { Masternode, #[error("scheme")] Scheme, + #[error("oracle")] + Oracle, } #[derive(Error, Debug)] diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index b14410c4e7c..9cafbcee392 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -1,6 +1,7 @@ mod auction; mod masternode; -mod oracle; +pub mod oracle; +pub mod oracle_test; mod pool; pub mod transaction; pub mod tx_result; @@ -77,13 +78,13 @@ pub fn index_block(services: &Arc, block: Block) -> Resul DfTx::CreateMasternode(data) => data.index(services, &ctx)?, DfTx::UpdateMasternode(data) => data.index(services, &ctx)?, DfTx::ResignMasternode(data) => data.index(services, &ctx)?, - // DfTx::AppointOracle(data) => data.index(services,&ctx)?, - // DfTx::RemoveOracle(data) => data.index(services,&ctx)?, - // DfTx::UpdateOracle(data) => data.index(services,&ctx)?, - // DfTx::SetOracleData(data) => data.index(services,&ctx)?, - DfTx::PoolSwap(data) => data.index(services, &ctx)?, - DfTx::CompositeSwap(data) => data.index(services, &ctx)?, - DfTx::PlaceAuctionBid(data) => data.index(services, &ctx)?, + DfTx::AppointOracle(data) => data.index(services, &ctx)?, + DfTx::RemoveOracle(data) => data.index(services, &ctx)?, + DfTx::UpdateOracle(data) => data.index(services, &ctx)?, + DfTx::SetOracleData(data) => data.index(services, &ctx)?, + // DfTx::PoolSwap(data) => data.index(services, &ctx)?, + // DfTx::CompositeSwap(data) => data.index(services, &ctx)?, + // DfTx::PlaceAuctionBid(data) => data.index(services, &ctx)?, _ => (), } log_elapsed(start, "Indexed dftx"); diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index 45ba1e87c25..7b379abd3ee 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -1,49 +1,889 @@ -use std::sync::Arc; +use std::{str::FromStr, sync::Arc, vec}; -use ain_dftx::oracles::*; +use ain_dftx::{common::CompactVec, oracles::*}; +use bitcoin::Txid; +use rust_decimal::{ + prelude::{ToPrimitive, Zero}, + Decimal, +}; -use super::Context; use crate::{ - indexer::{Index, Result}, - Services, + error::NotFoundKind, + indexer::{Context, Index, Result}, + model::{ + BlockContext, Oracle, OracleHistory, OracleIntervalSeconds, OraclePriceAggregated, + OraclePriceAggregatedAggregated, OraclePriceAggregatedAggregatedOracles, + OraclePriceAggregatedInterval, OraclePriceAggregatedIntervalAggregated, + OraclePriceAggregatedIntervalAggregatedOracles, OraclePriceFeed, OracleTokenCurrency, + PriceFeedsItem, + }, + repository::RepositoryOps, + storage::SortOrder, + Error, Services, }; impl Index for AppointOracle { - fn index(self, _services: &Arc, _ctx: &Context) -> Result<()> { - todo!() + fn index(self, services: &Arc, ctx: &Context) -> Result<()> { + let oracle_id = ctx.tx.txid; + + let price_feeds_items: Vec = self + .price_feeds + .iter() + .map(|pair| PriceFeedsItem { + token: pair.token.clone(), + currency: pair.currency.clone(), + }) + .collect(); + + let oracle = Oracle { + id: oracle_id, + owner_address: self.script.to_hex_string(), + weightage: self.weightage, + price_feeds: price_feeds_items.clone(), + block: ctx.block.clone(), + }; + services.oracle.by_id.put(&oracle.id, &oracle)?; + let oracle_history = OracleHistory { + id: (ctx.tx.txid, ctx.block.height, oracle_id), + oracle_id: ctx.tx.txid, + sort: format!( + "{}{}", + hex::encode(ctx.block.height.to_be_bytes()), + ctx.tx.txid + ), + owner_address: self.script.to_hex_string(), + weightage: self.weightage, + price_feeds: price_feeds_items, + block: ctx.block.clone(), + }; + services + .oracle_history + .by_id + .put(&oracle_history.id, &oracle_history)?; + services + .oracle_history + .by_key + .put(&oracle_history.oracle_id, &oracle_history.id)?; + let prices_feeds = self.price_feeds.as_ref(); + for token_currency in prices_feeds { + let oracle_token_currency = OracleTokenCurrency { + id: ( + token_currency.token.to_owned(), + token_currency.currency.to_owned(), + oracle_id, + ), + key: ( + token_currency.token.to_owned(), + token_currency.currency.to_owned(), + ), + token: token_currency.token.to_owned(), + currency: token_currency.currency.to_owned(), + oracle_id, + weightage: self.weightage, + block: ctx.block.clone(), + }; + services + .oracle_token_currency + .by_key + .put(&oracle_token_currency.key, &oracle_token_currency.id)?; + services + .oracle_token_currency + .by_id + .put(&oracle_token_currency.id, &oracle_token_currency)?; + } + + Ok(()) } - fn invalidate(&self, _services: &Arc, _context: &Context) -> Result<()> { - todo!() + fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { + let oracle_id = context.tx.txid; + services.oracle.by_id.delete(&oracle_id)?; + services.oracle_history.by_id.delete(&( + oracle_id, + context.block.height, + context.tx.txid, + ))?; + for currency_pair in self.price_feeds.as_ref().iter() { + let token_currency_id = ( + currency_pair.token.to_owned(), + currency_pair.currency.to_owned(), + oracle_id, + ); + let token_currency_key = ( + currency_pair.token.to_owned(), + currency_pair.currency.to_owned(), + ); + services + .oracle_token_currency + .by_id + .delete(&token_currency_id)?; + services + .oracle_token_currency + .by_key + .delete(&token_currency_key)?; + } + Ok(()) } } impl Index for RemoveOracle { - fn index(self, _services: &Arc, _ctx: &Context) -> Result<()> { - todo!() + fn index(self, services: &Arc, ctx: &Context) -> Result<()> { + let oracle_id = ctx.tx.txid; + //delete for oracle data from oracle + services.oracle.by_id.delete(&oracle_id)?; + let previous_hsitory = get_previous_oracle_history_list(services, oracle_id.clone()); + match previous_hsitory { + Ok(previous_oracle) => { + for oracle_history in &previous_oracle { + for price_feed_item in &oracle_history.price_feeds { + let deletion_key = ( + price_feed_item.token.to_owned(), + price_feed_item.currency.to_owned(), + oracle_history.oracle_id, + ); + match services.oracle_token_currency.by_id.delete(&deletion_key) { + Ok(_) => { + // Successfully deleted + } + Err(err) => { + let error_message = format!("Error: remove_oracle: {:?}", err); + eprintln!("{}", error_message); + return Err(Error::NotFound(NotFoundKind::Oracle)); + } + } + } + } + } + Err(err) => { + let error_message = format!("Error: remove_oracle: {:?}", err); + eprintln!("{}", error_message); + return Err(Error::NotFound(NotFoundKind::Oracle)); + } + } + Ok(()) } + fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { + let oracle_id = context.tx.txid; + let previous_oracle_history_result = + get_previous_oracle_history_list(services, oracle_id.clone()); - fn invalidate(&self, _services: &Arc, _context: &Context) -> Result<()> { - todo!() + match previous_oracle_history_result { + Ok(previous_oracle_history) => { + for previous_oracle in previous_oracle_history { + let oracle = Oracle { + id: previous_oracle.oracle_id, + owner_address: previous_oracle.owner_address, + weightage: previous_oracle.weightage, + price_feeds: previous_oracle.price_feeds.clone(), + block: previous_oracle.block, + }; + services.oracle.by_id.put(&oracle.id, &oracle)?; + + for prev_token_currency in previous_oracle.price_feeds { + let oracle_token_currency = OracleTokenCurrency { + id: ( + prev_token_currency.token.clone(), + prev_token_currency.currency.clone(), + oracle.id, + ), + key: ( + prev_token_currency.token.clone(), + prev_token_currency.currency.clone(), + ), + token: prev_token_currency.token, + currency: prev_token_currency.currency.to_owned(), + oracle_id, + weightage: oracle.weightage, + block: oracle.block.clone(), + }; + + services + .oracle_token_currency + .by_id + .put(&oracle_token_currency.id, &oracle_token_currency)?; + } + } + } + Err(err) => { + eprintln!("Error remove_oracle invalidate : {:?}", err); + return Err(Error::from(err)); + } + } + + Ok(()) } } impl Index for UpdateOracle { - fn index(self, _services: &Arc, _ctx: &Context) -> Result<()> { - todo!() + fn index(self, services: &Arc, ctx: &Context) -> Result<()> { + let oracle_id = ctx.tx.txid; + let price_feeds_items: Vec = self + .price_feeds + .iter() + .map(|pair| PriceFeedsItem { + token: pair.token.clone(), + currency: pair.currency.clone(), + }) + .collect(); + + let oracle = Oracle { + id: oracle_id, + owner_address: self.script.to_hex_string(), + weightage: self.weightage, + price_feeds: price_feeds_items, + block: ctx.block.clone(), + }; + + //save oracle + services.oracle.by_id.put(&oracle.id, &oracle)?; + let previous_oracle_history_result = + get_previous_oracle_history_list(services, oracle_id.clone()); + match previous_oracle_history_result { + Ok(previous_oracle) => { + for oracle in previous_oracle { + for price_feed_item in &oracle.price_feeds { + // Assuming `oracle_id` is a field in `data` that you want to use for deletion + let deletion_key = ( + price_feed_item.token.clone(), + price_feed_item.currency.clone(), + oracle_id.clone(), + ); + match services.oracle_token_currency.by_id.delete(&deletion_key) { + Ok(_) => { + // Successfully deleted + } + Err(err) => { + let error_message = format!("Error:update oracle: {:?}", err); + eprintln!("{}", error_message); + return Err(Error::NotFound(NotFoundKind::Oracle)); + } + } + } + } + } + Err(err) => { + let error_message = format!("Error:update oracle: {:?}", err); + eprintln!("{}", error_message); + return Err(Error::NotFound(NotFoundKind::Oracle)); + } + } + + let prices_feeds = self.price_feeds.as_ref(); + //saving value in oracle_token_currency + for token_currency in prices_feeds { + let oracle_token_currency = OracleTokenCurrency { + id: ( + token_currency.token.clone(), + token_currency.currency.clone(), + oracle_id, + ), + key: ( + token_currency.token.clone(), + token_currency.currency.clone(), + ), + token: token_currency.token.clone(), + currency: token_currency.currency.clone(), + oracle_id: oracle_id.clone(), + weightage: self.weightage, + block: ctx.block.clone(), + }; + + services + .oracle_token_currency + .by_key + .put(&oracle_token_currency.key, &oracle_token_currency.id)?; + services + .oracle_token_currency + .by_id + .put(&oracle_token_currency.id, &oracle_token_currency)?; + } + + let oracle_history = OracleHistory { + id: (ctx.tx.txid, ctx.block.height, oracle_id), + oracle_id: ctx.tx.txid, + sort: format!( + "{}{}", + hex::encode(ctx.block.height.to_be_bytes()), + ctx.tx.txid + ), + owner_address: self.script.to_hex_string(), + weightage: self.weightage, + price_feeds: vec![], + block: ctx.block.clone(), + }; + //saving value in oracle_history + services + .oracle_history + .by_key + .put(&oracle_history.oracle_id, &oracle_history.id)?; + services + .oracle_history + .by_id + .put(&oracle_history.id, &oracle_history)?; + + Ok(()) } - fn invalidate(&self, _services: &Arc, _context: &Context) -> Result<()> { - todo!() + fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { + let oracle_id = context.tx.txid; + services.oracle_history.by_key.delete(&oracle_id)?; + services.oracle_history.by_id.delete(&( + oracle_id, + context.block.height, + context.tx.txid, + ))?; + + let prices_feeds = self.price_feeds.as_ref(); + for pair in prices_feeds { + services.oracle_token_currency.by_id.delete(&( + pair.token.to_string(), + pair.token.to_string(), + self.oracle_id, + ))?; + } + let previous_oracle_history_result = + get_previous_oracle_history_list(services, oracle_id.clone()); + match previous_oracle_history_result { + Ok(previous_oracle_result) => { + for previous_oracle in previous_oracle_result { + for price_feed_item in &previous_oracle.price_feeds { + let deletion_key = ( + price_feed_item.token.clone(), + price_feed_item.currency.clone(), + previous_oracle.oracle_id.clone(), + ); + + match services.oracle_token_currency.by_id.delete(&deletion_key) { + Ok(_) => { + // Successfully deleted + } + Err(err) => { + let error_message = + format!("Error updating oracle invalidate: {:?}", err); + eprintln!("{}", error_message); + return Err(Error::NotFound(NotFoundKind::Oracle)); + } + } + } + } + } + Err(err) => { + let error_message = format!("Error updating oracle invalidate: {:?}", err); + eprintln!("{}", error_message); + return Err(Error::NotFound(NotFoundKind::Oracle)); + } + } + Ok(()) } } impl Index for SetOracleData { - fn index(self, _services: &Arc, _ctx: &Context) -> Result<()> { - todo!() + fn index(self, services: &Arc, context: &Context) -> Result<()> { + let set_oracle_data = SetOracleData { + oracle_id: self.oracle_id, + timestamp: self.timestamp, + token_prices: self.token_prices, + }; + let feeds = map_price_feeds(vec![&set_oracle_data], vec![context])?; + let mut pairs: Vec<(String, String)> = Vec::new(); + for feed in feeds { + pairs.push((feed.token.clone(), feed.currency.clone())); + services.oracle_price_feed.by_key.put(&feed.key, &feed.id)?; + services.oracle_price_feed.by_id.put(&feed.id, &feed)?; + } + let intervals: Vec = vec![ + OracleIntervalSeconds::FifteenMinutes, + OracleIntervalSeconds::OneHour, + OracleIntervalSeconds::OneDay, + ]; + for (token, currency) in pairs.iter() { + let aggregated_value = map_price_aggregated(services, context, token, currency); + if let Ok(Some(value)) = aggregated_value { + let aggreated_id = ( + value.token.clone(), + value.currency.clone(), + value.block.height.clone(), + ); + let aggreated_key = (value.token.clone(), value.currency.clone()); + services + .oracle_price_aggregated + .by_id + .put(&aggreated_id, &value)?; + services + .oracle_price_aggregated + .by_key + .put(&aggreated_key, &aggreated_id)?; + + //SetOracleInterval + let aggregated = services.oracle_price_aggregated.by_id.get(&( + token.to_owned(), + currency.to_owned(), + context.block.height, + ))?; + for interval in intervals.clone() { + index_interval_mapper( + services, + &context.block, + token, + currency, + aggregated.as_ref().unwrap(), + &interval, + )?; + } + } + } + + Ok(()) + } + + fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { + let set_oracle_data = SetOracleData { + oracle_id: self.oracle_id, + timestamp: self.timestamp, + token_prices: CompactVec::from(Vec::new()), + }; + let intervals: Vec = vec![ + OracleIntervalSeconds::FifteenMinutes, + OracleIntervalSeconds::OneHour, + OracleIntervalSeconds::OneDay, + ]; + let feeds = map_price_feeds(vec![&set_oracle_data], vec![context])?; + let mut pairs: Vec<(String, String)> = Vec::new(); + for feed in feeds { + pairs.push((feed.token.clone(), feed.currency.clone())); + services.oracle_price_feed.by_key.delete(&feed.key)?; + services.oracle_price_feed.by_id.delete(&feed.id)?; + } + for (token, currency) in pairs.iter() { + let aggreated_id = (token.to_owned(), currency.to_owned(), context.block.height); + let aggregated_price = services.oracle_price_aggregated.by_id.get(&aggreated_id)?; + if let Some(aggregated) = aggregated_price { + for interval in &intervals { + let err = invalidate_oracle_interval( + services, + &context.block, + token, + currency, + &aggregated, + interval, + ); + } + } + services + .oracle_price_aggregated + .by_id + .delete(&aggreated_id)?; + } + Ok(()) + } +} + +pub fn map_price_aggregated( + services: &Arc, + ctx: &Context, + token: &str, + currency: &str, +) -> Result> { + let key = (token.to_string(), currency.to_string()); + let oracle_token_currency = services + .oracle_token_currency + .by_key + .list(Some(key), SortOrder::Descending)? + .map(|item| { + let (_, id) = item?; + let b = services + .oracle_token_currency + .by_id + .get(&id)? + .ok_or("Error mapping price aggregated index")?; + + Ok(b) + }) + .collect::>>()?; + + let result = oracle_token_currency; + let mut aggregated = OraclePriceAggregatedAggregated { + amount: "0".to_string(), + weightage: 0, + oracles: OraclePriceAggregatedAggregatedOracles { + active: 0, + total: 0, + }, + }; + + for oracle in result { + if oracle.weightage == 0 { + continue; + } + + let key = (token.to_string(), currency.to_string(), oracle.oracle_id); + let feed_id = services.oracle_price_feed.by_key.get(&key); + + let feeds = match feed_id { + Ok(feed_ids) => feed_ids.map_or_else( + || Ok(None), + |id| { + services + .oracle_price_feed + .by_id + .get(&id) + .map(|data| Some(data)) + }, + ), + Err(err) => { + println!("the err {:?}", err); + Err(err) + } + }; + + let oracle_price_feed: Option = match feeds { + Ok(Some(Some(feed))) => Some(feed), + _ => None, + }; + + if oracle_price_feed.is_none() { + continue; + } + + if let Some(oracle_price_feed) = oracle_price_feed { + if (oracle_price_feed.time - ctx.block.time as i32) < 3600 { + aggregated.oracles.active += 1; + aggregated.weightage += oracle.weightage as i32; + let amount = oracle_price_feed.amount; + let weighted_amount = amount * oracle.weightage as i64; + if let Ok(current_amount) = aggregated.amount.parse::() { + aggregated.amount = (current_amount + weighted_amount).to_string(); + } + } + } else { + continue; + } + } + + if aggregated.oracles.active == 0 { + return Ok(None); + }; + + Ok(Some(OraclePriceAggregated { + id: (token.to_string(), currency.to_string(), ctx.block.height), + key: (token.to_string(), currency.to_string()), + sort: format!( + "{}{}", + hex::encode(ctx.block.median_time.to_be_bytes()), + hex::encode(ctx.block.height.to_be_bytes()) + ), + token: token.to_string(), + currency: currency.to_string(), + aggregated, + block: ctx.block.clone(), + })) +} + +pub fn map_price_feeds( + set_oracle_data: Vec<&SetOracleData>, + context: Vec<&Context>, +) -> Result> { + let mut result: Vec = Vec::new(); + for (idx, ctx) in context.into_iter().enumerate() { + // Use indexing to access elements in set_oracle_data + let set_data = set_oracle_data[idx]; + let token_prices = set_data.token_prices.as_ref(); + for token_price in token_prices { + for token_amount in token_price.prices.as_ref() { + let oracle_price_feed = OraclePriceFeed { + id: ( + token_price.token.clone(), + token_amount.currency.clone(), + set_data.oracle_id, + ctx.tx.txid, + ), + + key: ( + token_price.token.clone(), + token_amount.currency.clone(), + set_data.oracle_id, + ), + sort: hex::encode(ctx.block.height.to_string() + &ctx.tx.txid.to_string()), + amount: token_amount.amount, + currency: token_amount.currency.clone(), + block: ctx.block.clone(), + oracle_id: set_data.oracle_id, + time: set_data.timestamp as i32, + token: token_price.token.clone(), + txid: ctx.tx.txid, + }; + + result.push(oracle_price_feed); + } + } + } + Ok(result) +} + +pub fn index_interval_mapper( + services: &Arc, + block: &BlockContext, + token: &str, + currency: &str, + aggregated: &OraclePriceAggregated, + interval: &OracleIntervalSeconds, +) -> Result<()> { + let previous_aggrigated_interval = services + .oracle_price_aggregated_interval + .by_key + .list( + Some((token.to_owned(), currency.to_owned(), interval.clone())), + SortOrder::Descending, + )? + .take(1) + .map(|item| { + let (_, id) = item?; + let price_agrregated_interval = services + .oracle_price_aggregated_interval + .by_id + .get(&id)? + .ok_or("Missing oracle price aggregated interval index")?; + Ok(price_agrregated_interval) + }) + .collect::>>(); + + for previous_oracle_price_aggreated in previous_aggrigated_interval { + let clone_interval = interval.clone(); + if previous_oracle_price_aggreated.len() != 0 + || (block.median_time - previous_oracle_price_aggreated[0].block.median_time.clone()) + > clone_interval as i64 + { + let oracle_price_aggregated_interval = OraclePriceAggregatedInterval { + id: ( + token.to_owned(), + currency.to_owned(), + interval.clone(), + block.height, + ), + key: (token.to_owned(), currency.to_owned(), interval.clone()), + sort: aggregated.sort.to_owned(), + token: token.to_owned(), + currency: currency.to_owned(), + aggregated: previous_oracle_price_aggreated[0].aggregated.clone(), + block: block.clone(), + }; + let err = services.oracle_price_aggregated_interval.by_id.put( + &oracle_price_aggregated_interval.id, + &oracle_price_aggregated_interval, + ); + let err = services.oracle_price_aggregated_interval.by_key.put( + &oracle_price_aggregated_interval.key, + &oracle_price_aggregated_interval.id, + ); + } else { + process_inner_values(&services, &previous_oracle_price_aggreated[0], aggregated); + } } - fn invalidate(&self, _services: &Arc, _context: &Context) -> Result<()> { - todo!() + Ok(()) +} + +pub fn invalidate_oracle_interval( + services: &Arc, + block: &BlockContext, + token: &str, + currency: &str, + aggregated: &OraclePriceAggregated, + interval: &OracleIntervalSeconds, +) -> Result<()> { + let previous_aggrigated_interval = services + .oracle_price_aggregated_interval + .by_key + .list( + Some((token.to_owned(), currency.to_owned(), interval.clone())), + SortOrder::Descending, + )? + .take(1) + .map(|item| { + let (_, id) = item?; + let price_agrregated_interval = services + .oracle_price_aggregated_interval + .by_id + .get(&id)? + .ok_or("Missing oracle price aggregated interval index")?; + Ok(price_agrregated_interval) + }) + .collect::>>(); + + for oracle_price_aggreated in previous_aggrigated_interval { + if oracle_price_aggreated[0].aggregated.count != 1 { + let err = services + .oracle_price_aggregated_interval + .by_id + .delete(&oracle_price_aggreated[0].id); + } else { + let lastprice = oracle_price_aggreated[0].aggregated.clone(); + let count = lastprice.count - 1; + let previous_aggregated_interval = OraclePriceAggregatedInterval { + id: oracle_price_aggreated[0].id.clone(), + key: oracle_price_aggreated[0].key.clone(), + sort: oracle_price_aggreated[0].sort.clone(), + token: oracle_price_aggreated[0].token.clone(), + currency: oracle_price_aggreated[0].currency.clone(), + aggregated: OraclePriceAggregatedIntervalAggregated { + amount: backward_aggregate_value( + lastprice.amount.as_str(), + &aggregated.aggregated.amount.to_string(), + count as u32, + ) + .to_string(), + weightage: backward_aggregate_number( + lastprice.weightage, + aggregated.aggregated.weightage, + count as u32, + ), + count, + oracles: OraclePriceAggregatedIntervalAggregatedOracles { + active: backward_aggregate_number( + lastprice.oracles.active, + aggregated.aggregated.oracles.active, + lastprice.count as u32, + ) as i32, + total: backward_aggregate_number( + lastprice.oracles.total, + aggregated.aggregated.oracles.total, + lastprice.count as u32, + ), + }, + }, + block: oracle_price_aggreated[0].block.clone(), + }; + let err = services.oracle_price_aggregated_interval.by_id.put( + &previous_aggregated_interval.id, + &previous_aggregated_interval, + ); + let err = services.oracle_price_aggregated_interval.by_key.put( + &previous_aggregated_interval.key, + &previous_aggregated_interval.id, + ); + } } + Ok(()) +} + +fn process_inner_values( + services: &Arc, + previous_data: &OraclePriceAggregatedInterval, + aggregated: &OraclePriceAggregated, +) { + let lastprice = previous_data.aggregated.clone(); + let count = lastprice.count + 1; + + let aggregated_interval = OraclePriceAggregatedInterval { + id: previous_data.id.clone(), + key: previous_data.key.clone(), + sort: previous_data.sort.clone(), + token: previous_data.token.clone(), + currency: previous_data.currency.clone(), + aggregated: OraclePriceAggregatedIntervalAggregated { + amount: forward_aggregate_value( + lastprice.amount.as_str(), + aggregated.aggregated.amount.as_str(), + count, + ) + .to_string(), + weightage: forward_aggregate_number( + lastprice.weightage, + aggregated.aggregated.weightage, + count, + ), + count, + oracles: OraclePriceAggregatedIntervalAggregatedOracles { + active: forward_aggregate_number( + lastprice.oracles.active, + aggregated.aggregated.oracles.active, + lastprice.count, + ) as i32, + total: forward_aggregate_number( + lastprice.oracles.total, + aggregated.aggregated.oracles.total, + lastprice.count, + ), + }, + }, + block: previous_data.block.clone(), + }; + let err = services + .oracle_price_aggregated_interval + .by_id + .put(&aggregated_interval.id, &aggregated_interval); + let err = services + .oracle_price_aggregated_interval + .by_key + .put(&aggregated_interval.key, &aggregated_interval.id); +} + +fn forward_aggregate_number(last_value: i32, new_value: i32, count: i32) -> i32 { + let count_decimal = Decimal::from(count); + let last_value_decimal = Decimal::from(last_value); + let new_value_decimal = Decimal::from(new_value); + + let result = (last_value_decimal * count_decimal + new_value_decimal) + / (count_decimal + Decimal::from(1)); + + result.to_i32().unwrap_or_else(|| { + eprintln!("Result is too large to fit into i32, returning 0"); + i32::MAX + }) +} + +fn forward_aggregate_value(last_value: &str, new_value: &str, count: i32) -> Decimal { + let last_decimal = Decimal::from_str(last_value).unwrap(); + let new_decimal = Decimal::from_str(new_value).unwrap(); + let count_decimal = Decimal::from(count); + + let result = last_decimal * count_decimal + new_decimal; + result / (count_decimal + Decimal::from(1)) +} + +fn backward_aggregate_value(last_value: &str, new_value: &str, count: u32) -> Decimal { + let last_value_decimal = Decimal::from_str(last_value).unwrap_or_else(|_| Decimal::zero()); + let new_value_decimal = Decimal::from_str(new_value).unwrap_or_else(|_| Decimal::zero()); + let count_decimal = Decimal::from(count); + + (last_value_decimal * count_decimal.clone() - new_value_decimal) + / (count_decimal - Decimal::from(1)) +} + +fn backward_aggregate_number(last_value: i32, new_value: i32, count: u32) -> i32 { + let last_value_decimal = + Decimal::from_str(&last_value.to_string()).unwrap_or_else(|_| Decimal::zero()); + let new_value_decimal = + Decimal::from_str(&new_value.to_string()).unwrap_or_else(|_| Decimal::zero()); + let count_decimal = Decimal::from(count); + + let result = (last_value_decimal * count_decimal.clone() - new_value_decimal) + / (count_decimal - Decimal::from(1)); + + result.to_i32().unwrap_or_else(|| { + eprintln!("Result is too large to fit into i32, returning 0"); + 0 + }) +} + +fn get_previous_oracle_history_list( + services: &Arc, + oracle_id: Txid, +) -> std::result::Result, Box> { + let history = services + .oracle_history + .by_key + .list(Some(oracle_id), SortOrder::Descending)? + .map(|item| { + let (_, id) = item?; + let b = services + .oracle_history + .by_id + .get(&id)? + .ok_or("Missing oracle previous history index")?; + + Ok(b) + }) + .collect::, Box>>()?; + Ok(history) } diff --git a/lib/ain-ocean/src/indexer/oracle_test.rs b/lib/ain-ocean/src/indexer/oracle_test.rs new file mode 100644 index 00000000000..5b659ef7896 --- /dev/null +++ b/lib/ain-ocean/src/indexer/oracle_test.rs @@ -0,0 +1,91 @@ +#[cfg(test)] +mod tests { + use std::{str::FromStr, sync::Arc}; + + use ain_dftx::{common::CompactVec, price::CurrencyPair, types::oracles::AppointOracle}; + use bitcoin::{BlockHash, ScriptBuf, Txid}; + use defichain_rpc::json::blockchain::{Block, Transaction}; + use tempfile::tempdir; + + use super::*; + use crate::{ + indexer::{Context, Index}, + model::BlockContext, + storage::ocean_store, + Services, + }; + + #[test] + fn test_index_appoint_oracle() { + let temp_dir = tempdir().expect("Failed to create temporary directory"); + let path = temp_dir.path(); + let ocean_store_result = ocean_store::OceanStore::new(path); + let ocean_store = match ocean_store_result { + Ok(ocean_store) => Arc::new(ocean_store), + Err(error) => { + panic!("Failed to create OceanStore: {}", error); + } + }; + + let services = Arc::new(Services::new(ocean_store)); + + let block_context = BlockContext { + hash: BlockHash::from_str( + "0000000000000000000076b72aeedd65368d07d945a6321916a7e8fc4e3babb0", + ) + .unwrap(), + height: 10, + time: 123456789, + median_time: 123456789, + }; + + let transaction = Transaction { + txid: Txid::from_str( + "f42b38ac12e3fafc96ba1a9ba70cbfe326744aef75df5fb9db5d6e2855ca415f", + ) + .unwrap(), + hash: "transaction_hash".to_string(), + version: 1, + size: 100, + vsize: 90, + weight: 80, + locktime: 0, + vin: vec![], + vout: vec![], + hex: "transaction_hex".to_string(), + }; + + let appoint_oracle = AppointOracle { + script: ScriptBuf::default(), // Provide a valid script + weightage: 1, + price_feeds: CompactVec::from(vec![ + CurrencyPair { + token: "BTC".to_string(), + currency: "USD".to_string(), + }, + CurrencyPair { + token: "ETH".to_string(), + currency: "USD".to_string(), + }, + ]), + }; + let ctx = &Context { + block: block_context, + tx: transaction, + tx_idx: 2, + }; + let result = appoint_oracle.index(&services, ctx); + assert!(result.is_ok()); + // Add assertions to check if data is stored correctly in the database + } + + #[test] + fn test_index_with_invalid_input() { + // Test with invalid input data, like an empty script or invalid weightage + } + + #[test] + fn test_index_error_handling() { + // Test error handling scenarios, like database errors + } +} diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 57fa29993e6..ca792712aa4 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -5,12 +5,21 @@ use std::{path::PathBuf, sync::Arc}; pub use api::ocean_router; use error::Error; -pub use indexer::{index_block, invalidate_block, transaction::index_transaction, tx_result}; +pub use indexer::{ + index_block, invalidate_block, oracle::invalidate_oracle_interval, + transaction::index_transaction, tx_result, +}; use repository::{ AuctionHistoryByHeightRepository, AuctionHistoryRepository, BlockByHeightRepository, BlockRepository, MasternodeByHeightRepository, MasternodeRepository, MasternodeStatsRepository, - PoolSwapRepository, RawBlockRepository, TransactionByBlockHashRepository, - TransactionRepository, TransactionVinRepository, TransactionVoutRepository, TxResultRepository, + OracleHistoryRepository, OracleHistoryRepositoryKey, OraclePriceActiveKeyRepository, + OraclePriceActiveRepository, OraclePriceAggregatedIntervalKeyRepository, + OraclePriceAggregatedIntervalRepository, OraclePriceAggregatedRepository, + OraclePriceAggregatedRepositorykey, OraclePriceFeedKeyRepository, OraclePriceFeedRepository, + OracleRepository, OracleTokenCurrencyKeyRepository, OracleTokenCurrencyRepository, + PoolSwapRepository, PriceTickerRepository, RawBlockRepository, + TransactionByBlockHashRepository, TransactionRepository, TransactionVinRepository, + TransactionVoutRepository, TxResultRepository, }; pub mod api; mod model; @@ -59,6 +68,40 @@ pub struct TransactionService { vout_by_id: TransactionVoutRepository, } +pub struct OracleService { + by_id: OracleRepository, +} +pub struct OraclePriceFeedService { + by_key: OraclePriceFeedKeyRepository, + by_id: OraclePriceFeedRepository, +} +pub struct OraclePriceActiveService { + by_key: OraclePriceActiveKeyRepository, + by_id: OraclePriceActiveRepository, +} +pub struct OraclePriceAggregatedIntervalService { + by_key: OraclePriceAggregatedIntervalKeyRepository, + by_id: OraclePriceAggregatedIntervalRepository, +} +pub struct OraclePriceAggregatedService { + by_key: OraclePriceAggregatedRepositorykey, + by_id: OraclePriceAggregatedRepository, +} + +pub struct OracleTokenCurrencyService { + by_key: OracleTokenCurrencyKeyRepository, + by_id: OracleTokenCurrencyRepository, +} + +pub struct OracleHistoryService { + by_id: OracleHistoryRepository, + by_key: OracleHistoryRepositoryKey, +} + +pub struct PriceTickerService { + by_id: PriceTickerRepository, +} + pub struct Services { pub masternode: MasternodeService, pub block: BlockService, @@ -66,6 +109,14 @@ pub struct Services { pub result: TxResultRepository, pub pool: PoolService, pub transaction: TransactionService, + pub oracle: OracleService, + pub oracle_price_feed: OraclePriceFeedService, + pub oracle_price_active: OraclePriceActiveService, + pub oracle_price_aggregated_interval: OraclePriceAggregatedIntervalService, + pub oracle_price_aggregated: OraclePriceAggregatedService, + pub oracle_token_currency: OracleTokenCurrencyService, + pub oracle_history: OracleHistoryService, + pub price_ticker: PriceTickerService, } impl Services { @@ -95,6 +146,36 @@ impl Services { vin_by_id: TransactionVinRepository::new(Arc::clone(&store)), vout_by_id: TransactionVoutRepository::new(Arc::clone(&store)), }, + oracle: OracleService { + by_id: OracleRepository::new(Arc::clone(&store)), + }, + oracle_price_feed: OraclePriceFeedService { + by_key: OraclePriceFeedKeyRepository::new(Arc::clone(&store)), + by_id: OraclePriceFeedRepository::new(Arc::clone(&store)), + }, + oracle_price_active: OraclePriceActiveService { + by_key: OraclePriceActiveKeyRepository::new(Arc::clone(&store)), + by_id: OraclePriceActiveRepository::new(Arc::clone(&store)), + }, + oracle_price_aggregated_interval: OraclePriceAggregatedIntervalService { + by_key: OraclePriceAggregatedIntervalKeyRepository::new(Arc::clone(&store)), + by_id: OraclePriceAggregatedIntervalRepository::new(Arc::clone(&store)), + }, + oracle_price_aggregated: OraclePriceAggregatedService { + by_key: OraclePriceAggregatedRepositorykey::new(Arc::clone(&store)), + by_id: OraclePriceAggregatedRepository::new(Arc::clone(&store)), + }, + oracle_token_currency: OracleTokenCurrencyService { + by_key: OracleTokenCurrencyKeyRepository::new(Arc::clone(&store)), + by_id: OracleTokenCurrencyRepository::new(Arc::clone(&store)), + }, + oracle_history: OracleHistoryService { + by_id: OracleHistoryRepository::new(Arc::clone(&store)), + by_key: OracleHistoryRepositoryKey::new(Arc::clone(&store)), + }, + price_ticker: PriceTickerService { + by_id: PriceTickerRepository::new(Arc::clone(&store)), + }, } } } diff --git a/lib/ain-ocean/src/model/mod.rs b/lib/ain-ocean/src/model/mod.rs index 276ed46dae2..869df512ce8 100644 --- a/lib/ain-ocean/src/model/mod.rs +++ b/lib/ain-ocean/src/model/mod.rs @@ -1,7 +1,7 @@ mod block; mod masternode; mod masternode_stats; -mod oracle; +pub mod oracle; mod oracle_history; mod oracle_price_active; mod oracle_price_aggregated; @@ -11,6 +11,7 @@ mod oracle_token_currency; mod poolswap; mod poolswap_aggregated; mod price_ticker; +mod prices; mod raw_block; mod script_activity; mod script_aggregation; @@ -20,24 +21,24 @@ mod transaction_vin; mod transaction_vout; mod tx_result; mod vault_auction_batch_history; - pub use block::*; pub use masternode::*; pub use masternode_stats::*; -// pub use oracle::*; -// pub use oracle_history::*; -// pub use oracle_price_active::*; -// pub use oracle_price_aggregated::*; -// pub use oracle_price_aggregated_interval::*; -// pub use oracle_price_feed::*; -// pub use oracle_token_currency::*; +pub use oracle::*; +pub use oracle_history::*; +pub use oracle_price_active::*; +pub use oracle_price_aggregated::*; +pub use oracle_price_aggregated_interval::*; +pub use oracle_price_feed::*; +pub use oracle_token_currency::*; pub use poolswap::*; -// pub use poolswap_aggregated::*; -// pub use price_ticker::*; -// pub use raw_block::*; -// pub use script_activity::*; -// pub use script_aggregation::*; -// pub use script_unspent::*; +pub use poolswap_aggregated::*; +pub use price_ticker::*; +pub use prices::*; +pub use raw_block::*; +pub use script_activity::*; +pub use script_aggregation::*; +pub use script_unspent::*; pub use transaction::*; pub use transaction_vin::*; pub use transaction_vout::*; diff --git a/lib/ain-ocean/src/model/oracle.rs b/lib/ain-ocean/src/model/oracle.rs index d9892b23c30..e5cfac3bc33 100644 --- a/lib/ain-ocean/src/model/oracle.rs +++ b/lib/ain-ocean/src/model/oracle.rs @@ -1,3 +1,4 @@ +use bitcoin::Txid; use serde::{Deserialize, Serialize}; use super::BlockContext; @@ -5,14 +6,14 @@ use super::BlockContext; #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Oracle { - pub id: String, + pub id: Txid, pub owner_address: String, - pub weightage: i32, + pub weightage: u8, pub price_feeds: Vec, pub block: BlockContext, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct PriceFeedsItem { pub token: String, diff --git a/lib/ain-ocean/src/model/oracle_history.rs b/lib/ain-ocean/src/model/oracle_history.rs index faa93b373cb..bcc7a4dcfda 100644 --- a/lib/ain-ocean/src/model/oracle_history.rs +++ b/lib/ain-ocean/src/model/oracle_history.rs @@ -1,22 +1,19 @@ +use bitcoin::Txid; use serde::{Deserialize, Serialize}; use super::BlockContext; +use crate::model::oracle::PriceFeedsItem; -#[derive(Serialize, Deserialize, Debug)] +pub type OracleHistoryId = (Txid, u32, Txid); //oracleId-height-txid + +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct OracleHistory { - pub id: String, - pub oracle_id: String, - pub sort: String, + pub id: OracleHistoryId, + pub oracle_id: Txid, + pub sort: String, // height-txid pub owner_address: String, - pub weightage: i32, + pub weightage: u8, pub price_feeds: Vec, pub block: BlockContext, } - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(rename_all = "camelCase")] -pub struct PriceFeedsItem { - pub token: String, - pub currency: String, -} diff --git a/lib/ain-ocean/src/model/oracle_price_active.rs b/lib/ain-ocean/src/model/oracle_price_active.rs index 3f5b74a4ac8..47b234342b6 100644 --- a/lib/ain-ocean/src/model/oracle_price_active.rs +++ b/lib/ain-ocean/src/model/oracle_price_active.rs @@ -2,12 +2,14 @@ use serde::{Deserialize, Serialize}; use super::BlockContext; +pub type OraclePriceActiveId = (String, String, u32); //token-currency-height +pub type OraclePriceActiveKey = (String, String); //token-currency #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OraclePriceActive { - pub id: String, - pub key: String, - pub sort: String, + pub id: OraclePriceActiveId, + pub key: OraclePriceActiveKey, + pub sort: String, //height pub active: OraclePriceActiveActive, pub next: OraclePriceActiveNext, pub is_live: bool, diff --git a/lib/ain-ocean/src/model/oracle_price_aggregated.rs b/lib/ain-ocean/src/model/oracle_price_aggregated.rs index df0db13821c..539eb3c43d0 100644 --- a/lib/ain-ocean/src/model/oracle_price_aggregated.rs +++ b/lib/ain-ocean/src/model/oracle_price_aggregated.rs @@ -1,12 +1,13 @@ use serde::{Deserialize, Serialize}; use super::BlockContext; - -#[derive(Serialize, Deserialize, Debug)] +pub type OraclePriceAggregatedId = (String, String, u32); //token-currency-height +pub type OraclePriceAggregatedKey = (String, String); //token-currency +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregated { - pub id: String, - pub key: String, + pub id: OraclePriceAggregatedId, + pub key: OraclePriceAggregatedKey, pub sort: String, pub token: String, pub currency: String, @@ -14,7 +15,7 @@ pub struct OraclePriceAggregated { pub block: BlockContext, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedAggregated { pub amount: String, @@ -22,7 +23,7 @@ pub struct OraclePriceAggregatedAggregated { pub oracles: OraclePriceAggregatedAggregatedOracles, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedAggregatedOracles { pub active: i32, diff --git a/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs index 8380e7faee1..6c36c769330 100644 --- a/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs +++ b/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs @@ -1,12 +1,25 @@ use serde::{Deserialize, Serialize}; use super::BlockContext; +pub type OraclePriceAggregatedIntervalId = (String, String, OracleIntervalSeconds, u32); //token-currency-interval-height +pub type OraclePriceAggregatedIntervalKey = (String, String, OracleIntervalSeconds); //token-currency-interval -#[derive(Serialize, Deserialize, Debug)] +pub const FIFTEEN_MINUTES: isize = 15 * 60; +pub const ONE_HOUR: isize = 60 * 60; +pub const ONE_DAY: isize = 24 * 60 * 60; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum OracleIntervalSeconds { + FifteenMinutes = FIFTEEN_MINUTES, + OneHour = ONE_HOUR, + OneDay = ONE_DAY, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedInterval { - pub id: String, - pub key: String, + pub id: OraclePriceAggregatedIntervalId, + pub key: OraclePriceAggregatedIntervalKey, pub sort: String, pub token: String, pub currency: String, @@ -14,7 +27,7 @@ pub struct OraclePriceAggregatedInterval { pub block: BlockContext, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedIntervalAggregated { pub amount: String, @@ -23,7 +36,7 @@ pub struct OraclePriceAggregatedIntervalAggregated { pub oracles: OraclePriceAggregatedIntervalAggregatedOracles, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedIntervalAggregatedOracles { pub active: i32, diff --git a/lib/ain-ocean/src/model/oracle_price_feed.rs b/lib/ain-ocean/src/model/oracle_price_feed.rs index 2ff21dc1add..55451533647 100644 --- a/lib/ain-ocean/src/model/oracle_price_feed.rs +++ b/lib/ain-ocean/src/model/oracle_price_feed.rs @@ -1,18 +1,20 @@ +use bitcoin::Txid; use serde::{Deserialize, Serialize}; use super::BlockContext; - +pub type OraclePriceFeedId = (String, String, Txid, Txid); // token-currency-oracle_id-txid +pub type OraclePriceFeedkey = (String, String, Txid); // token-currency-oracle_id #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OraclePriceFeed { - pub id: String, - pub key: String, + pub id: OraclePriceFeedId, + pub key: OraclePriceFeedkey, pub sort: String, pub token: String, pub currency: String, - pub oracle_id: String, - pub txid: String, + pub oracle_id: Txid, + pub txid: Txid, pub time: i32, - pub amount: String, + pub amount: i64, pub block: BlockContext, } diff --git a/lib/ain-ocean/src/model/oracle_token_currency.rs b/lib/ain-ocean/src/model/oracle_token_currency.rs index c04a83d0a94..decfaa2d89a 100644 --- a/lib/ain-ocean/src/model/oracle_token_currency.rs +++ b/lib/ain-ocean/src/model/oracle_token_currency.rs @@ -1,15 +1,17 @@ +use bitcoin::Txid; use serde::{Deserialize, Serialize}; use super::BlockContext; - +pub type OracleTokenCurrencyId = (String, String, Txid); //token-currency-oracleId +pub type OracleTokenCurrencyKey = (String, String); //token-currency #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OracleTokenCurrency { - pub id: String, - pub key: String, + pub id: OracleTokenCurrencyId, + pub key: OracleTokenCurrencyKey, pub token: String, pub currency: String, - pub oracle_id: String, - pub weightage: i32, + pub oracle_id: Txid, + pub weightage: u8, pub block: BlockContext, } diff --git a/lib/ain-ocean/src/model/price_ticker.rs b/lib/ain-ocean/src/model/price_ticker.rs index 9767dbedc37..2a4a6cfcdfc 100644 --- a/lib/ain-ocean/src/model/price_ticker.rs +++ b/lib/ain-ocean/src/model/price_ticker.rs @@ -2,9 +2,11 @@ use serde::{Deserialize, Serialize}; use super::oracle_price_aggregated::OraclePriceAggregated; -#[derive(Debug, Serialize, Deserialize)] +pub type PriceTickerId = (String, String); //token-currency +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] pub struct PriceTicker { - pub id: String, - pub sort: String, + pub id: PriceTickerId, //token-currency + pub sort: String, //count-height-token-currency pub price: OraclePriceAggregated, } diff --git a/lib/ain-ocean/src/model/prices.rs b/lib/ain-ocean/src/model/prices.rs new file mode 100644 index 00000000000..10c555b27a5 --- /dev/null +++ b/lib/ain-ocean/src/model/prices.rs @@ -0,0 +1,14 @@ +use serde::{Deserialize, Serialize}; + +use super::{BlockContext, OraclePriceFeed}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct PriceOracles { + pub id: String, + pub key: String, + pub token: String, + pub currency: String, + pub oracle_id: String, + pub feed: OraclePriceFeed, + pub block: BlockContext, +} diff --git a/lib/ain-ocean/src/repository/mod.rs b/lib/ain-ocean/src/repository/mod.rs index 03ae76abcd9..26401c21b9b 100644 --- a/lib/ain-ocean/src/repository/mod.rs +++ b/lib/ain-ocean/src/repository/mod.rs @@ -3,6 +3,8 @@ use crate::{storage::SortOrder, Result}; mod block; mod masternode; mod masternode_stats; +mod oracle; +mod oracle_history; mod oracle_price_active; mod oracle_price_aggregated; mod oracle_price_aggregated_interval; @@ -24,14 +26,16 @@ mod vault_auction_batch_history; pub use block::*; pub use masternode::*; pub use masternode_stats::*; -// pub use oracle_price_active::*; -// pub use oracle_price_aggregated::*; -// pub use oracle_price_aggregated_interval::*; -// pub use oracle_price_feed::*; -// pub use oracle_token_currency::*; +pub use oracle::*; +pub use oracle_history::*; +pub use oracle_price_active::*; +pub use oracle_price_aggregated::*; +pub use oracle_price_aggregated_interval::*; +pub use oracle_price_feed::*; +pub use oracle_token_currency::*; pub use pool_swap::*; // pub use pool_swap_aggregated::*; -// pub use price_ticker::*; +pub use price_ticker::*; pub use raw_block::*; // pub use script_activity::*; // pub use script_aggregation::*; diff --git a/lib/ain-ocean/src/repository/oracle.rs b/lib/ain-ocean/src/repository/oracle.rs new file mode 100644 index 00000000000..15ff392b05b --- /dev/null +++ b/lib/ain-ocean/src/repository/oracle.rs @@ -0,0 +1,28 @@ +use std::sync::Arc; + +use ain_db::LedgerColumn; +use ain_macros::Repository; +use bitcoin::Txid; + +use super::RepositoryOps; +use crate::{ + model::Oracle, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "Txid", V = "Oracle")] +pub struct OracleRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl OracleRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} diff --git a/lib/ain-ocean/src/repository/oracle_history.rs b/lib/ain-ocean/src/repository/oracle_history.rs new file mode 100644 index 00000000000..8b6aa45c14b --- /dev/null +++ b/lib/ain-ocean/src/repository/oracle_history.rs @@ -0,0 +1,43 @@ +use std::sync::Arc; + +use ain_db::LedgerColumn; +use ain_macros::Repository; +use bitcoin::Txid; + +use super::RepositoryOps; +use crate::{ + model::{OracleHistory, OracleHistoryId}, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "OracleHistoryId", V = "OracleHistory")] +pub struct OracleHistoryRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl OracleHistoryRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} +#[derive(Repository)] +#[repository(K = "Txid", V = "OracleHistoryId")] +pub struct OracleHistoryRepositoryKey { + pub store: Arc, + col: LedgerColumn, +} + +impl OracleHistoryRepositoryKey { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} diff --git a/lib/ain-ocean/src/repository/oracle_price_active.rs b/lib/ain-ocean/src/repository/oracle_price_active.rs index 8b137891791..367a6a3a562 100644 --- a/lib/ain-ocean/src/repository/oracle_price_active.rs +++ b/lib/ain-ocean/src/repository/oracle_price_active.rs @@ -1 +1,43 @@ +use std::sync::Arc; +use ain_db::LedgerColumn; +use ain_macros::Repository; + +use super::RepositoryOps; +use crate::{ + model::{OraclePriceActive, OraclePriceActiveId, OraclePriceActiveKey}, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "OraclePriceActiveId", V = "OraclePriceActive")] +pub struct OraclePriceActiveRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl OraclePriceActiveRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} + +#[derive(Repository)] +#[repository(K = "OraclePriceActiveKey", V = "OraclePriceActiveId")] +pub struct OraclePriceActiveKeyRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl OraclePriceActiveKeyRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} diff --git a/lib/ain-ocean/src/repository/oracle_price_aggregated.rs b/lib/ain-ocean/src/repository/oracle_price_aggregated.rs index 8b137891791..3b8d9b926d1 100644 --- a/lib/ain-ocean/src/repository/oracle_price_aggregated.rs +++ b/lib/ain-ocean/src/repository/oracle_price_aggregated.rs @@ -1 +1,43 @@ +use std::sync::Arc; +use ain_db::LedgerColumn; +use ain_macros::Repository; + +use super::RepositoryOps; +use crate::{ + model::{OraclePriceAggregated, OraclePriceAggregatedId, OraclePriceAggregatedKey}, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "OraclePriceAggregatedId", V = "OraclePriceAggregated")] +pub struct OraclePriceAggregatedRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl OraclePriceAggregatedRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} + +#[derive(Repository)] +#[repository(K = "OraclePriceAggregatedKey", V = "OraclePriceAggregatedId")] +pub struct OraclePriceAggregatedRepositorykey { + pub store: Arc, + col: LedgerColumn, +} + +impl OraclePriceAggregatedRepositorykey { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} diff --git a/lib/ain-ocean/src/repository/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/repository/oracle_price_aggregated_interval.rs index 8b137891791..95aa9180d6c 100644 --- a/lib/ain-ocean/src/repository/oracle_price_aggregated_interval.rs +++ b/lib/ain-ocean/src/repository/oracle_price_aggregated_interval.rs @@ -1 +1,52 @@ +use std::sync::Arc; +use ain_db::LedgerColumn; +use ain_macros::Repository; + +use super::RepositoryOps; +use crate::{ + model::{ + OraclePriceAggregatedInterval, OraclePriceAggregatedIntervalId, + OraclePriceAggregatedIntervalKey, + }, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository( + K = "OraclePriceAggregatedIntervalId", + V = "OraclePriceAggregatedInterval" +)] +pub struct OraclePriceAggregatedIntervalRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl OraclePriceAggregatedIntervalRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} + +#[derive(Repository)] +#[repository( + K = "OraclePriceAggregatedIntervalKey", + V = "OraclePriceAggregatedIntervalId" +)] +pub struct OraclePriceAggregatedIntervalKeyRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl OraclePriceAggregatedIntervalKeyRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} diff --git a/lib/ain-ocean/src/repository/oracle_price_feed.rs b/lib/ain-ocean/src/repository/oracle_price_feed.rs index 8b137891791..dbeddeabed7 100644 --- a/lib/ain-ocean/src/repository/oracle_price_feed.rs +++ b/lib/ain-ocean/src/repository/oracle_price_feed.rs @@ -1 +1,43 @@ +use std::sync::Arc; +use ain_db::LedgerColumn; +use ain_macros::Repository; + +use super::RepositoryOps; +use crate::{ + model::{OraclePriceFeed, OraclePriceFeedId, OraclePriceFeedkey}, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "OraclePriceFeedId", V = "OraclePriceFeed")] +pub struct OraclePriceFeedRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl OraclePriceFeedRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} + +#[derive(Repository)] +#[repository(K = "OraclePriceFeedkey", V = "OraclePriceFeedId")] +pub struct OraclePriceFeedKeyRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl OraclePriceFeedKeyRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} diff --git a/lib/ain-ocean/src/repository/oracle_token_currency.rs b/lib/ain-ocean/src/repository/oracle_token_currency.rs index 8b137891791..7c99c954ffb 100644 --- a/lib/ain-ocean/src/repository/oracle_token_currency.rs +++ b/lib/ain-ocean/src/repository/oracle_token_currency.rs @@ -1 +1,43 @@ +use std::sync::Arc; +use ain_db::LedgerColumn; +use ain_macros::Repository; + +use super::RepositoryOps; +use crate::{ + model::{OracleTokenCurrency, OracleTokenCurrencyId, OracleTokenCurrencyKey}, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "OracleTokenCurrencyId", V = "OracleTokenCurrency")] +pub struct OracleTokenCurrencyRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl OracleTokenCurrencyRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} + +#[derive(Repository)] +#[repository(K = "OracleTokenCurrencyKey", V = "OracleTokenCurrencyId")] +pub struct OracleTokenCurrencyKeyRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl OracleTokenCurrencyKeyRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} diff --git a/lib/ain-ocean/src/repository/price_ticker.rs b/lib/ain-ocean/src/repository/price_ticker.rs index 8b137891791..fa22f13be42 100644 --- a/lib/ain-ocean/src/repository/price_ticker.rs +++ b/lib/ain-ocean/src/repository/price_ticker.rs @@ -1 +1,27 @@ +use std::sync::Arc; +use ain_db::LedgerColumn; +use ain_macros::Repository; + +use super::RepositoryOps; +use crate::{ + model::{PriceTicker, PriceTickerId}, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "PriceTickerId", V = "PriceTicker")] +pub struct PriceTickerRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl PriceTickerRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} diff --git a/lib/ain-ocean/src/storage/columns/mod.rs b/lib/ain-ocean/src/storage/columns/mod.rs index 76ad06047e6..02e36915d95 100644 --- a/lib/ain-ocean/src/storage/columns/mod.rs +++ b/lib/ain-ocean/src/storage/columns/mod.rs @@ -1,6 +1,7 @@ mod block; mod masternode; mod masternode_stats; +mod oracle; mod oracle_history; mod oracle_price_active; mod oracle_price_aggregated; @@ -24,6 +25,7 @@ use ain_db::ColumnName; pub use block::*; pub use masternode::*; pub use masternode_stats::*; +pub use oracle::*; pub use oracle_history::*; pub use oracle_price_active::*; pub use oracle_price_aggregated::*; @@ -43,18 +45,23 @@ pub use transaction_vout::*; pub use tx_result::*; pub use vault_auction_history::*; -pub const COLUMN_NAMES: [&str; 25] = [ +pub const COLUMN_NAMES: [&str; 30] = [ block::Block::NAME, block::BlockByHeight::NAME, masternode_stats::MasternodeStats::NAME, masternode::Masternode::NAME, masternode::MasternodeByHeight::NAME, + oracle::Oracle::NAME, oracle_history::OracleHistory::NAME, + oracle_history::OracleHistoryOracleIdSort::NAME, oracle_price_active::OraclePriceActive::NAME, oracle_price_aggregated::OraclePriceAggregated::NAME, + oracle_price_aggregated::OraclePriceAggregatedKey::NAME, oracle_price_aggregated_interval::OraclePriceAggregatedInterval::NAME, oracle_price_feed::OraclePriceFeed::NAME, + oracle_price_feed::OraclePriceFeedKey::NAME, oracle_token_currency::OracleTokenCurrency::NAME, + oracle_token_currency::OracleTokenCurrencyKey::NAME, pool_swap_aggregated::PoolSwapAggregated::NAME, pool_swap::PoolSwap::NAME, price_ticker::PriceTicker::NAME, diff --git a/lib/ain-ocean/src/storage/columns/oracle.rs b/lib/ain-ocean/src/storage/columns/oracle.rs new file mode 100644 index 00000000000..f159f0419f1 --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/oracle.rs @@ -0,0 +1,19 @@ +use ain_db::{Column, ColumnName, TypedColumn}; +use bitcoin::Txid; + +use crate::model; + +#[derive(Debug)] +pub struct Oracle; + +impl ColumnName for Oracle { + const NAME: &'static str = "oracle"; +} + +impl Column for Oracle { + type Index = Txid; +} + +impl TypedColumn for Oracle { + type Type = model::Oracle; +} diff --git a/lib/ain-ocean/src/storage/columns/oracle_history.rs b/lib/ain-ocean/src/storage/columns/oracle_history.rs index f42cf36713a..672cecb5f12 100644 --- a/lib/ain-ocean/src/storage/columns/oracle_history.rs +++ b/lib/ain-ocean/src/storage/columns/oracle_history.rs @@ -1,4 +1,7 @@ use ain_db::{Column, ColumnName, TypedColumn}; +use bitcoin::Txid; + +use crate::model; #[derive(Debug)] pub struct OracleHistory; @@ -8,9 +11,23 @@ impl ColumnName for OracleHistory { } impl Column for OracleHistory { - type Index = String; + type Index = model::OracleHistoryId; } impl TypedColumn for OracleHistory { - type Type = String; + type Type = model::OracleHistory; +} + +pub struct OracleHistoryOracleIdSort; + +impl ColumnName for OracleHistoryOracleIdSort { + const NAME: &'static str = "oracle_history_oracle_id_sort"; +} + +impl Column for OracleHistoryOracleIdSort { + type Index = Txid; +} + +impl TypedColumn for OracleHistoryOracleIdSort { + type Type = model::OracleHistoryId; } diff --git a/lib/ain-ocean/src/storage/columns/oracle_price_active.rs b/lib/ain-ocean/src/storage/columns/oracle_price_active.rs index 47222c6d961..a45b807472a 100644 --- a/lib/ain-ocean/src/storage/columns/oracle_price_active.rs +++ b/lib/ain-ocean/src/storage/columns/oracle_price_active.rs @@ -1,5 +1,7 @@ use ain_db::{Column, ColumnName, TypedColumn}; +use crate::model; + #[derive(Debug)] pub struct OraclePriceActive; @@ -8,9 +10,24 @@ impl ColumnName for OraclePriceActive { } impl Column for OraclePriceActive { - type Index = String; + type Index = model::OraclePriceActiveId; } impl TypedColumn for OraclePriceActive { - type Type = String; + type Type = model::OraclePriceActive; +} + +#[derive(Debug)] +pub struct OraclePriceActiveKey; + +impl ColumnName for OraclePriceActiveKey { + const NAME: &'static str = "oracle_price_active_key"; +} + +impl Column for OraclePriceActiveKey { + type Index = model::OraclePriceActiveKey; +} + +impl TypedColumn for OraclePriceActiveKey { + type Type = model::OraclePriceActiveId; } diff --git a/lib/ain-ocean/src/storage/columns/oracle_price_aggregated.rs b/lib/ain-ocean/src/storage/columns/oracle_price_aggregated.rs index ff4b0a32627..fd3d3f94702 100644 --- a/lib/ain-ocean/src/storage/columns/oracle_price_aggregated.rs +++ b/lib/ain-ocean/src/storage/columns/oracle_price_aggregated.rs @@ -1,5 +1,7 @@ use ain_db::{Column, ColumnName, TypedColumn}; +use crate::model; + #[derive(Debug)] pub struct OraclePriceAggregated; @@ -8,9 +10,23 @@ impl ColumnName for OraclePriceAggregated { } impl Column for OraclePriceAggregated { - type Index = String; + type Index = model::OraclePriceAggregatedId; } impl TypedColumn for OraclePriceAggregated { - type Type = String; + type Type = model::OraclePriceAggregated; +} + +pub struct OraclePriceAggregatedKey; + +impl ColumnName for OraclePriceAggregatedKey { + const NAME: &'static str = "oracle_price_aggregated_key"; +} + +impl Column for OraclePriceAggregatedKey { + type Index = model::OraclePriceAggregatedKey; +} + +impl TypedColumn for OraclePriceAggregatedKey { + type Type = model::OraclePriceAggregatedId; } diff --git a/lib/ain-ocean/src/storage/columns/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/storage/columns/oracle_price_aggregated_interval.rs index f4d925cc410..0adca75ae46 100644 --- a/lib/ain-ocean/src/storage/columns/oracle_price_aggregated_interval.rs +++ b/lib/ain-ocean/src/storage/columns/oracle_price_aggregated_interval.rs @@ -1,5 +1,7 @@ use ain_db::{Column, ColumnName, TypedColumn}; +use crate::model; + #[derive(Debug)] pub struct OraclePriceAggregatedInterval; @@ -8,9 +10,24 @@ impl ColumnName for OraclePriceAggregatedInterval { } impl Column for OraclePriceAggregatedInterval { - type Index = String; + type Index = model::OraclePriceAggregatedIntervalId; } impl TypedColumn for OraclePriceAggregatedInterval { - type Type = String; + type Type = model::OraclePriceAggregatedInterval; +} + +#[derive(Debug)] +pub struct OraclePriceAggregatedIntervalKey; + +impl ColumnName for OraclePriceAggregatedIntervalKey { + const NAME: &'static str = "oracle_price_aggregated_interval_key"; +} + +impl Column for OraclePriceAggregatedIntervalKey { + type Index = model::OraclePriceAggregatedIntervalKey; +} + +impl TypedColumn for OraclePriceAggregatedIntervalKey { + type Type = model::OraclePriceAggregatedIntervalId; } diff --git a/lib/ain-ocean/src/storage/columns/oracle_price_feed.rs b/lib/ain-ocean/src/storage/columns/oracle_price_feed.rs index 4a546eadc94..32e7acedc7e 100644 --- a/lib/ain-ocean/src/storage/columns/oracle_price_feed.rs +++ b/lib/ain-ocean/src/storage/columns/oracle_price_feed.rs @@ -1,5 +1,8 @@ use ain_db::{Column, ColumnName, TypedColumn}; +use crate::model::{ + OraclePriceFeed as OraclePriceFeedMapper, OraclePriceFeedId, OraclePriceFeedkey, +}; #[derive(Debug)] pub struct OraclePriceFeed; @@ -8,9 +11,23 @@ impl ColumnName for OraclePriceFeed { } impl Column for OraclePriceFeed { - type Index = String; + type Index = OraclePriceFeedId; } impl TypedColumn for OraclePriceFeed { - type Type = String; + type Type = OraclePriceFeedMapper; +} + +pub struct OraclePriceFeedKey; + +impl ColumnName for OraclePriceFeedKey { + const NAME: &'static str = "oracle_price_feed_key"; +} + +impl Column for OraclePriceFeedKey { + type Index = OraclePriceFeedkey; +} + +impl TypedColumn for OraclePriceFeedKey { + type Type = OraclePriceFeedId; } diff --git a/lib/ain-ocean/src/storage/columns/oracle_token_currency.rs b/lib/ain-ocean/src/storage/columns/oracle_token_currency.rs index b315cd259f8..42eed45f6eb 100644 --- a/lib/ain-ocean/src/storage/columns/oracle_token_currency.rs +++ b/lib/ain-ocean/src/storage/columns/oracle_token_currency.rs @@ -1,5 +1,6 @@ use ain_db::{Column, ColumnName, TypedColumn}; +use crate::model; #[derive(Debug)] pub struct OracleTokenCurrency; @@ -8,9 +9,23 @@ impl ColumnName for OracleTokenCurrency { } impl Column for OracleTokenCurrency { - type Index = String; + type Index = model::OracleTokenCurrencyId; } impl TypedColumn for OracleTokenCurrency { - type Type = String; + type Type = model::OracleTokenCurrency; +} + +pub struct OracleTokenCurrencyKey; + +impl ColumnName for OracleTokenCurrencyKey { + const NAME: &'static str = "oracle_token_currency_key"; +} + +impl Column for OracleTokenCurrencyKey { + type Index = model::OracleTokenCurrencyKey; +} + +impl TypedColumn for OracleTokenCurrencyKey { + type Type = model::OracleTokenCurrencyId; } diff --git a/lib/ain-ocean/src/storage/columns/price_ticker.rs b/lib/ain-ocean/src/storage/columns/price_ticker.rs index a92c44cdac9..db73d7219ba 100644 --- a/lib/ain-ocean/src/storage/columns/price_ticker.rs +++ b/lib/ain-ocean/src/storage/columns/price_ticker.rs @@ -1,16 +1,18 @@ use ain_db::{Column, ColumnName, TypedColumn}; +use crate::model; + #[derive(Debug)] pub struct PriceTicker; impl ColumnName for PriceTicker { - const NAME: &'static str = "price_tiker"; + const NAME: &'static str = "price_ticker"; } impl Column for PriceTicker { - type Index = String; + type Index = model::PriceTickerId; } impl TypedColumn for PriceTicker { - type Type = String; + type Type = model::PriceTicker; } From 60f5acd65519d6c57dc85e8bff37b7ac8da3aa20 Mon Sep 17 00:00:00 2001 From: jouzo Date: Tue, 9 Apr 2024 15:55:43 +0100 Subject: [PATCH 083/185] Clippy --- lib/ain-ocean/src/api/prices.rs | 2 +- lib/ain-ocean/src/indexer/oracle.rs | 48 ++++++++++-------------- lib/ain-ocean/src/indexer/oracle_test.rs | 3 +- lib/ain-ocean/src/model/mod.rs | 12 +++--- 4 files changed, 28 insertions(+), 37 deletions(-) diff --git a/lib/ain-ocean/src/api/prices.rs b/lib/ain-ocean/src/api/prices.rs index f384da3631c..192ad4694c2 100644 --- a/lib/ain-ocean/src/api/prices.rs +++ b/lib/ain-ocean/src/api/prices.rs @@ -254,7 +254,7 @@ async fn get_oracles( })) } -pub fn router(ctx: Arc) -> Router { +pub fn router(_ctx: Arc) -> Router { Router::new() .route("/", get(list_prices)) .route("/:key", get(get_price)) diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index 7b379abd3ee..71bea48a172 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -131,7 +131,7 @@ impl Index for RemoveOracle { let oracle_id = ctx.tx.txid; //delete for oracle data from oracle services.oracle.by_id.delete(&oracle_id)?; - let previous_hsitory = get_previous_oracle_history_list(services, oracle_id.clone()); + let previous_hsitory = get_previous_oracle_history_list(services, oracle_id); match previous_hsitory { Ok(previous_oracle) => { for oracle_history in &previous_oracle { @@ -459,7 +459,7 @@ impl Index for SetOracleData { let aggregated_price = services.oracle_price_aggregated.by_id.get(&aggreated_id)?; if let Some(aggregated) = aggregated_price { for interval in &intervals { - let err = invalidate_oracle_interval( + let _err = invalidate_oracle_interval( services, &context.block, token, @@ -520,16 +520,9 @@ pub fn map_price_aggregated( let feed_id = services.oracle_price_feed.by_key.get(&key); let feeds = match feed_id { - Ok(feed_ids) => feed_ids.map_or_else( - || Ok(None), - |id| { - services - .oracle_price_feed - .by_id - .get(&id) - .map(|data| Some(data)) - }, - ), + Ok(feed_ids) => { + feed_ids.map_or_else(|| Ok(None), |id| services.oracle_price_feed.by_id.get(&id)) + } Err(err) => { println!("the err {:?}", err); Err(err) @@ -537,7 +530,7 @@ pub fn map_price_aggregated( }; let oracle_price_feed: Option = match feeds { - Ok(Some(Some(feed))) => Some(feed), + Ok(Some(feed)) => Some(feed), _ => None, }; @@ -650,7 +643,7 @@ pub fn index_interval_mapper( for previous_oracle_price_aggreated in previous_aggrigated_interval { let clone_interval = interval.clone(); if previous_oracle_price_aggreated.len() != 0 - || (block.median_time - previous_oracle_price_aggreated[0].block.median_time.clone()) + || (block.median_time - previous_oracle_price_aggreated[0].block.median_time) > clone_interval as i64 { let oracle_price_aggregated_interval = OraclePriceAggregatedInterval { @@ -667,16 +660,16 @@ pub fn index_interval_mapper( aggregated: previous_oracle_price_aggreated[0].aggregated.clone(), block: block.clone(), }; - let err = services.oracle_price_aggregated_interval.by_id.put( + let _err = services.oracle_price_aggregated_interval.by_id.put( &oracle_price_aggregated_interval.id, &oracle_price_aggregated_interval, ); - let err = services.oracle_price_aggregated_interval.by_key.put( + let _err = services.oracle_price_aggregated_interval.by_key.put( &oracle_price_aggregated_interval.key, &oracle_price_aggregated_interval.id, ); } else { - process_inner_values(&services, &previous_oracle_price_aggreated[0], aggregated); + process_inner_values(services, &previous_oracle_price_aggreated[0], aggregated); } } @@ -685,7 +678,7 @@ pub fn index_interval_mapper( pub fn invalidate_oracle_interval( services: &Arc, - block: &BlockContext, + _block: &BlockContext, token: &str, currency: &str, aggregated: &OraclePriceAggregated, @@ -712,7 +705,7 @@ pub fn invalidate_oracle_interval( for oracle_price_aggreated in previous_aggrigated_interval { if oracle_price_aggreated[0].aggregated.count != 1 { - let err = services + let _err = services .oracle_price_aggregated_interval .by_id .delete(&oracle_price_aggreated[0].id); @@ -743,7 +736,7 @@ pub fn invalidate_oracle_interval( lastprice.oracles.active, aggregated.aggregated.oracles.active, lastprice.count as u32, - ) as i32, + ), total: backward_aggregate_number( lastprice.oracles.total, aggregated.aggregated.oracles.total, @@ -753,11 +746,11 @@ pub fn invalidate_oracle_interval( }, block: oracle_price_aggreated[0].block.clone(), }; - let err = services.oracle_price_aggregated_interval.by_id.put( + let _err = services.oracle_price_aggregated_interval.by_id.put( &previous_aggregated_interval.id, &previous_aggregated_interval, ); - let err = services.oracle_price_aggregated_interval.by_key.put( + let _err = services.oracle_price_aggregated_interval.by_key.put( &previous_aggregated_interval.key, &previous_aggregated_interval.id, ); @@ -798,7 +791,7 @@ fn process_inner_values( lastprice.oracles.active, aggregated.aggregated.oracles.active, lastprice.count, - ) as i32, + ), total: forward_aggregate_number( lastprice.oracles.total, aggregated.aggregated.oracles.total, @@ -808,11 +801,11 @@ fn process_inner_values( }, block: previous_data.block.clone(), }; - let err = services + let _err = services .oracle_price_aggregated_interval .by_id .put(&aggregated_interval.id, &aggregated_interval); - let err = services + let _err = services .oracle_price_aggregated_interval .by_key .put(&aggregated_interval.key, &aggregated_interval.id); @@ -846,8 +839,7 @@ fn backward_aggregate_value(last_value: &str, new_value: &str, count: u32) -> De let new_value_decimal = Decimal::from_str(new_value).unwrap_or_else(|_| Decimal::zero()); let count_decimal = Decimal::from(count); - (last_value_decimal * count_decimal.clone() - new_value_decimal) - / (count_decimal - Decimal::from(1)) + (last_value_decimal * count_decimal - new_value_decimal) / (count_decimal - Decimal::from(1)) } fn backward_aggregate_number(last_value: i32, new_value: i32, count: u32) -> i32 { @@ -857,7 +849,7 @@ fn backward_aggregate_number(last_value: i32, new_value: i32, count: u32) -> i32 Decimal::from_str(&new_value.to_string()).unwrap_or_else(|_| Decimal::zero()); let count_decimal = Decimal::from(count); - let result = (last_value_decimal * count_decimal.clone() - new_value_decimal) + let result = (last_value_decimal * count_decimal - new_value_decimal) / (count_decimal - Decimal::from(1)); result.to_i32().unwrap_or_else(|| { diff --git a/lib/ain-ocean/src/indexer/oracle_test.rs b/lib/ain-ocean/src/indexer/oracle_test.rs index 5b659ef7896..6f1afc9fd87 100644 --- a/lib/ain-ocean/src/indexer/oracle_test.rs +++ b/lib/ain-ocean/src/indexer/oracle_test.rs @@ -4,10 +4,9 @@ mod tests { use ain_dftx::{common::CompactVec, price::CurrencyPair, types::oracles::AppointOracle}; use bitcoin::{BlockHash, ScriptBuf, Txid}; - use defichain_rpc::json::blockchain::{Block, Transaction}; + use defichain_rpc::json::blockchain::Transaction; use tempfile::tempdir; - use super::*; use crate::{ indexer::{Context, Index}, model::BlockContext, diff --git a/lib/ain-ocean/src/model/mod.rs b/lib/ain-ocean/src/model/mod.rs index 869df512ce8..4aaf0139e69 100644 --- a/lib/ain-ocean/src/model/mod.rs +++ b/lib/ain-ocean/src/model/mod.rs @@ -32,13 +32,13 @@ pub use oracle_price_aggregated_interval::*; pub use oracle_price_feed::*; pub use oracle_token_currency::*; pub use poolswap::*; -pub use poolswap_aggregated::*; +// pub use poolswap_aggregated::*; pub use price_ticker::*; -pub use prices::*; -pub use raw_block::*; -pub use script_activity::*; -pub use script_aggregation::*; -pub use script_unspent::*; +// pub use prices::*; +// pub use raw_block::*; +// pub use script_activity::*; +// pub use script_aggregation::*; +// pub use script_unspent::*; pub use transaction::*; pub use transaction_vin::*; pub use transaction_vout::*; From ed0267f17c1511693847202da9289af00a99ce4d Mon Sep 17 00:00:00 2001 From: jouzo Date: Wed, 10 Apr 2024 11:20:12 +0100 Subject: [PATCH 084/185] Restore txid in Transaction --- lib/ain-ocean/src/indexer/transaction.rs | 1 + lib/ain-ocean/src/model/transaction.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/ain-ocean/src/indexer/transaction.rs b/lib/ain-ocean/src/indexer/transaction.rs index b571c97a11c..54a29041fae 100644 --- a/lib/ain-ocean/src/indexer/transaction.rs +++ b/lib/ain-ocean/src/indexer/transaction.rs @@ -65,6 +65,7 @@ pub fn index_transaction(services: &Arc, ctx: Context) -> Result<()> { let tx = TransactionMapper { id: txid, + txid, order, hash: ctx.tx.hash, block: ctx.block.clone(), diff --git a/lib/ain-ocean/src/model/transaction.rs b/lib/ain-ocean/src/model/transaction.rs index d9147a9a393..7939a18a495 100644 --- a/lib/ain-ocean/src/model/transaction.rs +++ b/lib/ain-ocean/src/model/transaction.rs @@ -10,6 +10,7 @@ pub type TransactionByBlockHashKey = (BlockHash, usize); #[serde(rename_all = "camelCase")] pub struct Transaction { pub id: Txid, + pub txid: Txid, pub order: usize, // tx order pub block: BlockContext, pub hash: String, From afb1d4386c3eb27021521d7cffe856fc280162b7 Mon Sep 17 00:00:00 2001 From: Nagaraj <144004792+nagarajm22@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:24:40 +0000 Subject: [PATCH 085/185] Update index mapper and oracle invalidate interval (#2888) * fixed clippy warning for oracle * format space * Revert "format space" This reverts commit 36c8e2143c4d356e5b2110073e65cc19e8e039d0. * fixed OraclePriceAggregatedIntervalKey * fixed index_interval_mapper * removed unwanted println * Fix clippy --------- Co-authored-by: jouzo --- lib/ain-ocean/src/bin/cli.rs | 1 - lib/ain-ocean/src/consts.rs | 15 ++-- lib/ain-ocean/src/indexer/oracle.rs | 71 +++++++++++++------ .../src/repository/test/oracle_test.rs | 1 - lib/ain-ocean/src/storage/columns/mod.rs | 4 +- 5 files changed, 60 insertions(+), 32 deletions(-) diff --git a/lib/ain-ocean/src/bin/cli.rs b/lib/ain-ocean/src/bin/cli.rs index c839e9a127f..e860e653232 100644 --- a/lib/ain-ocean/src/bin/cli.rs +++ b/lib/ain-ocean/src/bin/cli.rs @@ -64,7 +64,6 @@ async fn main() -> Result<()> { .by_height .get_highest()? .map_or(0, |b| b.height); - println!("current height in {:?}", highest_block); let new_height = highest_block + 1; let hash = if let Some(hash) = next_block_hash { hash diff --git a/lib/ain-ocean/src/consts.rs b/lib/ain-ocean/src/consts.rs index 9162f3429e7..4be0d108ad3 100644 --- a/lib/ain-ocean/src/consts.rs +++ b/lib/ain-ocean/src/consts.rs @@ -1,3 +1,4 @@ +use std::fmt; #[derive(Debug, Clone)] pub enum Network { Mainnet, @@ -21,14 +22,14 @@ impl std::str::FromStr for Network { } } -impl ToString for Network { - fn to_string(&self) -> String { +impl fmt::Display for Network { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Network::Mainnet => String::from("mainnet"), - Network::Testnet => String::from("testnet"), - Network::Regtest => String::from("regtest"), - Network::Devnet => String::from("devnet"), - Network::Changi => String::from("changi"), + Network::Mainnet => write!(f, "mainnet"), + Network::Testnet => write!(f, "testnet"), + Network::Regtest => write!(f, "regtest"), + Network::Devnet => write!(f, "devnet"), + Network::Changi => write!(f, "changi"), } } } diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index 71bea48a172..667893d0d7d 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -164,8 +164,7 @@ impl Index for RemoveOracle { } fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { let oracle_id = context.tx.txid; - let previous_oracle_history_result = - get_previous_oracle_history_list(services, oracle_id.clone()); + let previous_oracle_history_result = get_previous_oracle_history_list(services, oracle_id); match previous_oracle_history_result { Ok(previous_oracle_history) => { @@ -236,8 +235,7 @@ impl Index for UpdateOracle { //save oracle services.oracle.by_id.put(&oracle.id, &oracle)?; - let previous_oracle_history_result = - get_previous_oracle_history_list(services, oracle_id.clone()); + let previous_oracle_history_result = get_previous_oracle_history_list(services, oracle_id); match previous_oracle_history_result { Ok(previous_oracle) => { for oracle in previous_oracle { @@ -246,7 +244,7 @@ impl Index for UpdateOracle { let deletion_key = ( price_feed_item.token.clone(), price_feed_item.currency.clone(), - oracle_id.clone(), + oracle_id, ); match services.oracle_token_currency.by_id.delete(&deletion_key) { Ok(_) => { @@ -283,7 +281,7 @@ impl Index for UpdateOracle { ), token: token_currency.token.clone(), currency: token_currency.currency.clone(), - oracle_id: oracle_id.clone(), + oracle_id, weightage: self.weightage, block: ctx.block.clone(), }; @@ -341,8 +339,7 @@ impl Index for UpdateOracle { self.oracle_id, ))?; } - let previous_oracle_history_result = - get_previous_oracle_history_list(services, oracle_id.clone()); + let previous_oracle_history_result = get_previous_oracle_history_list(services, oracle_id); match previous_oracle_history_result { Ok(previous_oracle_result) => { for previous_oracle in previous_oracle_result { @@ -350,7 +347,7 @@ impl Index for UpdateOracle { let deletion_key = ( price_feed_item.token.clone(), price_feed_item.currency.clone(), - previous_oracle.oracle_id.clone(), + previous_oracle.oracle_id, ); match services.oracle_token_currency.by_id.delete(&deletion_key) { @@ -402,7 +399,7 @@ impl Index for SetOracleData { let aggreated_id = ( value.token.clone(), value.currency.clone(), - value.block.height.clone(), + value.block.height, ); let aggreated_key = (value.token.clone(), value.currency.clone()); services @@ -640,12 +637,8 @@ pub fn index_interval_mapper( }) .collect::>>(); - for previous_oracle_price_aggreated in previous_aggrigated_interval { - let clone_interval = interval.clone(); - if previous_oracle_price_aggreated.len() != 0 - || (block.median_time - previous_oracle_price_aggreated[0].block.median_time) - > clone_interval as i64 - { + if let Ok(previous_oracle_price_aggreated) = previous_aggrigated_interval { + if previous_oracle_price_aggreated.is_empty() { let oracle_price_aggregated_interval = OraclePriceAggregatedInterval { id: ( token.to_owned(), @@ -657,20 +650,41 @@ pub fn index_interval_mapper( sort: aggregated.sort.to_owned(), token: token.to_owned(), currency: currency.to_owned(), - aggregated: previous_oracle_price_aggreated[0].aggregated.clone(), + aggregated: OraclePriceAggregatedIntervalAggregated { + amount: aggregated.aggregated.amount.clone(), + weightage: aggregated.aggregated.weightage, + count: 1, + oracles: OraclePriceAggregatedIntervalAggregatedOracles { + active: aggregated.aggregated.oracles.active, + total: aggregated.aggregated.oracles.total, + }, + }, block: block.clone(), }; - let _err = services.oracle_price_aggregated_interval.by_id.put( + services.oracle_price_aggregated_interval.by_id.put( &oracle_price_aggregated_interval.id, &oracle_price_aggregated_interval, - ); - let _err = services.oracle_price_aggregated_interval.by_key.put( + )?; + services.oracle_price_aggregated_interval.by_key.put( &oracle_price_aggregated_interval.key, &oracle_price_aggregated_interval.id, - ); + )?; } else { process_inner_values(services, &previous_oracle_price_aggreated[0], aggregated); } + } else { + let err = previous_aggrigated_interval.err(); + match err { + Some(e) => { + let error_message = format!("Error updating oracle index interval mapper: {:?}", e); + eprintln!("{}", error_message); + return Err(Error::NotFound(NotFoundKind::Oracle)); + } + None => { + eprintln!("Unknown index interval mapper error "); + return Err(Error::NotFound(NotFoundKind::Oracle)); + } + } } Ok(()) @@ -703,7 +717,7 @@ pub fn invalidate_oracle_interval( }) .collect::>>(); - for oracle_price_aggreated in previous_aggrigated_interval { + if let Ok(oracle_price_aggreated) = previous_aggrigated_interval { if oracle_price_aggreated[0].aggregated.count != 1 { let _err = services .oracle_price_aggregated_interval @@ -755,6 +769,19 @@ pub fn invalidate_oracle_interval( &previous_aggregated_interval.id, ); } + } else { + let err = previous_aggrigated_interval.err(); + match err { + Some(e) => { + let error_message = format!("Error updating oracle interval: {:?}", e); + eprintln!("{}", error_message); + return Err(Error::NotFound(NotFoundKind::Oracle)); + } + None => { + eprintln!("Unknown previous_aggrigated_interval error "); + return Err(Error::NotFound(NotFoundKind::Oracle)); + } + } } Ok(()) } diff --git a/lib/ain-ocean/src/repository/test/oracle_test.rs b/lib/ain-ocean/src/repository/test/oracle_test.rs index b6930c9e904..c55e5154611 100644 --- a/lib/ain-ocean/src/repository/test/oracle_test.rs +++ b/lib/ain-ocean/src/repository/test/oracle_test.rs @@ -52,7 +52,6 @@ mod tests { let result = oracle_db.get(oracle.id.clone()).await.unwrap(); assert!(result.is_some()); - println!("the oracle result {:?}", result); assert_eq!(result.unwrap(), oracle); } diff --git a/lib/ain-ocean/src/storage/columns/mod.rs b/lib/ain-ocean/src/storage/columns/mod.rs index 02e36915d95..615205ce4bb 100644 --- a/lib/ain-ocean/src/storage/columns/mod.rs +++ b/lib/ain-ocean/src/storage/columns/mod.rs @@ -45,7 +45,7 @@ pub use transaction_vout::*; pub use tx_result::*; pub use vault_auction_history::*; -pub const COLUMN_NAMES: [&str; 30] = [ +pub const COLUMN_NAMES: [&str; 32] = [ block::Block::NAME, block::BlockByHeight::NAME, masternode_stats::MasternodeStats::NAME, @@ -55,9 +55,11 @@ pub const COLUMN_NAMES: [&str; 30] = [ oracle_history::OracleHistory::NAME, oracle_history::OracleHistoryOracleIdSort::NAME, oracle_price_active::OraclePriceActive::NAME, + oracle_price_active::OraclePriceActiveKey::NAME, oracle_price_aggregated::OraclePriceAggregated::NAME, oracle_price_aggregated::OraclePriceAggregatedKey::NAME, oracle_price_aggregated_interval::OraclePriceAggregatedInterval::NAME, + oracle_price_aggregated_interval::OraclePriceAggregatedIntervalKey::NAME, oracle_price_feed::OraclePriceFeed::NAME, oracle_price_feed::OraclePriceFeedKey::NAME, oracle_token_currency::OracleTokenCurrency::NAME, From 4f87db443ffc9f44b21758a5c75102498827cc8f Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Mon, 15 Apr 2024 08:29:59 +0100 Subject: [PATCH 086/185] Handle masternode state (#2889) --- .../api/{masternode.rs => masternode/mod.rs} | 48 ++-- lib/ain-ocean/src/api/masternode/state.rs | 64 ++++++ lib/ain-ocean/src/api/mod.rs | 8 +- lib/ain-ocean/src/bin/cli.rs | 4 +- lib/ain-ocean/src/consts.rs | 35 --- lib/ain-ocean/src/lib.rs | 2 +- lib/ain-ocean/src/network.rs | 215 ++++++++++++++++++ 7 files changed, 317 insertions(+), 59 deletions(-) rename lib/ain-ocean/src/api/{masternode.rs => masternode/mod.rs} (81%) create mode 100644 lib/ain-ocean/src/api/masternode/state.rs delete mode 100644 lib/ain-ocean/src/consts.rs create mode 100644 lib/ain-ocean/src/network.rs diff --git a/lib/ain-ocean/src/api/masternode.rs b/lib/ain-ocean/src/api/masternode/mod.rs similarity index 81% rename from lib/ain-ocean/src/api/masternode.rs rename to lib/ain-ocean/src/api/masternode/mod.rs index 24734ea5d1f..438f2923f68 100644 --- a/lib/ain-ocean/src/api/masternode.rs +++ b/lib/ain-ocean/src/api/masternode/mod.rs @@ -1,5 +1,7 @@ use std::sync::Arc; +mod state; + use ain_macros::ocean_endpoint; use anyhow::format_err; use axum::{ @@ -10,6 +12,8 @@ use axum::{ use bitcoin::Txid; use serde::{Deserialize, Serialize}; +use self::state::{MasternodeService, MasternodeState}; + use super::{ query::PaginationQuery, response::{ApiPagedResponse, Response}, @@ -24,19 +28,6 @@ use crate::{ Result, }; -#[derive(Serialize, Deserialize, Debug, Default, Clone)] -#[serde(rename_all = "SCREAMING_SNAKE_CASE")] -pub enum MasternodeState { - PreEnabled, - Enabled, - PreResigned, - Resigned, - PreBanned, - Banned, - #[default] - Unknown, -} - #[derive(Serialize, Deserialize, Debug, Clone)] pub struct MasternodeOwner { pub address: String, @@ -72,12 +63,12 @@ pub struct MasternodeData { pub timelock: u16, } -impl From for MasternodeData { - fn from(v: Masternode) -> Self { +impl MasternodeData { + fn from_with_state(v: Masternode, state: MasternodeState) -> Self { MasternodeData { id: v.id.to_string(), sort: format!("{:08x}{}", v.block.height, v.id), - state: MasternodeState::default(), // TODO Handle mn state + state, minted_blocks: v.minted_blocks, owner: MasternodeOwner { address: v.owner_address, @@ -121,11 +112,22 @@ async fn list_masternodes( }) .transpose()?; + let height = ctx + .services + .block + .by_height + .get_highest()? + .map_or(0, |b| b.height); + let masternodes = repository .list(next, SortOrder::Descending)? .paginate(&query) .map(|el| repository.retrieve_primary_value(el)) - .map(|v| v.map(MasternodeData::from)) + .map(|v| { + let mn = v.unwrap(); + let state = MasternodeService::new(ctx.network).get_masternode_state(&mn, height); + Ok(MasternodeData::from_with_state(mn, state)) + }) .collect::>>()?; Ok(ApiPagedResponse::of( @@ -140,12 +142,22 @@ async fn get_masternode( Path(masternode_id): Path, Extension(ctx): Extension>, ) -> Result> { + let height = ctx + .services + .block + .by_height + .get_highest()? + .map_or(0, |b| b.height); + let mn = ctx .services .masternode .by_id .get(&masternode_id)? - .map(Into::into) + .map(|mn| { + let state = MasternodeService::new(ctx.network).get_masternode_state(&mn, height); + MasternodeData::from_with_state(mn, state) + }) .ok_or(Error::NotFound(NotFoundKind::Masternode))?; Ok(Response::new(mn)) diff --git a/lib/ain-ocean/src/api/masternode/state.rs b/lib/ain-ocean/src/api/masternode/state.rs new file mode 100644 index 00000000000..cc2febf988e --- /dev/null +++ b/lib/ain-ocean/src/api/masternode/state.rs @@ -0,0 +1,64 @@ +use serde::{Deserialize, Serialize}; + +use crate::{model::Masternode, network::Network}; + +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum MasternodeState { + PreEnabled, + Enabled, + PreResigned, + Resigned, + PreBanned, + Banned, + #[default] + Unknown, +} + +pub struct MasternodeService { + network: Network, +} + +impl MasternodeService { + pub fn new(network: Network) -> Self { + MasternodeService { network } + } + + fn get_mn_activation_delay(&self, height: u32) -> u32 { + let eunos_height = self.network.fork_heights().df8_eunos_height; + if height < eunos_height { + self.network.params().activation_delay + } else { + self.network.params().new_activation_delay + } + } + + fn get_mn_resign_delay(&self, height: u32) -> u32 { + let eunos_height = self.network.fork_heights().df8_eunos_height; + if height < eunos_height { + self.network.params().resign_delay + } else { + self.network.params().new_resign_delay + } + } + + pub fn get_masternode_state(&self, masternode: &Masternode, height: u32) -> MasternodeState { + if let Some(resign_height) = masternode.resign_height { + let resign_delay = self.get_mn_resign_delay(resign_height); + if height < resign_height + resign_delay { + MasternodeState::PreResigned + } else { + MasternodeState::Resigned + } + } else { + let activation_delay = self.get_mn_activation_delay(masternode.creation_height); + if masternode.creation_height == 0 + || height >= masternode.creation_height + activation_delay + { + MasternodeState::Enabled + } else { + MasternodeState::PreEnabled + } + } + } +} diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index 570dafbbbe4..432e494f62a 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{str::FromStr, sync::Arc}; use axum::{extract::Request, http::StatusCode, response::IntoResponse, Json, Router}; @@ -24,7 +24,7 @@ mod transactions; use defichain_rpc::Client; use serde::{Deserialize, Serialize}; -use crate::{Result, Services}; +use crate::{network::Network, Result, Services}; #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] @@ -52,7 +52,7 @@ async fn not_found(req: Request) -> impl IntoResponse { pub struct AppContext { services: Arc, client: Arc, - network: String, // TODO Proper handling of network + network: Network, } pub async fn ocean_router( @@ -63,7 +63,7 @@ pub async fn ocean_router( let context = Arc::new(AppContext { client, services: services.clone(), - network, + network: Network::from_str(&network)?, }); println!("{:?}", context.network); Ok(Router::new().nest( diff --git a/lib/ain-ocean/src/bin/cli.rs b/lib/ain-ocean/src/bin/cli.rs index e860e653232..1fe109a90b1 100644 --- a/lib/ain-ocean/src/bin/cli.rs +++ b/lib/ain-ocean/src/bin/cli.rs @@ -1,6 +1,8 @@ use std::{net::SocketAddr, path::PathBuf, sync::Arc, time::Instant}; -use ain_ocean::{consts::Network, index_block, storage::ocean_store::OceanStore, Result, Services}; +use ain_ocean::{ + index_block, network::Network, storage::ocean_store::OceanStore, Result, Services, +}; use clap::Parser; use defichain_rpc::{json::blockchain::*, Auth, BlockchainRPC, Client}; diff --git a/lib/ain-ocean/src/consts.rs b/lib/ain-ocean/src/consts.rs deleted file mode 100644 index 4be0d108ad3..00000000000 --- a/lib/ain-ocean/src/consts.rs +++ /dev/null @@ -1,35 +0,0 @@ -use std::fmt; -#[derive(Debug, Clone)] -pub enum Network { - Mainnet, - Testnet, - Regtest, - Devnet, - Changi, -} - -impl std::str::FromStr for Network { - type Err = &'static str; - fn from_str(s: &str) -> Result { - match s { - "mainnet" => Ok(Network::Mainnet), - "testnet" => Ok(Network::Testnet), - "regtest" => Ok(Network::Regtest), - "devnet" => Ok(Network::Devnet), - "changi" => Ok(Network::Changi), - _ => Err("invalid network"), - } - } -} - -impl fmt::Display for Network { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Network::Mainnet => write!(f, "mainnet"), - Network::Testnet => write!(f, "testnet"), - Network::Regtest => write!(f, "regtest"), - Network::Devnet => write!(f, "devnet"), - Network::Changi => write!(f, "changi"), - } - } -} diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index ca792712aa4..320e391526f 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -1,6 +1,6 @@ -pub mod consts; pub mod error; mod indexer; +pub mod network; use std::{path::PathBuf, sync::Arc}; pub use api::ocean_router; diff --git a/lib/ain-ocean/src/network.rs b/lib/ain-ocean/src/network.rs new file mode 100644 index 00000000000..cf1361e4ffb --- /dev/null +++ b/lib/ain-ocean/src/network.rs @@ -0,0 +1,215 @@ +use std::fmt; +#[derive(Debug, Clone, Copy)] +pub enum Network { + Mainnet, + Testnet, + Regtest, + Devnet, + Changi, +} + +impl Network { + pub fn as_str(&self) -> &'static str { + match self { + Network::Mainnet => "mainnet", + Network::Testnet => "testnet", + Network::Regtest => "regtest", + Network::Devnet => "devnet", + Network::Changi => "changi", + } + } +} + +impl std::str::FromStr for Network { + type Err = &'static str; + fn from_str(s: &str) -> Result { + match s { + "mainnet" => Ok(Network::Mainnet), + "testnet" => Ok(Network::Testnet), + "regtest" => Ok(Network::Regtest), + "devnet" => Ok(Network::Devnet), + "changi" => Ok(Network::Changi), + _ => Err("invalid network"), + } + } +} + +impl fmt::Display for Network { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Network::Mainnet => write!(f, "mainnet"), + Network::Testnet => write!(f, "testnet"), + Network::Regtest => write!(f, "regtest"), + Network::Devnet => write!(f, "devnet"), + Network::Changi => write!(f, "changi"), + } + } +} + +#[derive(Debug, Clone, Copy)] +pub struct NetworkParams { + pub activation_delay: u32, + pub new_activation_delay: u32, + pub resign_delay: u32, + pub new_resign_delay: u32, +} + +impl Network { + pub fn params(&self) -> NetworkParams { + match self { + Network::Mainnet | Network::Testnet | Network::Devnet | Network::Changi => { + NetworkParams { + activation_delay: 10, + new_activation_delay: 1008, + resign_delay: 60, + new_resign_delay: 2016, + } + } + Network::Regtest => NetworkParams { + activation_delay: 10, + new_activation_delay: 20, + resign_delay: 10, + new_resign_delay: 40, + }, + } + } +} + +#[derive(Debug, Clone, Copy)] +pub struct ForkHeight { + pub df1_amk_height: u32, + pub df2_bayfront_height: u32, + pub df3_bayfront_marina_height: u32, + pub df4_bayfront_gardens_height: u32, + pub df5_clarke_quay_height: u32, + pub df6_dakota_height: u32, + pub df7_dakota_crescent_height: u32, + pub df8_eunos_height: u32, + pub df9_eunos_kampung_height: u32, + pub df10_eunos_paya_height: u32, + pub df11_fort_canning_height: u32, + pub df12_fort_canning_museum_height: u32, + pub df13_fort_canning_park_height: u32, + pub df14_fort_canning_hill_height: u32, + pub df15_fort_canning_road_height: u32, + pub df16_fort_canning_crunch_height: u32, + pub df17_fort_canning_spring_height: u32, + pub df18_fort_canning_great_world_height: u32, + pub df19_fort_canning_epilogue_height: u32, + pub df20_grand_central_height: u32, + pub df21_grand_central_epilogue_height: u32, + pub df22_metachain_height: u32, + pub df23_height: u32, + pub df24_height: u32, +} + +impl Network { + pub fn fork_heights(&self) -> ForkHeight { + match self { + Network::Mainnet => ForkHeight { + df1_amk_height: 356500, // Oct 12th, 2020., + df2_bayfront_height: 405000, // Nov 2nd, 2020., + df3_bayfront_marina_height: 465150, // Nov 28th, 2020., + df4_bayfront_gardens_height: 488300, // Dec 8th, 2020., + df5_clarke_quay_height: 595738, // Jan 24th, 2021., + df6_dakota_height: 678000, // Mar 1st, 2021., + df7_dakota_crescent_height: 733000, // Mar 25th, 2021., + df8_eunos_height: 894000, // Jun 3rd, 2021., + df9_eunos_kampung_height: 895743, // Jun 4th, 2021., + df10_eunos_paya_height: 1072000, // Aug 5th, 2021., + df11_fort_canning_height: 1367000, // Nov 15th, 2021., + df12_fort_canning_museum_height: 1430640, // Dec 7th, 2021., + df13_fort_canning_park_height: 1503143, // Jan 2nd, 2022., + df14_fort_canning_hill_height: 1604999, // Feb 7th, 2022., + df15_fort_canning_road_height: 1786000, // April 11th, 2022., + df16_fort_canning_crunch_height: 1936000, // June 2nd, 2022., + df17_fort_canning_spring_height: 2033000, // July 6th, 2022., + df18_fort_canning_great_world_height: 2212000, // Sep 7th, 2022., + df19_fort_canning_epilogue_height: 2257500, // Sep 22nd, 2022., + df20_grand_central_height: 2479000, // Dec 8th, 2022., + df21_grand_central_epilogue_height: 2574000, // Jan 10th, 2023., + df22_metachain_height: 3462000, // Nov 15th, 2023., + df23_height: u32::MAX, + df24_height: u32::MAX, + }, + Network::Testnet => ForkHeight { + df1_amk_height: 150, + df2_bayfront_height: 3000, + df3_bayfront_marina_height: 90470, + df4_bayfront_gardens_height: 101342, + df5_clarke_quay_height: 155000, + df6_dakota_height: 220680, + df7_dakota_crescent_height: 287700, + df8_eunos_height: 354950, + df9_eunos_kampung_height: 354950, + df10_eunos_paya_height: 463300, + df11_fort_canning_height: 686200, + df12_fort_canning_museum_height: 724000, + df13_fort_canning_park_height: 828800, + df14_fort_canning_hill_height: 828900, + df15_fort_canning_road_height: 893700, + df16_fort_canning_crunch_height: 1011600, + df17_fort_canning_spring_height: 1086000, + df18_fort_canning_great_world_height: 1150000, + df19_fort_canning_epilogue_height: 1150010, + df20_grand_central_height: 1150020, + df21_grand_central_epilogue_height: 1150030, + df22_metachain_height: 1150040, + df23_height: 1507200, + df24_height: u32::MAX, + }, + Network::Regtest => ForkHeight { + df1_amk_height: 10000000, + df2_bayfront_height: 10000000, + df3_bayfront_marina_height: 10000000, + df4_bayfront_gardens_height: 10000000, + df5_clarke_quay_height: 10000000, + df6_dakota_height: 10000000, + df7_dakota_crescent_height: 10000000, + df8_eunos_height: 10000000, + df9_eunos_kampung_height: 10000000, + df10_eunos_paya_height: 10000000, + df11_fort_canning_height: 10000000, + df12_fort_canning_museum_height: 10000000, + df13_fort_canning_park_height: 10000000, + df14_fort_canning_hill_height: 10000000, + df15_fort_canning_road_height: 10000000, + df16_fort_canning_crunch_height: 10000000, + df17_fort_canning_spring_height: 10000000, + df18_fort_canning_great_world_height: 10000000, + df19_fort_canning_epilogue_height: 10000000, + df20_grand_central_height: 10000000, + df21_grand_central_epilogue_height: 10000000, + df22_metachain_height: 10000000, + df23_height: 10000000, + df24_height: 10000000, + }, + Network::Devnet | Network::Changi => ForkHeight { + df1_amk_height: 150, + df2_bayfront_height: 3000, + df3_bayfront_marina_height: 90470, + df4_bayfront_gardens_height: 101342, + df5_clarke_quay_height: 155000, + df6_dakota_height: 220680, + df7_dakota_crescent_height: 287700, + df8_eunos_height: 354950, + df9_eunos_kampung_height: 354950, + df10_eunos_paya_height: 463300, + df11_fort_canning_height: 686200, + df12_fort_canning_museum_height: 724000, + df13_fort_canning_park_height: 828800, + df14_fort_canning_hill_height: 828900, + df15_fort_canning_road_height: 893700, + df16_fort_canning_crunch_height: 1011600, + df17_fort_canning_spring_height: 1086000, + df18_fort_canning_great_world_height: 1223000, + df19_fort_canning_epilogue_height: 1244000, + df20_grand_central_height: 1366000, + df21_grand_central_epilogue_height: 1438200, + df22_metachain_height: 1586750, + df23_height: 1985600, + df24_height: u32::MAX, + }, + } + } +} From 81e256c52e253e4b5fa9c31e59d69f1ece07924f Mon Sep 17 00:00:00 2001 From: jouzo Date: Mon, 15 Apr 2024 11:53:32 +0100 Subject: [PATCH 087/185] Fix doc --- lib/ain-ocean/src/api/common.rs | 14 ++++++++++---- lib/ain-ocean/src/api/mod.rs | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/ain-ocean/src/api/common.rs b/lib/ain-ocean/src/api/common.rs index 915f0b0ac5b..ca5397f9af4 100644 --- a/lib/ain-ocean/src/api/common.rs +++ b/lib/ain-ocean/src/api/common.rs @@ -45,13 +45,17 @@ fn parse_dat_symbol(symbol: &str) -> String { /// # Examples /// /// ``` +/// use rust_decimal::Decimal; +/// use rust_decimal_macros::dec; +/// use ain_ocean::api::{common::find_token_balance}; +/// /// let tokens = vec![ /// "557.35080849@DFI".to_string(), /// "9.98000000@BTC".to_string(), /// "421.46947098@DUSD".to_string() /// ]; /// let balance = find_token_balance(tokens, "DFI"); -/// assert_eq!(balance, 557.35080849); +/// assert_eq!(balance, dec!(557.35080849)); /// ``` /// /// # Returns @@ -88,10 +92,12 @@ pub fn find_token_balance(tokens: Vec, symbol: &str) -> Decimal { /// /// # Example /// -/// ```rust -/// use crate::Paginate; +/// This example is illustrative only and should not be executed directly as it involves API calls. +/// +/// ```rust,ignore +/// use ain_ocean::api::common::Paginate; /// -/// let query = { +/// let query = PaginationQuery { /// next: Some(1) /// limit: 3 /// }; diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index 432e494f62a..f9bfcd68bde 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -13,7 +13,7 @@ mod oracle; pub mod prices; // mod rawtx; mod cache; -mod common; +pub mod common; mod path; mod query; mod response; From 25c19d556cafb567de07baed4b732db67c4d4ce3 Mon Sep 17 00:00:00 2001 From: jouzo Date: Tue, 16 Apr 2024 09:05:02 +0100 Subject: [PATCH 088/185] Add support for mocknet --- lib/ain-ocean/src/network.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/ain-ocean/src/network.rs b/lib/ain-ocean/src/network.rs index cf1361e4ffb..75124611d15 100644 --- a/lib/ain-ocean/src/network.rs +++ b/lib/ain-ocean/src/network.rs @@ -2,6 +2,7 @@ use std::fmt; #[derive(Debug, Clone, Copy)] pub enum Network { Mainnet, + Mocknet, Testnet, Regtest, Devnet, @@ -12,6 +13,7 @@ impl Network { pub fn as_str(&self) -> &'static str { match self { Network::Mainnet => "mainnet", + Network::Mocknet => "mocknet", Network::Testnet => "testnet", Network::Regtest => "regtest", Network::Devnet => "devnet", @@ -25,6 +27,7 @@ impl std::str::FromStr for Network { fn from_str(s: &str) -> Result { match s { "mainnet" => Ok(Network::Mainnet), + "mocknet" => Ok(Network::Mocknet), "testnet" => Ok(Network::Testnet), "regtest" => Ok(Network::Regtest), "devnet" => Ok(Network::Devnet), @@ -38,6 +41,7 @@ impl fmt::Display for Network { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Network::Mainnet => write!(f, "mainnet"), + Network::Mocknet => write!(f, "mocknet"), Network::Testnet => write!(f, "testnet"), Network::Regtest => write!(f, "regtest"), Network::Devnet => write!(f, "devnet"), @@ -57,14 +61,16 @@ pub struct NetworkParams { impl Network { pub fn params(&self) -> NetworkParams { match self { - Network::Mainnet | Network::Testnet | Network::Devnet | Network::Changi => { - NetworkParams { - activation_delay: 10, - new_activation_delay: 1008, - resign_delay: 60, - new_resign_delay: 2016, - } - } + Network::Mainnet + | Network::Testnet + | Network::Devnet + | Network::Changi + | Network::Mocknet => NetworkParams { + activation_delay: 10, + new_activation_delay: 1008, + resign_delay: 60, + new_resign_delay: 2016, + }, Network::Regtest => NetworkParams { activation_delay: 10, new_activation_delay: 20, @@ -106,7 +112,7 @@ pub struct ForkHeight { impl Network { pub fn fork_heights(&self) -> ForkHeight { match self { - Network::Mainnet => ForkHeight { + Network::Mainnet | Network::Mocknet => ForkHeight { df1_amk_height: 356500, // Oct 12th, 2020., df2_bayfront_height: 405000, // Nov 2nd, 2020., df3_bayfront_marina_height: 465150, // Nov 28th, 2020., From d656a190fbd1919a6e7b82099af07ece41d87915 Mon Sep 17 00:00:00 2001 From: jouzo Date: Tue, 16 Apr 2024 09:42:22 +0100 Subject: [PATCH 089/185] Parse 'main' as mainnet network --- lib/ain-ocean/src/network.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ain-ocean/src/network.rs b/lib/ain-ocean/src/network.rs index 75124611d15..6a545f2bc4b 100644 --- a/lib/ain-ocean/src/network.rs +++ b/lib/ain-ocean/src/network.rs @@ -26,7 +26,7 @@ impl std::str::FromStr for Network { type Err = &'static str; fn from_str(s: &str) -> Result { match s { - "mainnet" => Ok(Network::Mainnet), + "mainnet" | "main" => Ok(Network::Mainnet), "mocknet" => Ok(Network::Mocknet), "testnet" => Ok(Network::Testnet), "regtest" => Ok(Network::Regtest), From 5ca1db545105207e17f81778d396e2a1941f2d92 Mon Sep 17 00:00:00 2001 From: jouzo Date: Thu, 25 Apr 2024 08:24:47 +0100 Subject: [PATCH 090/185] Trigger lint on feature/** branches --- .github/workflows/lint.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index c30a6d6a427..96bf3bb1ee4 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -10,6 +10,7 @@ on: pull_request: branches: - master + - feature/** concurrency: group: ${{ github.workflow }}-${{ github.ref || github.run_id }} From 489a8a7eef9b37dc7ce52d092870a0243a512567 Mon Sep 17 00:00:00 2001 From: jouzo Date: Thu, 25 Apr 2024 08:28:58 +0100 Subject: [PATCH 091/185] Fix missing ethsubscription doc --- src/init.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/init.cpp b/src/init.cpp index 540215f81d5..9ac70489329 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -671,6 +671,7 @@ void SetupServerArgs() gArgs.AddArg("-ethmaxresponsesize=", strprintf("Set the maximum response size in MB by the ETH-RPC server (default: %u, testnet: %u, changi: %u, devnet: %u, regtest: %u)", DEFAULT_ETH_MAX_RESPONSE_SIZE_MB, DEFAULT_ETH_MAX_RESPONSE_SIZE_MB, DEFAULT_ETH_MAX_RESPONSE_SIZE_MB, DEFAULT_ETH_MAX_RESPONSE_SIZE_MB, DEFAULT_ETH_MAX_RESPONSE_SIZE_MB), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC); gArgs.AddArg("-ethdebug", strprintf("Enable debug_* ETH RPCs (default: %b)", DEFAULT_ETH_DEBUG_ENABLED), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); gArgs.AddArg("-ethdebugtrace", strprintf("Enable debug_trace* ETH RPCs (default: %b)", DEFAULT_ETH_DEBUG_TRACE_ENABLED), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); + gArgs.AddArg("-ethsubscription", strprintf("Enable subscription notifications ETH RPCs (default: %b)", DEFAULT_ETH_SUBSCRIPTION_ENABLED), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); gArgs.AddArg("-oceanarchive", strprintf("Enable ocean archive and REST server (default: %b)", DEFAULT_OCEAN_ARCHIVE_ENABLED), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); gArgs.AddArg("-oceanarchiveport=", strprintf("Listen for ocean archive connections on (default: %u)", DEFAULT_OCEAN_ARCHIVE_PORT), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC); From ada8b1028387d551cc15f52fec8ef90665915e67 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Mon, 13 May 2024 16:21:09 +0800 Subject: [PATCH 092/185] Ocean: Api PoolPair (#2838) * comment unuse poolpairs api * enable api poolpairs list * rename struct prefix PoolPair and replace data by response * fix types * StringOrF64 * fmt * char * rm println * custom_rewards: Vec * fix PoolPairsResult de * filter BURN- and ordering * creation_height i64 * rm filter since using BTreeMap * apr and vol -> f64 * getpoolpair * token typings * pp list filter_map * StringOrFloat * rm StringOrFloat * wip listpoolswaps * Implement InitialKeyProvider for PoolSwapRepository * enable listpoolswapsverbose * Ocean: poolpair graph (#2855) * sync_token_graph on initialize * poolpairs_path * get_pool_pair_info_cached * compute_paths_between_tokens + all_simple_paths * get_pool_pair_info_cached * add list_paths api * fix list_paths api * fix all_simple_paths * missing Response list_paths api * temp disable list_pool_pairs_cached + fix get_pool_pair_info_cached * camelCase TokenIdentifier + Arc for token_graph & tokens_to_swappable_tokens data model * fix SwapPathPoolPair rename id to pool_pair_id, enable price_ratio * fix PriceRatio typing * sync_token_graph: execute first then wait in loop * estimated_dex_fees_in_pct * grab fab7f5f defichain-rpc * rm extra api * get_best_path * use rust_decimal * rm unuse import * fix estimated_dex_fees_in_pct * default 1 * mmv list_paths above of get_best_path * ceil * format num * fix typo * ceil * id default String * proper err for`from_token_id != to_token_id` * fix EstimatedDexFeesInPct typing * rm unuse comment * rm tokens_to_swappable_tokens & wip get_swappable_tokens api * fix get_swappable_tokens * get_swappable_tokens done * br * use format_err.into() * fix unwrap * rm println * sync_token_graph_if_empty * repl if let else by unwrap_or_default * rm ceil.. its bug * rm clone * refine recur * partialeq Network * pool.name * rm unuse pool dep * clippy * poolpair -> pool_pair * rename get_pool_pair_info_cached -> get_pool_pair_cached * refactor: mv pool_pair api to a new dir * fmt_rs * rm pp dir s * totalliquidityinusd + refactor + fix gettokencached and getpoolpaircached * swap DecimalError and SecondaryIndex * rename DecimalError to DecimalConversionError * add rust_decimal::Error as DecimalError, OverflowError and UnderflowError * get_gov_cached * wip apr * fmt_rs * fix token split value type str -> f64, get_blockchain_info eunos.height handling * total_liquidity usd typing decimal to string * sync_token_graph in tokio * fmt_rs * lint * undo defichain-rpc dep version * push latest cargo.lock updue to update of rust-defichain-rpc * fix list_pool_pairs_cached * disable cached on list pool pairs temp * lint * fmt_cpp * axum 0.7.5 * refine ocean ci * fix ocean ci * fix req: unwrap -> ok_or * fmt_rs * use expect on vec -> arr * use expect in fold --------- Co-authored-by: jouzo --- .github/workflows/tests-ocean.yml | 15 +- lib/Cargo.lock | 8 +- lib/Cargo.toml | 2 +- lib/ain-ocean/Cargo.toml | 2 + lib/ain-ocean/src/api/cache.rs | 114 +++- lib/ain-ocean/src/api/common.rs | 11 +- lib/ain-ocean/src/api/loan.rs | 9 +- lib/ain-ocean/src/api/mod.rs | 8 +- lib/ain-ocean/src/api/pool_pair/mod.rs | 617 +++++++++++++++++++++ lib/ain-ocean/src/api/pool_pair/path.rs | 521 +++++++++++++++++ lib/ain-ocean/src/api/pool_pair/service.rs | 361 ++++++++++++ lib/ain-ocean/src/api/poolpairs.rs | 215 ------- lib/ain-ocean/src/api/stats/cache.rs | 20 +- lib/ain-ocean/src/api/stats/mod.rs | 9 +- lib/ain-ocean/src/api/tokens.rs | 3 + lib/ain-ocean/src/error.rs | 10 +- lib/ain-ocean/src/indexer/masternode.rs | 3 +- lib/ain-ocean/src/indexer/transaction.rs | 2 +- lib/ain-ocean/src/lib.rs | 15 + lib/ain-ocean/src/network.rs | 2 +- lib/ain-ocean/src/repository/pool_swap.rs | 9 +- src/dfi/validation.cpp | 1 - test/lint/lint-circular-dependencies.sh | 3 +- 23 files changed, 1702 insertions(+), 258 deletions(-) create mode 100644 lib/ain-ocean/src/api/pool_pair/mod.rs create mode 100644 lib/ain-ocean/src/api/pool_pair/path.rs create mode 100644 lib/ain-ocean/src/api/pool_pair/service.rs delete mode 100644 lib/ain-ocean/src/api/poolpairs.rs diff --git a/.github/workflows/tests-ocean.yml b/.github/workflows/tests-ocean.yml index 4235d785373..b737977b678 100644 --- a/.github/workflows/tests-ocean.yml +++ b/.github/workflows/tests-ocean.yml @@ -12,7 +12,9 @@ concurrency: cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} env: + TARGET: x86_64-pc-linux-gnu MAKE_DEBUG: 0 + GIT_VERSION: 1 jobs: build: @@ -23,8 +25,6 @@ jobs: steps: - uses: actions/checkout@v4 - with: - ref: 'feature/ocean-archive' - run: git config --global --add safe.directory '*' - name: Populate environment @@ -36,10 +36,21 @@ jobs: - name: Setup user dependencies run: ./make.sh ci-setup-user-deps + - name: Restore cpp build cache + id: cpp-cache-restore + uses: actions/cache/restore@v3 + with: + path: | + ./build/depends + ./build/src + ~/.ccache + key: cpp-${{ env.TARGET }}-${{ env.BUILD_TYPE }} + - uses: Swatinem/rust-cache@v2 with: workspaces: lib -> ../build/lib/target save-if: ${{ github.ref == 'refs/heads/master' }} + shared-key: ${{ env.TARGET }} - name: Build binaries run: ./make.sh build diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 31f0308e285..7fbb2a72612 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -261,6 +261,8 @@ dependencies = [ "lazy_static", "log", "num_cpus", + "parking_lot", + "petgraph", "rocksdb", "rust_decimal", "rust_decimal_macros", @@ -1516,7 +1518,7 @@ dependencies = [ [[package]] name = "defichain-rpc" version = "0.18.0" -source = "git+https://github.com/defich/rust-defichain-rpc.git#fab7f5f9d38fe225b072087d621e8f0bf11706de" +source = "git+https://github.com/defich/rust-defichain-rpc.git#41f606433c7f3447cb5baa7e89b867ba8ae1ec88" dependencies = [ "async-trait", "defichain-rpc-json", @@ -1529,7 +1531,7 @@ dependencies = [ [[package]] name = "defichain-rpc-json" version = "0.18.0" -source = "git+https://github.com/defich/rust-defichain-rpc.git#fab7f5f9d38fe225b072087d621e8f0bf11706de" +source = "git+https://github.com/defich/rust-defichain-rpc.git#41f606433c7f3447cb5baa7e89b867ba8ae1ec88" dependencies = [ "bitcoin", "serde", @@ -3833,6 +3835,8 @@ checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", "indexmap 2.2.6", + "serde", + "serde_derive", ] [[package]] diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 433064cfcb3..1f05d06f708 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -81,7 +81,7 @@ jsonrpsee-core = "0.16" jsonrpsee-server = "0.16" jsonrpsee-types = "0.16" -axum = { version = "0.7.1", features = ["macros"] } +axum = { version = "0.7.5", features = ["macros"] } tempdir = "0.3" rocksdb = { version = "0.21", default-features = false } diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index e447dee4eed..c5e5ee1287d 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -44,6 +44,8 @@ rust_decimal = { version = "1.34", features = ["serde", "serde-float", "serde-wi rust_decimal_macros = "1.34" clap = { version = "4.5.0", features = ["derive"] } num_cpus.workspace = true +petgraph = { version = "0.6.4", features = ["serde-1"] } +parking_lot.workspace = true [dev-dependencies] tempdir.workspace = true diff --git a/lib/ain-ocean/src/api/cache.rs b/lib/ain-ocean/src/api/cache.rs index 96b95ac08bf..5703ba45c68 100644 --- a/lib/ain-ocean/src/api/cache.rs +++ b/lib/ain-ocean/src/api/cache.rs @@ -1,8 +1,14 @@ -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; -use anyhow::format_err; use cached::proc_macro::cached; -use defichain_rpc::{defichain_rpc_json::token::TokenInfo, TokenRPC}; +use defichain_rpc::{ + json::{ + poolpair::{PoolPairInfo, PoolPairPagination, PoolPairsResult}, + token::TokenInfo, + }, + jsonrpc_async::error::{Error as JsonRpcError, RpcError}, + Error, MasternodeRPC, PoolPairRPC, TokenRPC, +}; use super::AppContext; use crate::Result; @@ -12,14 +18,98 @@ use crate::Result; key = "String", convert = r#"{ format!("gettoken{symbol}") }"# )] -pub async fn get_token_cached(ctx: &Arc, symbol: &str) -> Result<(String, TokenInfo)> { - let token = ctx - .client - .get_token(symbol) - .await? - .0 - .into_iter() - .next() - .ok_or(format_err!("Error getting token info"))?; +pub async fn get_token_cached( + ctx: &Arc, + symbol: &str, +) -> Result> { + let res = ctx.client.get_token(symbol).await; + + let is_err = res.as_ref().is_err_and(|err| { + // allow `Token not found` err + err.to_string() + != Error::JsonRpc(JsonRpcError::Rpc(RpcError { + code: -5, + message: "Token not found".to_string(), + data: None, + })) + .to_string() + }); + if is_err { + return Err(res.unwrap_err().into()); + }; + + let res = res.ok(); + + let token = if let Some(res) = res { + res.0.into_iter().next() + } else { + None + }; + Ok(token) } + +#[cached( + result = true, + key = "String", + convert = r#"{ format!("getpoolpair{id}") }"# +)] +pub async fn get_pool_pair_cached( + ctx: &Arc, + id: String, +) -> Result> { + let res = ctx.client.get_pool_pair(id, Some(true)).await; + + let is_err = res.as_ref().is_err_and(|err| { + // allow `Pool not found` err + err.to_string() + != Error::JsonRpc(JsonRpcError::Rpc(RpcError { + code: -5, + message: "Pool not found".to_string(), + data: None, + })) + .to_string() + }); + if is_err { + return Err(res.unwrap_err().into()); + }; + + let res = res.ok(); + + let pool_pair = if let Some(res) = res { + res.0.into_iter().next() + } else { + None + }; + + Ok(pool_pair) +} + +// #[cached( +// result = true, +// key = "String", +// convert = r#"{ format!("listpoolpairs") }"# +// )] +pub async fn list_pool_pairs_cached(ctx: &Arc) -> Result { + let pool_pairs = ctx + .client + .list_pool_pairs( + Some(PoolPairPagination { + start: 0, + including_start: true, + limit: 1000, + }), + Some(true), + ) + .await?; + Ok(pool_pairs) +} + +#[cached(result = true, key = "String", convert = r#"{ format!("gov{id}") }"#)] +pub async fn get_gov_cached( + ctx: &Arc, + id: String, +) -> Result> { + let gov = ctx.client.get_gov(id).await?; + Ok(gov) +} diff --git a/lib/ain-ocean/src/api/common.rs b/lib/ain-ocean/src/api/common.rs index ca5397f9af4..5d91fe75a53 100644 --- a/lib/ain-ocean/src/api/common.rs +++ b/lib/ain-ocean/src/api/common.rs @@ -1,5 +1,6 @@ use defichain_rpc::json::token::TokenInfo; use rust_decimal::Decimal; +use rust_decimal_macros::dec; use super::query::PaginationQuery; @@ -20,7 +21,7 @@ pub fn parse_display_symbol(token_info: &TokenInfo) -> String { token_info.symbol.clone() } -fn parse_dat_symbol(symbol: &str) -> String { +pub fn parse_dat_symbol(symbol: &str) -> String { let special_symbols = ["DUSD", "DFI", "csETH"]; if special_symbols.contains(&symbol) { @@ -30,6 +31,14 @@ fn parse_dat_symbol(symbol: &str) -> String { } } +pub fn format_number(v: Decimal) -> String { + if v == dec!(0) { + "0".to_string() + } else { + format!("{:.8}", v) + } +} + /// Finds the balance of a specified token symbol within a list of token strings. /// /// This function iterates through a vector of token strings, where each string diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index 174d0938003..5980f8315b1 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; +use anyhow::format_err; use axum::{routing::get, Extension, Router}; use bitcoin::Txid; use defichain_rpc::{ @@ -122,7 +123,9 @@ async fn list_collateral_token( .into_iter() .fake_paginate(&query, skip_while) .map(|v| async { - let (id, info) = get_token_cached(&ctx, &v.token_id).await?; + let (id, info) = get_token_cached(&ctx, &v.token_id) + .await? + .ok_or(format_err!("None is not valid"))?; Ok::(CollateralToken::from_with_id(id, v, info)) }) .collect::>(); @@ -140,7 +143,9 @@ async fn get_collateral_token( Extension(ctx): Extension>, ) -> Result> { let collateral_token = ctx.client.get_collateral_token(token_id).await?; - let (id, info) = get_token_cached(&ctx, &collateral_token.token_id).await?; + let (id, info) = get_token_cached(&ctx, &collateral_token.token_id) + .await? + .ok_or(format_err!("None is not valid"))?; Ok(Response::new(CollateralToken::from_with_id( id, diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index f9bfcd68bde..8e253717539 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -9,7 +9,7 @@ mod governance; mod loan; mod masternode; mod oracle; -// mod poolpairs; +mod pool_pair; pub mod prices; // mod rawtx; mod cache; @@ -66,6 +66,10 @@ pub async fn ocean_router( network: Network::from_str(&network)?, }); println!("{:?}", context.network); + + let context_cloned = context.clone(); + tokio::spawn(async move { pool_pair::path::sync_token_graph(&context_cloned).await }); + Ok(Router::new().nest( format!("/v0/{}", context.network).as_str(), Router::new() @@ -75,7 +79,7 @@ pub async fn ocean_router( .nest("/fee", fee::router(Arc::clone(&context))) .nest("/masternodes", masternode::router(Arc::clone(&context))) .nest("/oracles", oracle::router(Arc::clone(&context))) - // .nest("/poolpairs", poolpairs::router(Arc::clone(&context))) + .nest("/poolpairs", pool_pair::router(Arc::clone(&context))) // .nest("/prices", prices::router(Arc::clone(&context))) // .nest("/rawtx", rawtx::router(Arc::clone(&context))) .nest("/stats", stats::router(Arc::clone(&context))) diff --git a/lib/ain-ocean/src/api/pool_pair/mod.rs b/lib/ain-ocean/src/api/pool_pair/mod.rs new file mode 100644 index 00000000000..7feb81cd0bb --- /dev/null +++ b/lib/ain-ocean/src/api/pool_pair/mod.rs @@ -0,0 +1,617 @@ +use petgraph::graphmap::UnGraphMap; +use std::{collections::HashSet, sync::Arc}; + +use ain_macros::ocean_endpoint; +use anyhow::format_err; +use axum::{routing::get, Extension, Router}; +use defichain_rpc::{ + json::{ + poolpair::{PoolPairInfo, PoolPairsResult}, + token::TokenInfo, + }, + RpcApi, +}; +use futures::future::try_join_all; +use rust_decimal::Decimal; +use rust_decimal_macros::dec; +use serde::{Deserialize, Serialize}; +use serde_json::json; + +use super::{ + cache::{get_pool_pair_cached, get_token_cached}, + common::{format_number, parse_dat_symbol}, + path::Path, + query::{PaginationQuery, Query}, + response::{ApiPagedResponse, Response}, + AppContext, +}; + +use crate::{ + error::{ApiError, Error}, + model::{BlockContext, PoolSwap}, + repository::{InitialKeyProvider, PoolSwapRepository, RepositoryOps}, + storage::SortOrder, + Result, TokenIdentifier, +}; + +use path::{ + compute_return_less_dex_fees_in_destination_token, get_all_swap_paths, get_token_identifier, + sync_token_graph_if_empty, BestSwapPathResponse, EstimatedLessDexFeeInfo, SwapPathPoolPair, + SwapPathsResponse, +}; + +use service::{get_apr, get_total_liquidity_usd}; + +pub mod path; +pub mod service; + +// #[derive(Deserialize)] +// struct PoolPair { +// id: String, +// } + +// #[derive(Deserialize)] +// struct SwapAggregate { +// id: String, +// interval: i64, +// } + +// #[derive(Debug, Deserialize)] +// struct DexPrices { +// denomination: Option, +// } + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PoolSwapFromToResponse { + address: String, + amount: String, + // symbol: String, + // display_symbol: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PoolSwapVerboseResponse { + id: String, + sort: String, + txid: String, + txno: usize, + pool_pair_id: String, + from_amount: String, + from_token_id: u64, + block: BlockContext, + from: PoolSwapFromToResponse, + to: PoolSwapFromToResponse, + // type: todo()! +} + +impl From for PoolSwapVerboseResponse { + fn from(v: PoolSwap) -> Self { + Self { + id: v.id, + sort: v.sort, + txid: v.txid.to_string(), + txno: v.txno, + pool_pair_id: v.pool_id.to_string(), + from_amount: v.from_amount.to_string(), + from_token_id: v.from_token_id, + from: PoolSwapFromToResponse { + address: v.from.to_hex_string(), + amount: v.from_amount.to_string(), + // symbol: todo!(), + // display_symbol: todo!(), + }, + to: PoolSwapFromToResponse { + address: v.to.to_hex_string(), + amount: v.to_amount.to_string(), + // symbol: todo!(), + // display_symbol: todo!(), + }, + block: v.block, + // type: todo!(), + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PoolSwapResponse { + id: String, + sort: String, + txid: String, + txno: usize, + pool_pair_id: String, + from_amount: String, + from_token_id: u64, + block: BlockContext, +} + +impl From for PoolSwapResponse { + fn from(v: PoolSwap) -> Self { + Self { + id: v.id, + sort: v.sort, + txid: v.txid.to_string(), + txno: v.txno, + pool_pair_id: v.pool_id.to_string(), + from_amount: v.from_amount.to_string(), + from_token_id: v.from_token_id, + block: v.block, + } + } +} + +#[derive(Serialize, Debug, Clone, Default)] +#[serde(rename_all = "camelCase")] +struct PoolPairFeeResponse { + pct: Option, + in_pct: Option, + out_pct: Option, +} + +#[derive(Serialize, Debug, Clone, Default)] +#[serde(rename_all = "camelCase")] +struct PoolPairTokenResponse { + id: String, + name: String, + symbol: String, + display_symbol: String, + reserve: String, + block_commission: String, + fee: Option, +} + +#[derive(Serialize, Debug, Clone, Default)] +struct PoolPairPriceRatioResponse { + ab: String, + ba: String, +} + +#[derive(Serialize, Debug, Clone, Default)] +struct PoolPairTotalLiquidityResponse { + token: Option, + usd: Option, +} + +#[derive(Serialize, Debug, Clone, Default)] +struct PoolPairCreationResponse { + tx: String, + height: i64, +} + +#[derive(Serialize, Debug, Clone, Default)] +pub struct PoolPairAprResponse { + pub total: Decimal, + pub reward: Decimal, + pub commission: Decimal, +} + +#[derive(Serialize, Debug, Clone, Default)] +struct PoolPairVolumeResponse { + d30: f64, + h24: f64, +} + +#[derive(Serialize, Debug, Clone, Default)] +#[serde(rename_all = "camelCase")] +pub struct PoolPairResponse { + id: String, + symbol: String, + display_symbol: String, + name: String, + status: bool, + token_a: PoolPairTokenResponse, + token_b: PoolPairTokenResponse, + price_ratio: PoolPairPriceRatioResponse, + commission: String, + total_liquidity: PoolPairTotalLiquidityResponse, + trade_enabled: bool, + owner_address: String, + reward_pct: String, + reward_loan_pct: String, + custom_rewards: Option>, + creation: PoolPairCreationResponse, + apr: Option, + volume: Option, +} + +impl PoolPairResponse { + pub fn from_with_id( + id: String, + p: PoolPairInfo, + a_token_name: String, + b_token_name: String, + total_liquidity_usd: Decimal, + ) -> Self { + let parts = p.symbol.split('-').collect::>(); + let [a, b] = <[&str; 2]>::try_from(parts).expect("Invalid pool pair symbol structure"); + let a_parsed = parse_dat_symbol(a); + let b_parsed = parse_dat_symbol(b); + + Self { + id, + symbol: p.symbol.clone(), + display_symbol: format!("{a_parsed}-{b_parsed}"), + name: p.name, + status: p.status, + token_a: PoolPairTokenResponse { + symbol: a.to_string(), + display_symbol: a_parsed, + id: p.id_token_a, + name: a_token_name, + reserve: p.reserve_a.to_string(), + block_commission: p.block_commission_a.to_string(), + fee: p.dex_fee_in_pct_token_a.map(|_| PoolPairFeeResponse { + pct: p.dex_fee_pct_token_a.map(|fee| fee.to_string()), + in_pct: p.dex_fee_in_pct_token_a.map(|fee| fee.to_string()), + out_pct: p.dex_fee_out_pct_token_a.map(|fee| fee.to_string()), + }), + }, + token_b: PoolPairTokenResponse { + symbol: b.to_string(), + display_symbol: b_parsed, + id: p.id_token_b, + name: b_token_name, + reserve: p.reserve_b.to_string(), + block_commission: p.block_commission_b.to_string(), + fee: p.dex_fee_in_pct_token_b.map(|_| PoolPairFeeResponse { + pct: p.dex_fee_pct_token_b.map(|fee| fee.to_string()), + in_pct: p.dex_fee_in_pct_token_b.map(|fee| fee.to_string()), + out_pct: p.dex_fee_out_pct_token_b.map(|fee| fee.to_string()), + }), + }, + price_ratio: PoolPairPriceRatioResponse { + ab: p.reserve_a_reserve_b.to_string(), + ba: p.reserve_b_reserve_a.to_string(), + }, + commission: p.commission.to_string(), + total_liquidity: PoolPairTotalLiquidityResponse { + token: Some(p.total_liquidity.to_string()), + usd: Some(total_liquidity_usd.to_string()), + }, + trade_enabled: p.trade_enabled, + owner_address: p.owner_address, + reward_pct: p.reward_pct.to_string(), + reward_loan_pct: p.reward_loan_pct.to_string(), + custom_rewards: p.custom_rewards, + creation: PoolPairCreationResponse { + tx: p.creation_tx, + height: p.creation_height, + }, + apr: None, // todo: await this.poolPairService.getAPR(id, info) + volume: None, // todo: await this.poolPairService.getUSDVolume(id) + } + } +} + +#[ocean_endpoint] +async fn list_pool_pairs( + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let pools: PoolPairsResult = ctx.client.call( + "listpoolpairs", + &[ + json!({ + "limit": query.size, + "start": query.next.as_ref().and_then(|n| n.parse::().ok()).unwrap_or_default(), + "including_start": query.next.is_none() + }), + true.into(), + ], + ).await?; + + let fut = pools + .0 + .into_iter() + .filter(|(_, p)| !p.symbol.starts_with("BURN-")) + .map(|(id, p)| async { + let ( + _, + TokenInfo { + name: a_token_name, .. + }, + ) = get_token_cached(&ctx, &p.id_token_a) + .await? + .ok_or(format_err!("None is not valid"))?; + let ( + _, + TokenInfo { + name: b_token_name, .. + }, + ) = get_token_cached(&ctx, &p.id_token_b) + .await? + .ok_or(format_err!("None is not valid"))?; + + let total_liquidity_usd = get_total_liquidity_usd(&ctx, &p).await?; + let _apr = get_apr(&ctx, &id, &p).await?; + + Ok::(PoolPairResponse::from_with_id( + id, + p, + a_token_name, + b_token_name, + total_liquidity_usd, + )) + }) + .collect::>(); + + let res = try_join_all(fut).await?; + + Ok(ApiPagedResponse::of(res, query.size, |pool| { + pool.id.clone() + })) +} + +#[ocean_endpoint] +async fn get_pool_pair( + Path(id): Path, + Extension(ctx): Extension>, +) -> Result>> { + if let Some((id, pool)) = get_pool_pair_cached(&ctx, id).await? { + let total_liquidity_usd = get_total_liquidity_usd(&ctx, &pool).await?; + let _apr = get_apr(&ctx, &id, &pool).await?; + let ( + _, + TokenInfo { + name: a_token_name, .. + }, + ) = get_token_cached(&ctx, &pool.id_token_a) + .await? + .ok_or(format_err!("None is not valid"))?; + let ( + _, + TokenInfo { + name: b_token_name, .. + }, + ) = get_token_cached(&ctx, &pool.id_token_b) + .await? + .ok_or(format_err!("None is not valid"))?; + let res = PoolPairResponse::from_with_id( + id, + pool, + a_token_name, + b_token_name, + total_liquidity_usd, + ); + return Ok(Response::new(Some(res))); + }; + + Ok(Response::new(None)) +} + +#[ocean_endpoint] +async fn list_pool_swaps( + Path(id): Path, + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let next = query + .next + .as_ref() + .map(|q| { + let parts: Vec<&str> = q.split('-').collect(); + if parts.len() != 2 { + return Err("Invalid query format"); + } + + let height = parts[0].parse::().map_err(|_| "Invalid height")?; + let txno = parts[1].parse::().map_err(|_| "Invalid txno")?; + + Ok((id, height, txno)) + }) + .transpose()? + .unwrap_or(PoolSwapRepository::initial_key(id)); + + let size = if query.size > 200 { 200 } else { query.size }; + + let swaps = ctx + .services + .pool + .by_id + .list(Some(next), SortOrder::Descending)? + .take(size) + .take_while(|item| match item { + Ok((k, _)) => k.0 == id, + _ => true, + }) + .map(|item| { + let (_, swap) = item?; + Ok(PoolSwapResponse::from(swap)) + }) + .collect::>>()?; + + Ok(ApiPagedResponse::of(swaps, query.size, |swap| { + swap.sort.to_string() + })) +} + +#[ocean_endpoint] +async fn list_pool_swaps_verbose( + Path(id): Path, + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let next = query + .next + .as_ref() + .map(|q| { + let parts: Vec<&str> = q.split('-').collect(); + if parts.len() != 2 { + return Err("Invalid query format"); + } + + let height = parts[0].parse::().map_err(|_| "Invalid height")?; + let txno = parts[1].parse::().map_err(|_| "Invalid txno")?; + + Ok((id, height, txno)) + }) + .transpose()? + .unwrap_or(PoolSwapRepository::initial_key(id)); + + let size = if query.size > 200 { 200 } else { query.size }; + + let swaps = ctx + .services + .pool + .by_id + .list(Some(next), SortOrder::Descending)? + .take(size) + .take_while(|item| match item { + Ok((k, _)) => k.0 == id, + _ => true, + }) + .map(|item| { + let (_, swap) = item?; + Ok(PoolSwapVerboseResponse::from(swap)) + }) + .collect::>>()?; + + Ok(ApiPagedResponse::of(swaps, query.size, |swap| { + swap.sort.to_string() + })) +} + +// #[ocean_endpoint] +// async fn list_pool_swap_aggregates( +// Path(SwapAggregate { id, interval }): Path, +// ) -> String { +// format!( +// "Aggregate swaps for poolpair {} over interval {}", +// id, interval +// ) +// } + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +struct AllSwappableTokensResponse { + from_token: TokenIdentifier, + swappable_tokens: Vec, +} + +#[ocean_endpoint] +async fn get_swappable_tokens( + Path(token_id): Path, + Extension(ctx): Extension>, +) -> Result> { + sync_token_graph_if_empty(&ctx).await?; + + let mut token_ids: HashSet = HashSet::new(); + + fn recur(graph: &UnGraphMap, token_ids: &mut HashSet, token_id: u32) { + if token_ids.contains(&token_id) { + return; + }; + token_ids.insert(token_id); + let edges = graph.edges(token_id).collect::>(); + for edge in edges { + recur(graph, token_ids, edge.0); + recur(graph, token_ids, edge.1); + } + } + + { + let graph = ctx.services.token_graph.lock().clone(); + recur(&graph, &mut token_ids, token_id.parse::()?); + } + + token_ids.remove(&token_id.parse::()?); + + let mut swappable_tokens = Vec::new(); + for id in token_ids.into_iter() { + let token = get_token_identifier(&ctx, &id.to_string()).await?; + swappable_tokens.push(token); + } + + Ok(Response::new(AllSwappableTokensResponse { + from_token: get_token_identifier(&ctx, &token_id).await?, + swappable_tokens, + })) +} + +#[ocean_endpoint] +async fn list_paths( + Path((token_id, to_token_id)): Path<(String, String)>, + Extension(ctx): Extension>, +) -> Result> { + let res = get_all_swap_paths(&ctx, &token_id, &to_token_id).await?; + + Ok(Response::new(res)) +} + +#[ocean_endpoint] +async fn get_best_path( + Path((from_token_id, to_token_id)): Path<(String, String)>, + Extension(ctx): Extension>, +) -> Result> { + let SwapPathsResponse { + from_token, + to_token, + paths, + } = get_all_swap_paths(&ctx, &from_token_id, &to_token_id).await?; + + let mut best_path = Vec::::new(); + let mut best_return = dec!(0); + let mut best_return_less_dex_fees = dec!(0); + + for path in paths { + let path_len = path.len(); + let EstimatedLessDexFeeInfo { + estimated_return, + estimated_return_less_dex_fees, + } = compute_return_less_dex_fees_in_destination_token(&path, &from_token_id).await?; + + if path_len == 1 { + return Ok(Response::new(BestSwapPathResponse { + from_token, + to_token, + best_path: path, + estimated_return: format_number(estimated_return), + estimated_return_less_dex_fees: format_number(estimated_return_less_dex_fees), + })); + }; + + if estimated_return > best_return { + best_return = estimated_return; + } + + if estimated_return_less_dex_fees > best_return_less_dex_fees { + best_return_less_dex_fees = estimated_return_less_dex_fees; + best_path = path; + }; + } + + Ok(Response::new(BestSwapPathResponse { + from_token, + to_token, + best_path, + estimated_return: format_number(best_return), + estimated_return_less_dex_fees: format_number(best_return_less_dex_fees), + })) +} + +// #[ocean_endpoint] +// async fn list_dex_prices(Query(DexPrices { denomination }): Query) -> String { +// format!("List of DEX prices with denomination {:?}", denomination) +// } + +pub fn router(ctx: Arc) -> Router { + Router::new() + .route("/", get(list_pool_pairs)) + .route("/:id", get(get_pool_pair)) + .route("/:id/swaps", get(list_pool_swaps)) + .route("/:id/swaps/verbose", get(list_pool_swaps_verbose)) + .route("/paths/from/:fromTokenId/to/:toTokenId", get(list_paths)) + .route( + "/paths/best/from/:fromTokenId/to/:toTokenId", + get(get_best_path), + ) + // .route( + // "/:id/swaps/aggregate/:interval", + // get(list_pool_swap_aggregates), + // ) + .route("/paths/swappable/:tokenId", get(get_swappable_tokens)) + // .route("/dexprices", get(list_dex_prices)) + .layer(Extension(ctx)) +} diff --git a/lib/ain-ocean/src/api/pool_pair/path.rs b/lib/ain-ocean/src/api/pool_pair/path.rs new file mode 100644 index 00000000000..f31a09d4c52 --- /dev/null +++ b/lib/ain-ocean/src/api/pool_pair/path.rs @@ -0,0 +1,521 @@ +use std::{collections::HashSet, str::FromStr, sync::Arc, time::Duration}; + +use anyhow::format_err; +use defichain_rpc::json::poolpair::PoolPairInfo; +use rust_decimal::{prelude::FromPrimitive, Decimal}; +use rust_decimal_macros::dec; +use serde::Serialize; + +use super::AppContext; + +use crate::{ + api::{ + cache::{get_pool_pair_cached, get_token_cached, list_pool_pairs_cached}, + common::{format_number, parse_dat_symbol}, + }, + network::Network, + Result, TokenIdentifier, +}; + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +struct PriceRatio { + ab: String, + ba: String, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +struct EstimatedDexFeesInPct { + ab: String, + ba: String, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SwapPathPoolPair { + pool_pair_id: String, + symbol: String, + token_a: TokenIdentifier, + token_b: TokenIdentifier, + price_ratio: PriceRatio, + commission_fee_in_pct: String, + #[serde(skip_serializing_if = "Option::is_none")] + estimated_dex_fees_in_pct: Option, +} + +#[derive(Debug)] +pub struct EstimatedLessDexFeeInfo { + pub estimated_return: Decimal, + pub estimated_return_less_dex_fees: Decimal, +} + +#[derive(Debug)] +struct StackSet { + set: HashSet, + stack: Vec, + size: usize, +} + +impl StackSet { + fn new() -> Self { + Self { + set: HashSet::new(), + stack: Vec::new(), + size: 0, + } + } + + fn has(&self, value: &u32) -> bool { + self.set.contains(value) + } + + fn push(&mut self, value: u32) { + self.stack.push(value); + self.set.insert(value); + self.size += 1; + } + + fn pop(&mut self) { + if let Some(value) = self.stack.pop() { + self.set.remove(&value); + self.size -= 1; + } + } + + fn path(&self, value: u32) -> Vec { + let mut path = self.stack.clone(); + path.push(value); + path + } + + fn of(value: u32, is_cycle: bool) -> Self { + let mut set = StackSet::new(); + if !is_cycle { + set.push(value); + } else { + set.stack.push(value); + } + set + } +} + +pub async fn get_token_identifier(ctx: &Arc, id: &str) -> Result { + let (id, token) = get_token_cached(ctx, id).await?.unwrap(); + Ok(TokenIdentifier { + id, + display_symbol: parse_dat_symbol(&token.symbol), + name: token.name, + symbol: token.symbol, + }) +} + +pub async fn get_all_swap_paths( + ctx: &Arc, + from_token_id: &String, + to_token_id: &String, +) -> Result { + sync_token_graph_if_empty(ctx).await?; + + if from_token_id == to_token_id { + return Err(format_err!("Invalid tokens: fromToken must be different from toToken").into()); + } + + let mut res = SwapPathsResponse { + from_token: get_token_identifier(ctx, from_token_id).await?, + to_token: get_token_identifier(ctx, to_token_id).await?, + paths: vec![], + }; + + if !ctx + .services + .token_graph + .lock() + .contains_node(from_token_id.parse::()?) + || !ctx + .services + .token_graph + .lock() + .contains_node(to_token_id.parse::()?) + { + return Ok(res); + } + + res.paths = compute_paths_between_tokens(ctx, from_token_id, to_token_id).await?; + + Ok(res) +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SwapPathsResponse { + pub from_token: TokenIdentifier, + pub to_token: TokenIdentifier, + pub paths: Vec>, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct BestSwapPathResponse { + pub from_token: TokenIdentifier, + pub to_token: TokenIdentifier, + pub best_path: Vec, + pub estimated_return: String, + pub estimated_return_less_dex_fees: String, +} + +pub async fn get_best_path( + ctx: &Arc, + from_token_id: &String, + to_token_id: &String, +) -> Result { + let SwapPathsResponse { + from_token, + to_token, + paths, + } = get_all_swap_paths(ctx, from_token_id, to_token_id).await?; + + let mut best_path = Vec::::new(); + let mut best_return = dec!(0); + let mut best_return_less_dex_fees = dec!(0); + + for path in paths { + let path_len = path.len(); + let EstimatedLessDexFeeInfo { + estimated_return, + estimated_return_less_dex_fees, + } = compute_return_less_dex_fees_in_destination_token(&path, from_token_id).await?; + + if path_len == 1 { + return Ok(BestSwapPathResponse { + from_token, + to_token, + best_path: path, + estimated_return: format_number(estimated_return), + estimated_return_less_dex_fees: format_number(estimated_return_less_dex_fees), + }); + }; + + if estimated_return > best_return { + best_return = estimated_return; + } + + if estimated_return_less_dex_fees > best_return_less_dex_fees { + best_return_less_dex_fees = estimated_return_less_dex_fees; + best_path = path; + }; + } + + Ok(BestSwapPathResponse { + from_token, + to_token, + best_path, + estimated_return: format_number(best_return), + estimated_return_less_dex_fees: format_number(best_return_less_dex_fees), + }) +} + +fn all_simple_paths( + ctx: &Arc, + from_token_id: &str, + to_token_id: &str, +) -> Result>> { + let from_token_id = from_token_id.parse::()?; + let to_token_id = to_token_id.parse::()?; + + let graph = &ctx.services.token_graph; + if !graph.lock().contains_node(from_token_id) { + return Err(format_err!("from_token_id not found: {:?}", from_token_id).into()); + } + if !graph.lock().contains_node(to_token_id) { + return Err(format_err!("to_token_id not found: {:?}", to_token_id).into()); + } + + let is_cycle = from_token_id == to_token_id; + + let mut stack = vec![graph + .lock() + .neighbors_directed(from_token_id, petgraph::Direction::Outgoing) + .collect::>()]; + let mut visited = StackSet::of(from_token_id, is_cycle); + + let mut paths: Vec> = Vec::new(); + while !stack.is_empty() { + let child = stack.last_mut().and_then(|s| s.pop()); + if let Some(child) = child { + if visited.has(&child) { + continue; + } + if child == to_token_id { + let mut p = visited.path(child); + if is_cycle { + p[0] = from_token_id; + } + paths.push(p); + } + visited.push(child); + if !visited.has(&to_token_id) { + stack.push( + graph + .lock() + .neighbors_directed(child, petgraph::Direction::Outgoing) + .collect::>(), + ) + } else { + visited.pop(); + } + } else { + stack.pop(); + visited.pop(); + } + } + + Ok(paths) +} + +pub async fn compute_paths_between_tokens( + ctx: &Arc, + from_token_id: &String, + to_token_id: &String, +) -> Result>> { + let mut pool_pair_paths = Vec::new(); + + let graph = &ctx.services.token_graph; + + let paths = all_simple_paths(ctx, from_token_id, to_token_id)?; + + for path in paths { + if path.len() > 4 { + continue; + } + + let mut pool_pairs = Vec::new(); + + for i in 1..path.len() { + let token_a = path[i - 1]; + let token_b = path[i]; + + let pool_pair_id = graph + .lock() + .edge_weight(token_a, token_b) + .ok_or_else(|| { + format_err!( + "Unexpected error encountered during path finding - could not find edge between {} and {}", + token_a, + token_b + ) + })? + .to_string(); + + let pool = get_pool_pair_cached(ctx, pool_pair_id.clone()).await?; + if pool.is_none() { + return Err(format_err!("Pool pair by id {pool_pair_id} not found").into()); + } + + let (_, pool_pair_info) = pool.unwrap(); + + let PoolPairInfo { + symbol, + id_token_a, + id_token_b, + reserve_a_reserve_b: ab, + reserve_b_reserve_a: ba, + commission, + dex_fee_in_pct_token_a, + dex_fee_out_pct_token_a, + dex_fee_in_pct_token_b, + dex_fee_out_pct_token_b, + .. + } = pool_pair_info; + + let token_a_direction = if id_token_a == *from_token_id { + "in" + } else { + "out" + }; + + let token_b_direction = if id_token_b == *to_token_id { + "out" + } else { + "in" + }; + + let estimated_dex_fees_in_pct = if let ( + Some(dex_fee_in_pct_token_a), + Some(dex_fee_out_pct_token_a), + Some(dex_fee_in_pct_token_b), + Some(dex_fee_out_pct_token_b), + ) = ( + dex_fee_in_pct_token_a, + dex_fee_out_pct_token_a, + dex_fee_in_pct_token_b, + dex_fee_out_pct_token_b, + ) { + Some(EstimatedDexFeesInPct { + ba: if token_a_direction == "in" { + format!("{:.8}", dex_fee_in_pct_token_a) + } else { + format!("{:.8}", dex_fee_out_pct_token_a) + }, + ab: if token_b_direction == "in" { + format!("{:.8}", dex_fee_in_pct_token_b) + } else { + format!("{:.8}", dex_fee_out_pct_token_b) + }, + }) + } else { + None + }; + + let swap_path_pool_pair = SwapPathPoolPair { + pool_pair_id, + symbol, + token_a: get_token_identifier(ctx, &id_token_a).await?, + token_b: get_token_identifier(ctx, &id_token_b).await?, + price_ratio: PriceRatio { + ab: format_number(Decimal::from_f64(ab).unwrap_or_default()), + ba: format_number(Decimal::from_f64(ba).unwrap_or_default()), + }, + commission_fee_in_pct: format_number( + Decimal::from_f64(commission).unwrap_or_default(), + ), + estimated_dex_fees_in_pct, + }; + + pool_pairs.push(swap_path_pool_pair); + } + + pool_pair_paths.push(pool_pairs); + } + + Ok(pool_pair_paths) +} + +pub async fn compute_return_less_dex_fees_in_destination_token( + path: &Vec, + from_token_id: &String, +) -> Result { + let mut estimated_return_less_dex_fees = dec!(1); + let mut estimated_return = dec!(1); + + let mut from_token_id = from_token_id.to_owned(); + let mut price_ratio; + let mut from_token_fee_pct; + let mut to_token_fee_pct; + + for pool in path { + if from_token_id == pool.token_a.id { + from_token_id = pool.token_b.id.to_owned(); + price_ratio = Decimal::from_str(pool.price_ratio.ba.as_str())?; + (from_token_fee_pct, to_token_fee_pct) = + if let Some(estimated_dex_fees_in_pct) = &pool.estimated_dex_fees_in_pct { + let ba = Decimal::from_str(estimated_dex_fees_in_pct.ba.as_str())?; + let ab = Decimal::from_str(estimated_dex_fees_in_pct.ab.as_str())?; + (Some(ba), Some(ab)) + } else { + (None, None) + }; + } else { + from_token_id = pool.token_a.id.to_owned(); + price_ratio = + Decimal::from_str(pool.price_ratio.ab.as_str()).map_err(|e| format_err!(e))?; + (from_token_fee_pct, to_token_fee_pct) = + if let Some(estimated_dex_fees_in_pct) = &pool.estimated_dex_fees_in_pct { + let ab = Decimal::from_str(estimated_dex_fees_in_pct.ab.as_str()) + .map_err(|e| format_err!(e))?; + let ba = Decimal::from_str(estimated_dex_fees_in_pct.ba.as_str()) + .map_err(|e| format_err!(e))?; + (Some(ab), Some(ba)) + } else { + (None, None) + }; + }; + + estimated_return = estimated_return + .checked_mul(price_ratio) + .ok_or_else(|| format_err!("estimated_return overflow"))?; + + // less commission fee + let commission_fee_in_pct = + Decimal::from_str(pool.commission_fee_in_pct.as_str()).map_err(|e| format_err!(e))?; + let commission_fee = estimated_return_less_dex_fees + .checked_mul(commission_fee_in_pct) + .ok_or_else(|| format_err!("commission_fee overflow"))?; + estimated_return_less_dex_fees = estimated_return_less_dex_fees + .checked_sub(commission_fee) + .ok_or_else(|| format_err!("estimated_return_less_dex_fees underflow"))?; + + // less dex fee from_token + let from_token_estimated_dex_fee = from_token_fee_pct + .unwrap_or_default() + .checked_mul(estimated_return_less_dex_fees) + .ok_or_else(|| format_err!("from_token_fee_pct overflow"))?; + + estimated_return_less_dex_fees = estimated_return_less_dex_fees + .checked_sub(from_token_estimated_dex_fee) + .ok_or_else(|| format_err!("estimated_return_less_dex_fees underflow"))?; + + // convert to to_token + let from_token_estimated_return_less_dex_fee = estimated_return_less_dex_fees + .checked_mul(price_ratio) + .ok_or_else(|| format_err!("from_token_estimated_return_less_dex_fee overflow"))?; + let to_token_estimated_dex_fee = to_token_fee_pct + .unwrap_or_default() + .checked_mul(from_token_estimated_return_less_dex_fee) + .ok_or_else(|| format_err!("to_token_estimated_dex_fee overflow"))?; + + // less dex fee to_token + estimated_return_less_dex_fees = from_token_estimated_return_less_dex_fee + .checked_sub(to_token_estimated_dex_fee) + .ok_or_else(|| format_err!("estimated_return_less_dex_fees underflow"))?; + } + + Ok(EstimatedLessDexFeeInfo { + estimated_return, + estimated_return_less_dex_fees, + }) +} + +pub async fn sync_token_graph(ctx: &Arc) -> Result<()> { + let mut interval = tokio::time::interval(Duration::from_secs(120)); + + loop { + let pools = list_pool_pairs_cached(ctx).await?; + + // addTokensAndConnectionsToGraph + for (k, v) in pools.0 { + // isPoolPairIgnored + if !v.status { + continue; + } + // skip mainnet BURN-DFI pool + if ctx.network == Network::Mainnet && k == "48" { + continue; + } + let id_token_a = v.id_token_a.parse::()?; + let id_token_b = v.id_token_b.parse::()?; + let graph = &ctx.services.token_graph; + if !graph.lock().contains_node(id_token_a) { + graph.lock().add_node(id_token_a); + } + if !graph.lock().contains_node(id_token_b) { + graph.lock().add_node(id_token_b); + } + if !graph.lock().contains_edge(id_token_a, id_token_b) { + graph.lock().add_edge(id_token_a, id_token_b, k); + } + } + + // wait 120s + interval.tick().await; + } // end of loop +} + +pub async fn sync_token_graph_if_empty(ctx: &Arc) -> Result<()> { + if ctx.services.token_graph.lock().edge_count() == 0 { + let ctx_cloned = ctx.clone(); + tokio::spawn(async move { sync_token_graph(&ctx_cloned).await }); + return Ok(()); + }; + Ok(()) +} diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs new file mode 100644 index 00000000000..a8cf4d19ca4 --- /dev/null +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -0,0 +1,361 @@ +use anyhow::format_err; +use defichain_rpc::{json::poolpair::PoolPairInfo, BlockchainRPC}; +use rust_decimal::{prelude::FromPrimitive, Decimal}; +use rust_decimal_macros::dec; +use std::{str::FromStr, sync::Arc}; + +use super::{AppContext, PoolPairAprResponse}; + +use crate::{ + api::cache::{get_gov_cached, get_pool_pair_cached, get_token_cached}, + api::pool_pair::path::{get_best_path, BestSwapPathResponse}, + error::Error, + Result, +}; + +async fn get_usd_per_dfi(ctx: &Arc) -> Result { + let usdt = get_pool_pair_cached(ctx, "USDT-DFI".to_string()).await?; + + let usdc = get_pool_pair_cached(ctx, "USDC-DFI".to_string()).await?; + + let mut total_usd = dec!(0); + let mut total_dfi = dec!(0); + + fn add( + p: PoolPairInfo, + mut total_usd: Decimal, + mut total_dfi: Decimal, + ) -> Result<(Decimal, Decimal)> { + let reserve_a = Decimal::from_f64(p.reserve_a).unwrap_or_default(); + let reserve_b = Decimal::from_f64(p.reserve_b).unwrap_or_default(); + if p.id_token_a == "0" { + total_usd = total_usd + .checked_add(reserve_b) + .ok_or_else(|| Error::OverflowError)?; + total_dfi = total_dfi + .checked_add(reserve_a) + .ok_or_else(|| Error::OverflowError)?; + } else if p.id_token_b == "0" { + total_usd = total_usd + .checked_add(reserve_a) + .ok_or_else(|| Error::OverflowError)?; + total_dfi = total_dfi + .checked_add(reserve_b) + .ok_or_else(|| Error::OverflowError)?; + } + Ok((total_usd, total_dfi)) + } + + if let Some((_, usdt)) = usdt { + (total_usd, total_dfi) = add(usdt, total_usd, total_dfi)?; + }; + + if let Some((_, usdc)) = usdc { + (total_usd, total_dfi) = add(usdc, total_usd, total_dfi)?; + }; + + if !total_usd.is_zero() { + let res = total_usd + .checked_div(total_dfi) + .ok_or_else(|| Error::UnderflowError)?; + return Ok(res); + }; + + Ok(dec!(0)) +} + +async fn get_total_liquidity_usd_by_best_path( + ctx: &Arc, + p: &PoolPairInfo, +) -> Result { + let (usdt_id, _) = get_token_cached(ctx, "USDT").await?.unwrap(); + + let mut a_token_rate = dec!(1); + let mut b_token_rate = dec!(1); + + if p.id_token_a != usdt_id { + let BestSwapPathResponse { + estimated_return, .. + } = get_best_path(ctx, &p.id_token_a, &usdt_id).await?; + a_token_rate = Decimal::from_str(estimated_return.as_str())?; + } + + if p.id_token_a != usdt_id { + let BestSwapPathResponse { + estimated_return, .. + } = get_best_path(ctx, &p.id_token_b, &usdt_id).await?; + b_token_rate = Decimal::from_str(estimated_return.as_str())?; + } + + let reserve_a = Decimal::from_f64(p.reserve_a).unwrap_or_default(); + let reserve_b = Decimal::from_f64(p.reserve_b).unwrap_or_default(); + + let a = a_token_rate + .checked_mul(reserve_a) + .ok_or_else(|| Error::OverflowError)?; + + let b = b_token_rate + .checked_mul(reserve_b) + .ok_or_else(|| Error::OverflowError)?; + + let res = a.checked_add(b).ok_or_else(|| Error::OverflowError)?; + + Ok(res) +} + +pub async fn get_total_liquidity_usd(ctx: &Arc, p: &PoolPairInfo) -> Result { + let parts = p.symbol.split('-').collect::>(); + let [a, b] = <[&str; 2]>::try_from(parts).expect("Invalid pool pair symbol structure"); + + let reserve_a = Decimal::from_f64(p.reserve_a).unwrap_or_default(); + let reserve_b = Decimal::from_f64(p.reserve_b).unwrap_or_default(); + + if ["DUSD", "USDT", "USDC"].contains(&a) { + return reserve_a + .checked_mul(dec!(2)) + .ok_or_else(|| Error::OverflowError); + }; + + if ["DUSD", "USDT", "USDC"].contains(&b) { + return reserve_b + .checked_mul(dec!(2)) + .ok_or_else(|| Error::OverflowError); + }; + + let usdt_per_dfi = get_usd_per_dfi(ctx).await?; + if usdt_per_dfi.is_zero() { + return Ok(usdt_per_dfi); + }; + + if a == "DFI" { + return reserve_a + .checked_mul(dec!(2)) + .ok_or_else(|| Error::OverflowError)? + .checked_mul(usdt_per_dfi) + .ok_or_else(|| Error::OverflowError); + }; + + if b == "DFI" { + return reserve_b + .checked_mul(dec!(2)) + .ok_or_else(|| Error::OverflowError)? + .checked_mul(usdt_per_dfi) + .ok_or_else(|| Error::OverflowError); + }; + + let res = get_total_liquidity_usd_by_best_path(ctx, p).await?; + Ok(res) +} + +async fn get_yearly_custom_reward_usd(ctx: &Arc, p: &PoolPairInfo) -> Result { + if p.custom_rewards.is_none() { + return Ok(dec!(0)); + }; + + let dfi_price_usdt = get_usd_per_dfi(ctx).await?; + if dfi_price_usdt.is_zero() { + return Ok(dfi_price_usdt); + }; + + let rewards = if let Some(custom_rewards) = &p.custom_rewards { + let total = custom_rewards + .iter() + .fold(dec!(0), |accumulate: Decimal, account: &String| { + let parts = account.split('-').collect::>(); + let [amount, token] = + <[&str; 2]>::try_from(parts).expect("Invalid pool pair symbol structure"); + if token != "0" && token != "DFI" { + return accumulate; + }; + + let yearly = Decimal::from_str(amount) + .expect("convert numeric string to number error") + .checked_mul(dec!(2880)) + .and_then(|v| v.checked_mul(dec!(365))) + .and_then(|v| v.checked_mul(dfi_price_usdt)) + .expect("yearly reward overflow err"); + + accumulate + .checked_add(yearly) + .expect("accumlate reward overflow err") + }); + + total + } else { + dec!(0) + }; + + Ok(rewards) +} + +async fn get_daily_dfi_reward(ctx: &Arc) -> Result { + let gov = get_gov_cached(ctx, "LP_DAILY_DFI_REWARD".to_string()).await?; + + let reward = gov + .get("LP_DAILY_DFI_REWARD") + .and_then(|v| v.as_f64()) // eg: { "LP_DAILY_DFI_REWARD": 3664.80000000 } + .unwrap_or_default(); + + let daily_dfi_reward = + Decimal::from_f64(reward).ok_or_else(|| Error::DecimalConversionError)?; + Ok(daily_dfi_reward) +} + +async fn get_loan_token_splits(ctx: &Arc) -> Result> { + let splits = get_gov_cached(ctx, "LP_LOAN_TOKEN_SPLITS".to_string()) + .await? + .get("LP_LOAN_TOKEN_SPLITS") + .cloned(); + Ok(splits) +} + +async fn get_yearly_reward_pct_usd(ctx: &Arc, p: &PoolPairInfo) -> Result { + // if p.reward_pct.is_none() { + // return dec!(0) + // }; + + let dfi_price_usd = get_usd_per_dfi(ctx).await?; + let daily_dfi_reward = get_daily_dfi_reward(ctx).await?; + + let reward_pct = Decimal::from_f64(p.reward_pct).unwrap_or_default(); + reward_pct + .checked_mul(daily_dfi_reward) + .ok_or_else(|| Error::OverflowError)? + .checked_mul(dec!(365)) + .ok_or_else(|| Error::OverflowError)? + .checked_mul(dfi_price_usd) + .ok_or_else(|| Error::OverflowError) +} + +async fn get_block_subsidy(eunos_height: u32, height: u32) -> Result { + let eunos_height = + Decimal::from_u32(eunos_height).ok_or_else(|| Error::DecimalConversionError)?; + let height = Decimal::from_u32(height).ok_or_else(|| Error::DecimalConversionError)?; + let mut block_subsidy = dec!(405.04); + + if height >= eunos_height { + let reduction_amount = dec!(0.01658); // 1.658% + let mut reductions = height + .checked_sub(eunos_height) + .ok_or_else(|| Error::UnderflowError)? + .checked_div(dec!(32690)) + .ok_or_else(|| Error::UnderflowError)? + .floor(); + + while reductions >= dec!(0) { + let amount = reduction_amount + .checked_mul(block_subsidy) + .ok_or_else(|| Error::OverflowError)?; + if amount <= dec!(0.00001) { + return Ok(dec!(0)); + }; + block_subsidy = block_subsidy + .checked_sub(amount) + .ok_or_else(|| Error::UnderflowError)?; + reductions = reductions + .checked_sub(dec!(1)) + .ok_or_else(|| Error::UnderflowError)?; + } + }; + + Ok(block_subsidy) +} + +// TODO(): cached +async fn get_loan_emission(ctx: &Arc) -> Result { + let info = ctx.client.get_blockchain_info().await?; + let eunos_height = info + .softforks + .get("eunos") + .and_then(|eunos| eunos.height) + .ok_or_else(|| format_err!("BlockchainInfo eunos height field is missing"))?; + + get_block_subsidy(eunos_height, info.blocks).await +} + +async fn get_yearly_reward_loan_usd(ctx: &Arc, id: &String) -> Result { + let splits = get_loan_token_splits(ctx).await?; + let value = splits.unwrap_or_default(); + let split = value + .as_object() + .and_then(|obj| obj.get(id)) + .and_then(|v| v.as_f64()) + .unwrap_or_default(); + let split = Decimal::from_f64(split).ok_or_else(|| Error::DecimalConversionError)?; + + let dfi_price_usd = get_usd_per_dfi(ctx).await?; + + let loan_emission = get_loan_emission(ctx).await?; + + loan_emission + .checked_mul(split) // 60 * 60 * 24 / 30, 30 seconds = 1 block + .ok_or_else(|| Error::OverflowError)? + .checked_mul(dec!(2880)) // 60 * 60 * 24 / 30, 30 seconds = 1 block + .ok_or_else(|| Error::OverflowError)? + .checked_mul(dec!(365)) // 60 * 60 * 24 / 30, 30 seconds = 1 block + .ok_or_else(|| Error::OverflowError)? + .checked_mul(dfi_price_usd) // 60 * 60 * 24 / 30, 30 seconds = 1 block + .ok_or_else(|| Error::OverflowError) +} + +// TODO(): poolswap aggregate required +async fn get_usd_volume(id: &String) -> Result { + println!("id: {:?}", id); + Ok(dec!(0)) +} + +/// Estimate yearly commission rate by taking 24 hour commission x 365 days +async fn get_yearly_commission_estimate(id: &String, p: &PoolPairInfo) -> Result { + let volume = get_usd_volume(id).await?; + let commission = Decimal::from_f64(p.commission).unwrap_or_default(); + commission + .checked_mul(volume) + .ok_or_else(|| Error::OverflowError)? + .checked_mul(dec!(365)) + .ok_or_else(|| Error::OverflowError) +} + +pub async fn get_apr( + ctx: &Arc, + id: &String, + p: &PoolPairInfo, +) -> Result> { + let custom_usd = get_yearly_custom_reward_usd(ctx, p).await?; + let pct_usd = get_yearly_reward_pct_usd(ctx, p).await?; + let loan_usd = get_yearly_reward_loan_usd(ctx, id).await?; + let total_liquidity_usd = get_total_liquidity_usd(ctx, p).await?; + + if custom_usd.is_zero() + || pct_usd.is_zero() + || loan_usd.is_zero() + || total_liquidity_usd.is_zero() + { + return Ok(None); + }; + + let yearly_usd = custom_usd + .checked_add(pct_usd) + .ok_or_else(|| Error::OverflowError)? + .checked_add(loan_usd) + .ok_or_else(|| Error::OverflowError)?; + + // 1 == 100%, 0.1 = 10% + let reward = yearly_usd + .checked_div(total_liquidity_usd) + .ok_or_else(|| Error::UnderflowError)?; + + let yearly_commission = get_yearly_commission_estimate(id, p).await?; + let commission = yearly_commission + .checked_div(total_liquidity_usd) + .ok_or_else(|| Error::UnderflowError)?; + + let total = reward + .checked_add(commission) + .ok_or_else(|| Error::OverflowError)?; + + Ok(Some(PoolPairAprResponse { + reward, + commission, + total, + })) +} diff --git a/lib/ain-ocean/src/api/poolpairs.rs b/lib/ain-ocean/src/api/poolpairs.rs deleted file mode 100644 index 89a42372034..00000000000 --- a/lib/ain-ocean/src/api/poolpairs.rs +++ /dev/null @@ -1,215 +0,0 @@ -use std::sync::Arc; - -use axum::{ - extract::{Path, Query}, - routing::get, - Json, Router, -}; -use defichain_rpc::{Client, RpcApi}; -use log::debug; -use serde::{Deserialize, Serialize}; - -use crate::{ - api_paged_response::ApiPagedResponse, - api_query::PaginationQuery, - model::{BlockContext, PoolSwap}, - repository::RepositoryOps, - services, Result, -}; - -#[derive(Deserialize)] -struct PoolPair { - id: String, -} - -#[derive(Deserialize)] -struct SwapAggregate { - id: String, - interval: i64, -} - -#[derive(Deserialize)] -struct SwappableTokens { - token_id: String, -} - -#[derive(Deserialize)] -struct BestPath { - from_token_id: String, - to_token_id: String, -} - -#[derive(Debug, Deserialize)] -struct DexPrices { - denomination: Option, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct PoolSwapFromToData { - address: String, - amount: String, - // symbol: String, - // display_symbol: String, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct PoolSwapData { - id: String, - sort: String, - txid: String, - txno: usize, - pool_pair_id: String, - from_amount: String, - from_token_id: u64, - block: BlockContext, - from: PoolSwapFromToData, - to: PoolSwapFromToData, -} - -impl From for PoolSwapData { - fn from(v: PoolSwap) -> Self { - Self { - id: v.id, - sort: v.sort, - txid: v.txid.to_string(), - txno: v.txno, - pool_pair_id: v.pool_id.to_string(), - from_amount: v.from_amount.to_string(), - from_token_id: v.from_token_id, - from: PoolSwapFromToData { - address: v.from.to_hex_string(), - amount: v.from_amount.to_string(), - // symbol: todo!(), - // display_symbol: todo!(), - }, - to: PoolSwapFromToData { - address: v.to.to_hex_string(), - amount: v.to_amount.to_string(), - // symbol: todo!(), - // display_symbol: todo!(), - }, - block: v.block, - } - } -} - -async fn list_poolpairs() -> String { - "List of poolpairs".to_string() -} - -async fn get_poolpair(Path(PoolPair { id }): Path) -> String { - format!("Details of poolpair with id {}", id) -} - -// Use single method for now since additional verbose keys are indexed -// TODO: assess need for additional verbose method -async fn list_pool_swaps( - Path(id): Path, - Query(query): Query, -) -> Result>> { - debug!("list_pool_swaps for id {id}",); - let next = query - .next - .map(|q| { - let parts: Vec<&str> = q.split('-').collect(); - if parts.len() != 2 { - return Err("Invalid query format"); - } - - let height = parts[0].parse::().map_err(|_| "Invalid height")?; - let txno = parts[1].parse::().map_err(|_| "Invalid txno")?; - - Ok((height, txno)) - }) - .transpose()? - .unwrap_or_default(); - - debug!("next : {:?}", next); - - let size = if query.size > 0 && query.size < 20 { - query.size - } else { - 20 - }; - - let swaps = services - .pool - .by_id - .list(Some((id, next.0, next.1)))? - .take(size) - .take_while(|item| match item { - Ok((k, _)) => k.0 == id, - _ => true, - }) - .map(|item| { - let (_, swap) = item?; - Ok(PoolSwapData::from(swap)) - }) - .collect::>>()?; - - Ok(Json(ApiPagedResponse::of(swaps, query.size, |swap| { - swap.sort.to_string() - }))) -} - -async fn list_pool_swap_aggregates( - Path(SwapAggregate { id, interval }): Path, -) -> String { - format!( - "Aggregate swaps for poolpair {} over interval {}", - id, interval - ) -} - -async fn get_swappable_tokens(Path(SwappableTokens { token_id }): Path) -> String { - format!("Swappable tokens for token id {}", token_id) -} - -async fn get_best_path( - Query(BestPath { - from_token_id, - to_token_id, - }): Query, -) -> String { - format!( - "Best path from token id {} to {}", - from_token_id, to_token_id - ) -} - -async fn get_all_paths( - Query(BestPath { - from_token_id, - to_token_id, - }): Query, -) -> String { - format!( - "All paths from token id {} to {}", - from_token_id, to_token_id - ) -} - -async fn list_dex_prices(Query(DexPrices { denomination }): Query) -> String { - format!("List of DEX prices with denomination {:?}", denomination) -} - -pub fn router(ctx: Arc) -> Router { - Router::new() - .route("/", get(list_poolpairs)) - .route("/:id", get(get_poolpair)) - .route("/:id/swaps", get(list_pool_swaps)) - .route("/:id/swaps/verbose", get(list_pool_swaps)) - .route( - "/:id/swaps/aggregate/:interval", - get(list_pool_swap_aggregates), - ) - .route("/paths/swappable/:tokenId", get(get_swappable_tokens)) - .route( - "/paths/best/from/:fromTokenId/to/:toTokenId", - get(get_best_path), - ) - .route("/paths/from/:fromTokenId/to/:toTokenId", get(get_all_paths)) - .route("/dexprices", get(list_dex_prices)) -} diff --git a/lib/ain-ocean/src/api/stats/cache.rs b/lib/ain-ocean/src/api/stats/cache.rs index 9ddef3b7cf1..672a694a59c 100644 --- a/lib/ain-ocean/src/api/stats/cache.rs +++ b/lib/ain-ocean/src/api/stats/cache.rs @@ -37,10 +37,11 @@ pub struct Burned { pub async fn get_burned(client: &Client) -> Result { let burn_info = client.get_burn_info().await?; - let utxo = Decimal::from_f64(burn_info.amount).ok_or(Error::DecimalError)?; - let emission = Decimal::from_f64(burn_info.emissionburn).ok_or(Error::DecimalError)?; - let fee = Decimal::from_f64(burn_info.feeburn).ok_or(Error::DecimalError)?; - let auction = Decimal::from_f64(burn_info.auctionburn).ok_or(Error::DecimalError)?; + let utxo = Decimal::from_f64(burn_info.amount).ok_or(Error::DecimalConversionError)?; + let emission = + Decimal::from_f64(burn_info.emissionburn).ok_or(Error::DecimalConversionError)?; + let fee = Decimal::from_f64(burn_info.feeburn).ok_or(Error::DecimalConversionError)?; + let auction = Decimal::from_f64(burn_info.auctionburn).ok_or(Error::DecimalConversionError)?; let account = find_token_balance(burn_info.tokens, "DFI"); let address = utxo + account; @@ -124,9 +125,10 @@ pub async fn get_burned_total(ctx: &AppContext) -> Result { .await?; let burn_info = ctx.client.get_burn_info().await?; - let utxo = Decimal::from_f64(burn_info.amount).ok_or(Error::DecimalError)?; - let emission = Decimal::from_f64(burn_info.emissionburn).ok_or(Error::DecimalError)?; - let fee = Decimal::from_f64(burn_info.feeburn).ok_or(Error::DecimalError)?; + let utxo = Decimal::from_f64(burn_info.amount).ok_or(Error::DecimalConversionError)?; + let emission = + Decimal::from_f64(burn_info.emissionburn).ok_or(Error::DecimalConversionError)?; + let fee = Decimal::from_f64(burn_info.feeburn).ok_or(Error::DecimalConversionError)?; let account_balance = tokens .0 .remove("0") @@ -152,8 +154,8 @@ pub struct Emission { convert = r#"{ format!("emission") }"# )] pub fn get_emission(height: u32) -> Result { - let subsidy = - Decimal::from_u64(BLOCK_SUBSIDY.get_block_subsidy(height)).ok_or(Error::DecimalError)?; + let subsidy = Decimal::from_u64(BLOCK_SUBSIDY.get_block_subsidy(height)) + .ok_or(Error::DecimalConversionError)?; let distribution = get_block_reward_distribution(subsidy); let masternode = distribution.masternode; diff --git a/lib/ain-ocean/src/api/stats/mod.rs b/lib/ain-ocean/src/api/stats/mod.rs index efcc3ed1689..e646a22eade 100644 --- a/lib/ain-ocean/src/api/stats/mod.rs +++ b/lib/ain-ocean/src/api/stats/mod.rs @@ -125,8 +125,8 @@ async fn get_reward_distribution( .map(|b| b.height) .unwrap_or_default(); // Default to genesis block - let subsidy = - Decimal::from_u64(BLOCK_SUBSIDY.get_block_subsidy(height)).ok_or(Error::DecimalError)?; + let subsidy = Decimal::from_u64(BLOCK_SUBSIDY.get_block_subsidy(height)) + .ok_or(Error::DecimalConversionError)?; let distribution = get_block_reward_distribution(subsidy); let distribution = RewardDistributionData { @@ -161,8 +161,9 @@ async fn get_supply(Extension(ctx): Extension>) -> Result, ctx: Context) -> Result<()> { .vout_by_id .put(&(txid, vout_idx), &tx_vout)?; - total_vout_value += Decimal::from_f64(vout.value).ok_or(Error::DecimalError)?; + total_vout_value += Decimal::from_f64(vout.value).ok_or(Error::DecimalConversionError)?; vouts.push(tx_vout); } diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 320e391526f..018fc713496 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -1,6 +1,10 @@ pub mod error; mod indexer; pub mod network; + +use parking_lot::Mutex; +use petgraph::graphmap::UnGraphMap; +use serde::Serialize; use std::{path::PathBuf, sync::Arc}; pub use api::ocean_router; @@ -102,6 +106,15 @@ pub struct PriceTickerService { by_id: PriceTickerRepository, } +#[derive(Clone, Debug, Serialize, Eq, PartialEq, Hash)] +#[serde(rename_all = "camelCase")] +pub struct TokenIdentifier { + pub id: String, + pub name: String, + pub symbol: String, + pub display_symbol: String, +} + pub struct Services { pub masternode: MasternodeService, pub block: BlockService, @@ -117,6 +130,7 @@ pub struct Services { pub oracle_token_currency: OracleTokenCurrencyService, pub oracle_history: OracleHistoryService, pub price_ticker: PriceTickerService, + pub token_graph: Arc>>, } impl Services { @@ -176,6 +190,7 @@ impl Services { price_ticker: PriceTickerService { by_id: PriceTickerRepository::new(Arc::clone(&store)), }, + token_graph: Arc::new(Mutex::new(UnGraphMap::new())), } } } diff --git a/lib/ain-ocean/src/network.rs b/lib/ain-ocean/src/network.rs index 6a545f2bc4b..19d59082b16 100644 --- a/lib/ain-ocean/src/network.rs +++ b/lib/ain-ocean/src/network.rs @@ -1,5 +1,5 @@ use std::fmt; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum Network { Mainnet, Mocknet, diff --git a/lib/ain-ocean/src/repository/pool_swap.rs b/lib/ain-ocean/src/repository/pool_swap.rs index 53bfa3e432e..2a9e05a1d5f 100644 --- a/lib/ain-ocean/src/repository/pool_swap.rs +++ b/lib/ain-ocean/src/repository/pool_swap.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use ain_db::LedgerColumn; use ain_macros::Repository; -use super::RepositoryOps; +use super::{InitialKeyProvider, RepositoryOps}; use crate::{ model::{PoolSwap, PoolSwapKey}, storage::{columns, ocean_store::OceanStore}, @@ -25,3 +25,10 @@ impl PoolSwapRepository { } } } + +impl InitialKeyProvider for PoolSwapRepository { + type PartialKey = u32; + fn initial_key(pk: Self::PartialKey) -> PoolSwapKey { + (pk, u32::MAX, usize::MAX) + } +} diff --git a/src/dfi/validation.cpp b/src/dfi/validation.cpp index ebccc8835d3..bc944c9e350 100644 --- a/src/dfi/validation.cpp +++ b/src/dfi/validation.cpp @@ -3133,7 +3133,6 @@ Res ProcessDeFiEventFallible(const CBlock &block, // Ocean archive if (gArgs.GetBoolArg("-oceanarchive", DEFAULT_OCEAN_ARCHIVE_ENABLED)) { - const UniValue b = blockToJSON(block, ::ChainActive().Tip(), pindex, true, 2); CrossBoundaryResult result; ocean_index_block(result, b.write()); diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh index 811bb198854..e4d6ab0a300 100755 --- a/test/lint/lint-circular-dependencies.sh +++ b/test/lint/lint-circular-dependencies.sh @@ -82,7 +82,8 @@ EXPECTED_CIRCULAR_DEPENDENCIES=( "dfi/mn_rpc -> rpc/resultcache -> dfi/mn_rpc" "dfi/mn_rpc -> wallet/rpcwallet -> init -> ffi/ffiexports -> dfi/mn_rpc" "dfi/govvariables/attributes -> dfi/mn_rpc -> wallet/rpcwallet -> init -> miner -> dfi/govvariables/attributes" - "dfi/govvariables/attributes -> dfi/mn_rpc -> wallet/rpcwallet -> init -> rpc/blockchain -> dfi/govvariables/attributes" + # "dfi/govvariables/attributes -> dfi/mn_rpc -> wallet/rpcwallet -> init -> rpc/blockchain -> dfi/govvariables/attributes" + "dfi/govvariables/attributes -> dfi/validation -> rpc/blockchain -> dfi/govvariables/attributes" "dfi/mn_rpc -> wallet/rpcwallet -> init -> miner -> dfi/validation -> dfi/mn_rpc" "dfi/validation -> validation -> dfi/validation" "dfi/validation -> ffi/ffiexports -> dfi/validation" From 7f02b0fefe1c5228fb030f6a4ac8e8867c779cf0 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Mon, 13 May 2024 10:46:03 +0100 Subject: [PATCH 093/185] Ocean: Remove poolpair API unwraps (#2913) * Remove unwraps * Use slice --- lib/ain-ocean/src/api/pool_pair/mod.rs | 17 +++--- lib/ain-ocean/src/api/pool_pair/service.rs | 64 +++++++++++----------- 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/lib/ain-ocean/src/api/pool_pair/mod.rs b/lib/ain-ocean/src/api/pool_pair/mod.rs index 7feb81cd0bb..34ed06fc685 100644 --- a/lib/ain-ocean/src/api/pool_pair/mod.rs +++ b/lib/ain-ocean/src/api/pool_pair/mod.rs @@ -223,13 +223,14 @@ impl PoolPairResponse { a_token_name: String, b_token_name: String, total_liquidity_usd: Decimal, - ) -> Self { + ) -> Result { let parts = p.symbol.split('-').collect::>(); - let [a, b] = <[&str; 2]>::try_from(parts).expect("Invalid pool pair symbol structure"); + let [a, b] = <[&str; 2]>::try_from(parts) + .map_err(|_| format_err!("Invalid pool pair symbol structure"))?; let a_parsed = parse_dat_symbol(a); let b_parsed = parse_dat_symbol(b); - Self { + Ok(Self { id, symbol: p.symbol.clone(), display_symbol: format!("{a_parsed}-{b_parsed}"), @@ -281,7 +282,7 @@ impl PoolPairResponse { }, apr: None, // todo: await this.poolPairService.getAPR(id, info) volume: None, // todo: await this.poolPairService.getUSDVolume(id) - } + }) } } @@ -326,14 +327,14 @@ async fn list_pool_pairs( let total_liquidity_usd = get_total_liquidity_usd(&ctx, &p).await?; let _apr = get_apr(&ctx, &id, &p).await?; - - Ok::(PoolPairResponse::from_with_id( + let res = PoolPairResponse::from_with_id( id, p, a_token_name, b_token_name, total_liquidity_usd, - )) + )?; + Ok::(res) }) .collect::>(); @@ -374,7 +375,7 @@ async fn get_pool_pair( a_token_name, b_token_name, total_liquidity_usd, - ); + )?; return Ok(Response::new(Some(res))); }; diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index a8cf4d19ca4..87b7039e4ef 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -1,11 +1,11 @@ +use super::{AppContext, PoolPairAprResponse}; use anyhow::format_err; +use anyhow::Context; use defichain_rpc::{json::poolpair::PoolPairInfo, BlockchainRPC}; use rust_decimal::{prelude::FromPrimitive, Decimal}; use rust_decimal_macros::dec; use std::{str::FromStr, sync::Arc}; -use super::{AppContext, PoolPairAprResponse}; - use crate::{ api::cache::{get_gov_cached, get_pool_pair_cached, get_token_cached}, api::pool_pair::path::{get_best_path, BestSwapPathResponse}, @@ -105,7 +105,8 @@ async fn get_total_liquidity_usd_by_best_path( pub async fn get_total_liquidity_usd(ctx: &Arc, p: &PoolPairInfo) -> Result { let parts = p.symbol.split('-').collect::>(); - let [a, b] = <[&str; 2]>::try_from(parts).expect("Invalid pool pair symbol structure"); + let [a, b] = <[&str; 2]>::try_from(parts) + .map_err(|_| format_err!("Invalid pool pair symbol structure"))?; let reserve_a = Decimal::from_f64(p.reserve_a).unwrap_or_default(); let reserve_b = Decimal::from_f64(p.reserve_b).unwrap_or_default(); @@ -147,6 +148,31 @@ pub async fn get_total_liquidity_usd(ctx: &Arc, p: &PoolPairInfo) -> Ok(res) } +fn calculate_rewards(accounts: &[String], dfi_price_usdt: Decimal) -> Result { + let rewards = accounts.iter().try_fold(dec!(0), |accumulate, account| { + let parts = account.split('-').collect::>(); + let [amount, token] = parts + .as_slice() + .try_into() + .context("Invalid pool pair symbol structure")?; + + if token != "0" && token != "DFI" { + return Ok(accumulate); + } + + let yearly = Decimal::from_str(amount) + .context("convert numeric string to number")? + .checked_mul(dec!(2880)) + .and_then(|v| v.checked_mul(dec!(365))) + .and_then(|v| v.checked_mul(dfi_price_usdt)) + .context("yearly reward overflow")?; + accumulate + .checked_add(yearly) + .context("accumlate reward overflow") + })?; + Ok(rewards) +} + async fn get_yearly_custom_reward_usd(ctx: &Arc, p: &PoolPairInfo) -> Result { if p.custom_rewards.is_none() { return Ok(dec!(0)); @@ -157,35 +183,9 @@ async fn get_yearly_custom_reward_usd(ctx: &Arc, p: &PoolPairInfo) - return Ok(dfi_price_usdt); }; - let rewards = if let Some(custom_rewards) = &p.custom_rewards { - let total = custom_rewards - .iter() - .fold(dec!(0), |accumulate: Decimal, account: &String| { - let parts = account.split('-').collect::>(); - let [amount, token] = - <[&str; 2]>::try_from(parts).expect("Invalid pool pair symbol structure"); - if token != "0" && token != "DFI" { - return accumulate; - }; - - let yearly = Decimal::from_str(amount) - .expect("convert numeric string to number error") - .checked_mul(dec!(2880)) - .and_then(|v| v.checked_mul(dec!(365))) - .and_then(|v| v.checked_mul(dfi_price_usdt)) - .expect("yearly reward overflow err"); - - accumulate - .checked_add(yearly) - .expect("accumlate reward overflow err") - }); - - total - } else { - dec!(0) - }; - - Ok(rewards) + p.custom_rewards.as_ref().map_or(Ok(dec!(0)), |rewards| { + calculate_rewards(rewards, dfi_price_usdt) + }) } async fn get_daily_dfi_reward(ctx: &Arc) -> Result { From fed50afa1106e1b2c5cd4c5d68eef42c068be727 Mon Sep 17 00:00:00 2001 From: jouzo Date: Tue, 14 May 2024 09:47:05 +0100 Subject: [PATCH 094/185] Restore GetByteArray() --- src/dfi/mn_checks.cpp | 2 +- src/test/xvm_tests.cpp | 2 +- src/uint256.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dfi/mn_checks.cpp b/src/dfi/mn_checks.cpp index 2a7645ca432..4be0377caae 100644 --- a/src/dfi/mn_checks.cpp +++ b/src/dfi/mn_checks.cpp @@ -1160,7 +1160,7 @@ Res CPoolSwap::ExecuteSwap(CCustomCSView &view, CrossBoundaryResult ffiResult; ocean_try_set_tx_result(ffiResult, static_cast(txType), - txHash.GetByteArray(), + txHash.GetByteArrayBE(), static_cast(reinterpret_cast(&finalSwapAmount))); } diff --git a/src/test/xvm_tests.cpp b/src/test/xvm_tests.cpp index d687660a013..8307f7ccda9 100644 --- a/src/test/xvm_tests.cpp +++ b/src/test/xvm_tests.cpp @@ -12,7 +12,7 @@ BOOST_AUTO_TEST_CASE(xvm_test_case_1) { auto zero = uint256S("0x0"); auto one = uint256S("0x1"); - auto oneArr = uint256S("0x1").GetByteArrayRev(); + auto oneArr = uint256S("0x1").GetByteArray(); auto oneVec = std::vector(oneArr.begin(), oneArr.end()); auto oneVecReversed = std::vector(oneArr.begin(), oneArr.end()); std::reverse(oneVecReversed.begin(), oneVecReversed.end()); diff --git a/src/uint256.h b/src/uint256.h index dfef91f8de4..f3676a75101 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -66,7 +66,7 @@ class base_blob ((uint64_t)ptr[7]) << 56; } - [[nodiscard]] std::array GetByteArrayRev() const + [[nodiscard]] std::array GetByteArray() const { // We store bytes in little endian. So any expectations of // an array of bytes should be in same order as the hex string. @@ -76,7 +76,7 @@ class base_blob return reversedArray; } - [[nodiscard]] std::array GetByteArray() const + [[nodiscard]] std::array GetByteArrayBE() const { std::array byteArray; std::copy(data, data + WIDTH, byteArray.begin()); From 53251000fdd38e22da3fc08a2d27459de1117d5b Mon Sep 17 00:00:00 2001 From: canonbrother Date: Tue, 28 May 2024 04:21:29 +0800 Subject: [PATCH 095/185] Ocean: list pool swap aggregates (#2918) * wip * fmt * rm log * cleanup * [index_block_start] sort pool creation_height desc * faster get_pool_pair * paginate * enable pool swap indexer * default 0 if empty accounts * [index_block_start] wrap oneday interval * missing store onehour aggregate * fix wrong amount token id * [fix] DeserializeAnyNotSupported decimal, change aggregate token amount type from decimal to string * fmt * index_block_start poolswap grab the latest only * decimal places 8 + convert base unit to logical unit * fix interval hour * fmt_rs * cleanup * async function is not directly supported yet * fmt * impl correct index approach * cleanup * missing PoolSwapAggregated and PoolSwapAggregatedKey columns * fix getting splited arr wrong index * rm oneday and onehour columns * rm PoolSwapAggregatedInterval from * add bucket into key * refine * stuck * Impl Column trait * revert hiding code * rm pool_test.rs * fmt_rs * clear debug log * add invalidate poolswapagg --------- Co-authored-by: jouzo --- lib/ain-ocean/src/api/pool_pair/mod.rs | 113 +++++++++++--- lib/ain-ocean/src/api/pool_pair/path.rs | 4 +- lib/ain-ocean/src/api/pool_pair/service.rs | 84 +++++++++- lib/ain-ocean/src/bin/cli.rs | 26 +++- lib/ain-ocean/src/error.rs | 4 + lib/ain-ocean/src/indexer/masternode.rs | 2 +- lib/ain-ocean/src/indexer/mod.rs | 91 ++++++++++- lib/ain-ocean/src/indexer/pool.rs | 147 +++++++++++++++++- lib/ain-ocean/src/lib.rs | 18 ++- lib/ain-ocean/src/model/mod.rs | 2 +- .../src/model/poolswap_aggregated.rs | 9 +- lib/ain-ocean/src/repository/mod.rs | 2 +- .../src/repository/pool_swap_aggregated.rs | 57 +++++++ lib/ain-ocean/src/storage/columns/mod.rs | 3 +- .../storage/columns/pool_swap_aggregated.rs | 90 ++++++++++- lib/ain-rs-exports/src/lib.rs | 11 +- lib/ain-rs-exports/src/ocean.rs | 13 +- src/dfi/validation.cpp | 13 +- src/init.cpp | 12 +- 19 files changed, 641 insertions(+), 60 deletions(-) diff --git a/lib/ain-ocean/src/api/pool_pair/mod.rs b/lib/ain-ocean/src/api/pool_pair/mod.rs index 34ed06fc685..e9a16a8b4c8 100644 --- a/lib/ain-ocean/src/api/pool_pair/mod.rs +++ b/lib/ain-ocean/src/api/pool_pair/mod.rs @@ -1,5 +1,8 @@ use petgraph::graphmap::UnGraphMap; -use std::{collections::HashSet, sync::Arc}; +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, +}; use ain_macros::ocean_endpoint; use anyhow::format_err; @@ -28,8 +31,8 @@ use super::{ use crate::{ error::{ApiError, Error}, - model::{BlockContext, PoolSwap}, - repository::{InitialKeyProvider, PoolSwapRepository, RepositoryOps}, + model::{BlockContext, PoolSwap, PoolSwapAggregated}, + repository::{InitialKeyProvider, PoolSwapRepository, RepositoryOps, SecondaryIndex}, storage::SortOrder, Result, TokenIdentifier, }; @@ -40,7 +43,7 @@ use path::{ SwapPathsResponse, }; -use service::{get_apr, get_total_liquidity_usd}; +use service::{get_aggregated_in_usd, get_apr, get_total_liquidity_usd}; pub mod path; pub mod service; @@ -50,11 +53,11 @@ pub mod service; // id: String, // } -// #[derive(Deserialize)] -// struct SwapAggregate { -// id: String, -// interval: i64, -// } +#[derive(Deserialize)] +struct SwapAggregate { + id: String, + interval: u32, +} // #[derive(Debug, Deserialize)] // struct DexPrices { @@ -474,15 +477,81 @@ async fn list_pool_swaps_verbose( })) } -// #[ocean_endpoint] -// async fn list_pool_swap_aggregates( -// Path(SwapAggregate { id, interval }): Path, -// ) -> String { -// format!( -// "Aggregate swaps for poolpair {} over interval {}", -// id, interval -// ) -// } +#[derive(Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +struct PoolSwapAggregatedAggregatedResponse { + amounts: HashMap, + usd: Decimal, +} + +#[derive(Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +struct PoolSwapAggregatedResponse { + id: String, + key: String, + bucket: i64, + aggregated: PoolSwapAggregatedAggregatedResponse, + block: BlockContext, +} + +impl PoolSwapAggregatedResponse { + fn with_usd(p: PoolSwapAggregated, usd: Decimal) -> Self { + Self { + id: p.id, + key: p.key, + bucket: p.bucket, + aggregated: PoolSwapAggregatedAggregatedResponse { + amounts: p.aggregated.amounts, + usd, + }, + block: p.block, + } + } +} + +#[ocean_endpoint] +async fn list_pool_swap_aggregates( + Path(SwapAggregate { id, interval }): Path, + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let pool_id = id.parse::()?; + + // bucket + let next = query + .next + .map(|bucket| { + let bucket = bucket.parse::()?; + Ok::(bucket) + }) + .transpose()? + .unwrap_or(i64::MAX); + + let repository = &ctx.services.pool_swap_aggregated; + let aggregates = repository + .by_key + .list(Some((pool_id, interval, next)), SortOrder::Descending)? + .take(query.size) + .take_while(|item| match item { + Ok((k, _)) => k.0 == pool_id && k.1 == interval, + _ => true, + }) + .map(|e| repository.by_key.retrieve_primary_value(e)) + .collect::>>()?; + + let mut aggregated_usd = Vec::::new(); + for aggregated in aggregates { + let usd = get_aggregated_in_usd(&ctx, &aggregated.aggregated).await?; + let aggregate_with_usd = PoolSwapAggregatedResponse::with_usd(aggregated, usd); + aggregated_usd.push(aggregate_with_usd) + } + + Ok(ApiPagedResponse::of( + aggregated_usd, + query.size, + |aggregated| aggregated.bucket, + )) +} #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] @@ -608,10 +677,10 @@ pub fn router(ctx: Arc) -> Router { "/paths/best/from/:fromTokenId/to/:toTokenId", get(get_best_path), ) - // .route( - // "/:id/swaps/aggregate/:interval", - // get(list_pool_swap_aggregates), - // ) + .route( + "/:id/swaps/aggregate/:interval", + get(list_pool_swap_aggregates), + ) .route("/paths/swappable/:tokenId", get(get_swappable_tokens)) // .route("/dexprices", get(list_dex_prices)) .layer(Extension(ctx)) diff --git a/lib/ain-ocean/src/api/pool_pair/path.rs b/lib/ain-ocean/src/api/pool_pair/path.rs index f31a09d4c52..e481300c619 100644 --- a/lib/ain-ocean/src/api/pool_pair/path.rs +++ b/lib/ain-ocean/src/api/pool_pair/path.rs @@ -405,7 +405,7 @@ pub async fn compute_return_less_dex_fees_in_destination_token( for pool in path { if from_token_id == pool.token_a.id { - from_token_id = pool.token_b.id.to_owned(); + pool.token_b.id.clone_into(&mut from_token_id); price_ratio = Decimal::from_str(pool.price_ratio.ba.as_str())?; (from_token_fee_pct, to_token_fee_pct) = if let Some(estimated_dex_fees_in_pct) = &pool.estimated_dex_fees_in_pct { @@ -416,7 +416,7 @@ pub async fn compute_return_less_dex_fees_in_destination_token( (None, None) }; } else { - from_token_id = pool.token_a.id.to_owned(); + pool.token_a.id.clone_into(&mut from_token_id); price_ratio = Decimal::from_str(pool.price_ratio.ab.as_str()).map_err(|e| format_err!(e))?; (from_token_fee_pct, to_token_fee_pct) = diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index 87b7039e4ef..3083fa9660d 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -9,7 +9,8 @@ use std::{str::FromStr, sync::Arc}; use crate::{ api::cache::{get_gov_cached, get_pool_pair_cached, get_token_cached}, api::pool_pair::path::{get_best_path, BestSwapPathResponse}, - error::Error, + error::{Error, NotFoundKind}, + model::PoolSwapAggregatedAggregated, Result, }; @@ -359,3 +360,84 @@ pub async fn get_apr( total, })) } + +async fn get_pool_pair(ctx: &Arc, a: &str, b: &str) -> Result> { + let ab = get_pool_pair_cached(ctx, format!("{a}-{b}")).await?; + if let Some((_, info)) = ab { + Ok(Some(info)) + } else { + let ba = get_pool_pair_cached(ctx, format!("{b}-{a}")).await?; + if let Some((_, info)) = ba { + Ok(Some(info)) + } else { + Ok(None) + } + } +} + +async fn get_token_usd_value(ctx: &Arc, token_id: &str) -> Result { + let (_, info) = get_token_cached(ctx, token_id) + .await? + .ok_or(Error::NotFound(NotFoundKind::Token))?; + + if ["DUSD", "USDT", "USDC"].contains(&info.symbol.as_str()) { + return Ok(dec!(1)); + }; + + let dusd_pool = get_pool_pair(ctx, &info.symbol, "DUSD").await?; + if let Some(p) = dusd_pool { + let parts = p.symbol.split('-').collect::>(); + let [a, _] = <[&str; 2]>::try_from(parts) + .map_err(|_| format_err!("Invalid pool pair symbol structure"))?; + let reserve_a = Decimal::from_f64(p.reserve_a).ok_or(Error::DecimalConversionError)?; + let reserve_b = Decimal::from_f64(p.reserve_b).ok_or(Error::DecimalConversionError)?; + if a == "DUSD" { + return reserve_a + .checked_div(reserve_b) + .ok_or(Error::UnderflowError); + }; + return reserve_b + .checked_div(reserve_a) + .ok_or(Error::UnderflowError); + } + + let dfi_pool = get_pool_pair(ctx, &info.symbol, "DFI").await?; + if let Some(p) = dfi_pool { + let usd_per_dfi = get_usd_per_dfi(ctx).await?; + let reserve_a = Decimal::from_f64(p.reserve_a).ok_or(Error::DecimalConversionError)?; + let reserve_b = Decimal::from_f64(p.reserve_b).ok_or(Error::DecimalConversionError)?; + if p.id_token_a == *"0" { + return reserve_a + .checked_div(reserve_b) + .ok_or(Error::UnderflowError)? + .checked_mul(usd_per_dfi) + .ok_or(Error::OverflowError); + } + return reserve_b + .checked_div(reserve_a) + .ok_or(Error::UnderflowError)? + .checked_mul(usd_per_dfi) + .ok_or(Error::OverflowError); + } + + Ok(dec!(0)) +} + +pub async fn get_aggregated_in_usd( + ctx: &Arc, + aggregated: &PoolSwapAggregatedAggregated, +) -> Result { + let mut value = dec!(0); + + for (token_id, amount) in &aggregated.amounts { + let token_price = get_token_usd_value(ctx, token_id).await?; + let amount = Decimal::from_str(amount)?; + value = value + .checked_add(token_price) + .ok_or(Error::OverflowError)? + .checked_mul(amount) + .ok_or(Error::OverflowError)? + } + + Ok(value) +} diff --git a/lib/ain-ocean/src/bin/cli.rs b/lib/ain-ocean/src/bin/cli.rs index 1fe109a90b1..0fbc9136ebe 100644 --- a/lib/ain-ocean/src/bin/cli.rs +++ b/lib/ain-ocean/src/bin/cli.rs @@ -1,10 +1,11 @@ use std::{net::SocketAddr, path::PathBuf, sync::Arc, time::Instant}; use ain_ocean::{ - index_block, network::Network, storage::ocean_store::OceanStore, Result, Services, + index_block, network::Network, storage::ocean_store::OceanStore, PoolCreationHeight, Result, + Services, }; use clap::Parser; -use defichain_rpc::{json::blockchain::*, Auth, BlockchainRPC, Client}; +use defichain_rpc::{json::blockchain::*, Auth, BlockchainRPC, Client, PoolPairRPC}; #[derive(Parser, Debug)] #[command( @@ -47,7 +48,13 @@ async fn main() -> Result<()> { let store = Arc::new(OceanStore::new(&cli.datadir)?); - let client = Arc::new(Client::new(&cli.rpcaddress, Auth::UserPass(cli.user, cli.pass)).await?); + let client = Arc::new( + Client::new( + &cli.rpcaddress, + Auth::UserPass(cli.user.clone(), cli.pass.clone()), + ) + .await?, + ); let services = Arc::new(Services::new(store)); @@ -91,8 +98,19 @@ async fn main() -> Result<()> { Ok(_) => return Err("Error deserializing block".into()), }; + let pools = client + .list_pool_pairs(None, Some(true)) + .await? + .0 + .into_iter() + .map(|(id, info)| PoolCreationHeight { + id: id.parse::().unwrap(), + creation_height: info.creation_height as u32, + }) + .collect::>(); + next_block_hash = block.nextblockhash; - match index_block(&services, block) { + match index_block(&services, block, pools) { Ok(_) => (), Err(e) => { return Err(e); diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 9157d2f75f3..1f8d2efb6c6 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -21,10 +21,14 @@ pub enum NotFoundKind { Scheme, #[error("oracle")] Oracle, + #[error("token")] + Token, } #[derive(Error, Debug)] pub enum Error { + #[error("Ocean: Bincode error: {0:?}")] + BincodeError(#[from] bincode::Error), #[error("Ocean: HexToArrayError error: {0:?}")] HexToArrayError(#[from] HexToArrayError), #[error("Ocean: ParseIntError error: {0:?}")] diff --git a/lib/ain-ocean/src/indexer/masternode.rs b/lib/ain-ocean/src/indexer/masternode.rs index f5eee963f72..eadaae81f80 100644 --- a/lib/ain-ocean/src/indexer/masternode.rs +++ b/lib/ain-ocean/src/indexer/masternode.rs @@ -117,7 +117,7 @@ impl Index for UpdateMasternode { match update.r#type { 0x1 => { if let Some(ref addresses) = ctx.tx.vout[1].script_pub_key.addresses { - mn.owner_address = addresses[0].clone() + mn.owner_address.clone_from(&addresses[0]) } } 0x2 => { diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 9cafbcee392..004fe427d66 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -12,19 +12,30 @@ use ain_dftx::{deserialize, DfTx, Stack}; use defichain_rpc::json::blockchain::{Block, Transaction}; use log::debug; +pub use pool::AGGREGATED_INTERVALS; + use crate::{ index_transaction, - model::{Block as BlockMapper, BlockContext}, - repository::RepositoryOps, + model::{Block as BlockMapper, BlockContext, PoolSwapAggregated, PoolSwapAggregatedAggregated}, + repository::{RepositoryOps, SecondaryIndex}, + storage::SortOrder, Result, Services, }; pub(crate) trait Index { fn index(self, services: &Arc, ctx: &Context) -> Result<()>; + // TODO: allow dead_code at the moment + #[allow(dead_code)] fn invalidate(&self, services: &Arc, ctx: &Context) -> Result<()>; } +#[derive(Debug, Clone)] +pub struct PoolCreationHeight { + pub id: u32, + pub creation_height: u32, +} + #[derive(Debug)] pub struct Context { block: BlockContext, @@ -37,7 +48,77 @@ fn log_elapsed(previous: Instant, msg: &str) { debug!("{} in {} ms", msg, now.duration_since(previous).as_millis()); } -pub fn index_block(services: &Arc, block: Block) -> Result<()> { +fn get_bucket(block: &Block, interval: i64) -> i64 { + block.mediantime - (block.mediantime % interval) +} + +fn index_block_start( + services: &Arc, + block: &Block, + pool_pairs: Vec, +) -> Result<()> { + let mut pool_pairs = pool_pairs; + pool_pairs.sort_by(|a, b| b.creation_height.cmp(&a.creation_height)); + + for interval in AGGREGATED_INTERVALS { + for pool_pair in &pool_pairs { + let repository = &services.pool_swap_aggregated; + + let prevs = repository + .by_key + .list( + Some((pool_pair.id, interval, i64::MAX)), + SortOrder::Descending, + )? + .take(1) + .take_while(|item| match item { + Ok((k, _)) => k.0 == pool_pair.id && k.1 == interval, + _ => true, + }) + .map(|e| repository.by_key.retrieve_primary_value(e)) + .collect::>>()?; + + let bucket = get_bucket(block, interval as i64); + + if prevs.len() == 1 && prevs[0].bucket >= bucket { + break; + } + + let aggregated = PoolSwapAggregated { + id: format!("{}-{}-{}", pool_pair.id, interval, block.hash), + key: format!("{}-{}", pool_pair.id, interval), + bucket, + aggregated: PoolSwapAggregatedAggregated { + amounts: Default::default(), + }, + block: BlockContext { + hash: block.hash, + height: block.height, + time: block.time, + median_time: block.mediantime, + }, + }; + + let pool_swap_aggregated_key = (pool_pair.id, interval, bucket); + let pool_swap_aggregated_id = (pool_pair.id, interval, block.hash); + + repository + .by_key + .put(&pool_swap_aggregated_key, &pool_swap_aggregated_id)?; + repository + .by_id + .put(&pool_swap_aggregated_id, &aggregated)?; + } + } + + Ok(()) +} + +pub fn index_block( + services: &Arc, + block: Block, + pools: Vec, +) -> Result<()> { debug!("[index_block] Indexing block..."); let start = Instant::now(); @@ -50,6 +131,8 @@ pub fn index_block(services: &Arc, block: Block) -> Resul median_time: block.mediantime, }; + index_block_start(services, &block, pools)?; + for (tx_idx, tx) in block.tx.into_iter().enumerate() { let start = Instant::now(); let ctx = Context { @@ -82,7 +165,7 @@ pub fn index_block(services: &Arc, block: Block) -> Resul DfTx::RemoveOracle(data) => data.index(services, &ctx)?, DfTx::UpdateOracle(data) => data.index(services, &ctx)?, DfTx::SetOracleData(data) => data.index(services, &ctx)?, - // DfTx::PoolSwap(data) => data.index(services, &ctx)?, + DfTx::PoolSwap(data) => data.index(services, &ctx)?, // DfTx::CompositeSwap(data) => data.index(services, &ctx)?, // DfTx::PlaceAuctionBid(data) => data.index(services, &ctx)?, _ => (), diff --git a/lib/ain-ocean/src/indexer/pool.rs b/lib/ain-ocean/src/indexer/pool.rs index b12a9dd24bf..349bc9859c5 100644 --- a/lib/ain-ocean/src/indexer/pool.rs +++ b/lib/ain-ocean/src/indexer/pool.rs @@ -1,18 +1,33 @@ -use std::sync::Arc; +use std::{ops::Div, str::FromStr, sync::Arc}; use ain_dftx::pool::*; -// use anyhow::format_err; +use anyhow::format_err; +use bitcoin::BlockHash; // use bitcoin::Address; use log::debug; +use rust_decimal::Decimal; +use rust_decimal_macros::dec; use super::Context; use crate::{ indexer::{tx_result, Index, Result}, model::{self, PoolSwapResult, TxResult}, - repository::RepositoryOps, - Services, + repository::{RepositoryOps, SecondaryIndex}, + storage::SortOrder, + Error, Services, }; +pub const AGGREGATED_INTERVALS: [u32; 2] = [ + PoolSwapAggregatedInterval::OneDay as u32, + PoolSwapAggregatedInterval::OneHour as u32, +]; + +#[derive(Debug, Clone, Copy)] +pub enum PoolSwapAggregatedInterval { + OneDay = 60 * 60 * 24, + OneHour = 60 * 60, +} + impl Index for PoolSwap { fn index(self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[Poolswap] Indexing..."); @@ -30,14 +45,17 @@ impl Index for PoolSwap { let from = self.from_script; let to = self.to_script; + let from_token_id = self.from_token_id.0; + let from_amount = self.from_amount; let swap = model::PoolSwap { id: format!("{}-{}", pool_id, txid), + // TODO: use hex::encode eg: sort: hex::encode(ctx.block.height + idx) sort: format!("{}-{}", ctx.block.height, idx), txid, txno: idx, - from_amount: self.from_amount, - from_token_id: self.from_token_id.0, + from_amount, + from_token_id, to_token_id: self.to_token_id.0, to_amount, pool_id, @@ -50,7 +68,62 @@ impl Index for PoolSwap { services .pool .by_id - .put(&(pool_id, ctx.block.height, idx), &swap) + .put(&(pool_id, ctx.block.height, idx), &swap)?; + + for interval in AGGREGATED_INTERVALS { + let repository = &services.pool_swap_aggregated; + let mut prevs = repository + .by_key + .list(Some((pool_id, interval, i64::MAX)), SortOrder::Descending)? + .take(1) + .take_while(|item| match item { + Ok((k, _)) => k.0 == pool_id && k.1 == interval, + _ => true, + }) + .map(|e| repository.by_key.retrieve_primary_value(e)) + .collect::>>()?; + + if prevs.is_empty() { + log::error!( + "index swap {txid}: Unable to find {pool_id}-{interval} for Aggregate Indexing" + ); + continue; + } + + let aggregated = prevs.first_mut(); + if let Some(aggregated) = aggregated { + let amount = aggregated + .aggregated + .amounts + .get(&from_token_id.to_string()) + .map(|amt| Decimal::from_str(amt)) + .transpose()? + .unwrap_or(dec!(0)); + + let aggregated_amount = amount + .checked_add(Decimal::from(from_amount).div(dec!(100_000_000))) + .ok_or(Error::OverflowError)?; + + aggregated.aggregated.amounts.insert( + from_token_id.to_string(), + format!("{:.8}", aggregated_amount), + ); + + let parts = aggregated.id.split('-').collect::>(); + if parts.len() != 3 { + return Err(format_err!("Invalid poolswap aggregated id format").into()); + }; + let pool_id = parts[0].parse::()?; + let interval = parts[1].parse::()?; + let hash = parts[2].parse::()?; + + repository + .by_id + .put(&(pool_id, interval, hash), aggregated)?; + } + } + + Ok(()) } fn invalidate(&self, services: &Arc, ctx: &Context) -> Result<()> { @@ -65,7 +138,65 @@ impl Index for PoolSwap { .pool .by_id .delete(&(pool_id, ctx.block.height, ctx.tx_idx))?; - tx_result::invalidate(services, &txid) + tx_result::invalidate(services, &txid)?; + + for interval in AGGREGATED_INTERVALS { + let repository = &services.pool_swap_aggregated; + let mut prevs = repository + .by_key + .list(Some((pool_id, interval, i64::MAX)), SortOrder::Descending)? + .take(1) + .take_while(|item| match item { + Ok((k, _)) => k.0 == pool_id && k.1 == interval, + _ => true, + }) + .map(|e| repository.by_key.retrieve_primary_value(e)) + .collect::>>()?; + + if prevs.is_empty() { + log::error!( + "invalidate swap {txid}: Unable to find {pool_id}-{interval} for Aggregate Indexing" + ); + continue; + } + + let from_token_id = self.from_token_id.0; + let from_amount = self.from_amount; + + let aggregated = prevs.first_mut(); + if let Some(aggregated) = aggregated { + let amount = aggregated + .aggregated + .amounts + .get(&from_token_id.to_string()) + .map(|amt| Decimal::from_str(amt)) + .transpose()? + .unwrap_or(dec!(0)); + + let aggregated_amount = amount + .checked_sub(Decimal::from(from_amount).div(dec!(100_000_000))) + .ok_or(Error::UnderflowError)?; + + aggregated.aggregated.amounts.insert( + from_token_id.to_string(), + format!("{:.8}", aggregated_amount), + ); + + let parts = aggregated.id.split('-').collect::>(); + if parts.len() != 3 { + return Err(format_err!("Invalid poolswap aggregated id format").into()); + }; + let pool_id = parts[0].parse::()?; + let interval = parts[1].parse::()?; + let hash = parts[2].parse::()?; + + repository + .by_id + .put(&(pool_id, interval, hash), aggregated)?; + } + } + + Ok(()) } } diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 018fc713496..d418c1a00ae 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -11,7 +11,7 @@ pub use api::ocean_router; use error::Error; pub use indexer::{ index_block, invalidate_block, oracle::invalidate_oracle_interval, - transaction::index_transaction, tx_result, + transaction::index_transaction, tx_result, PoolCreationHeight, }; use repository::{ AuctionHistoryByHeightRepository, AuctionHistoryRepository, BlockByHeightRepository, @@ -21,9 +21,9 @@ use repository::{ OraclePriceAggregatedIntervalRepository, OraclePriceAggregatedRepository, OraclePriceAggregatedRepositorykey, OraclePriceFeedKeyRepository, OraclePriceFeedRepository, OracleRepository, OracleTokenCurrencyKeyRepository, OracleTokenCurrencyRepository, - PoolSwapRepository, PriceTickerRepository, RawBlockRepository, - TransactionByBlockHashRepository, TransactionRepository, TransactionVinRepository, - TransactionVoutRepository, TxResultRepository, + PoolSwapAggregatedKeyRepository, PoolSwapAggregatedRepository, PoolSwapRepository, + PriceTickerRepository, RawBlockRepository, TransactionByBlockHashRepository, + TransactionRepository, TransactionVinRepository, TransactionVoutRepository, TxResultRepository, }; pub mod api; mod model; @@ -65,6 +65,11 @@ pub struct PoolService { by_id: PoolSwapRepository, } +pub struct PoolSwapAggregatedService { + by_id: PoolSwapAggregatedRepository, + by_key: PoolSwapAggregatedKeyRepository, +} + pub struct TransactionService { by_id: TransactionRepository, by_block_hash: TransactionByBlockHashRepository, @@ -121,6 +126,7 @@ pub struct Services { pub auction: AuctionService, pub result: TxResultRepository, pub pool: PoolService, + pub pool_swap_aggregated: PoolSwapAggregatedService, pub transaction: TransactionService, pub oracle: OracleService, pub oracle_price_feed: OraclePriceFeedService, @@ -154,6 +160,10 @@ impl Services { pool: PoolService { by_id: PoolSwapRepository::new(Arc::clone(&store)), }, + pool_swap_aggregated: PoolSwapAggregatedService { + by_id: PoolSwapAggregatedRepository::new(Arc::clone(&store)), + by_key: PoolSwapAggregatedKeyRepository::new(Arc::clone(&store)), + }, transaction: TransactionService { by_id: TransactionRepository::new(Arc::clone(&store)), by_block_hash: TransactionByBlockHashRepository::new(Arc::clone(&store)), diff --git a/lib/ain-ocean/src/model/mod.rs b/lib/ain-ocean/src/model/mod.rs index 4aaf0139e69..4ff98fec0d1 100644 --- a/lib/ain-ocean/src/model/mod.rs +++ b/lib/ain-ocean/src/model/mod.rs @@ -32,7 +32,7 @@ pub use oracle_price_aggregated_interval::*; pub use oracle_price_feed::*; pub use oracle_token_currency::*; pub use poolswap::*; -// pub use poolswap_aggregated::*; +pub use poolswap_aggregated::*; pub use price_ticker::*; // pub use prices::*; // pub use raw_block::*; diff --git a/lib/ain-ocean/src/model/poolswap_aggregated.rs b/lib/ain-ocean/src/model/poolswap_aggregated.rs index 7b5453b9eb7..2823cf15332 100644 --- a/lib/ain-ocean/src/model/poolswap_aggregated.rs +++ b/lib/ain-ocean/src/model/poolswap_aggregated.rs @@ -1,13 +1,18 @@ use serde::{Deserialize, Serialize}; +use std::collections::HashMap; use super::BlockContext; +use bitcoin::BlockHash; + +pub type PoolSwapAggregatedId = (u32, u32, BlockHash); // (pool_id, interval, block_hash) +pub type PoolSwapAggregatedKey = (u32, u32, i64); // (pool_id, interval, bucket) #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct PoolSwapAggregated { pub id: String, pub key: String, - pub bucket: i32, + pub bucket: i64, pub aggregated: PoolSwapAggregatedAggregated, pub block: BlockContext, } @@ -15,5 +20,5 @@ pub struct PoolSwapAggregated { #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct PoolSwapAggregatedAggregated { - pub amounts: Vec, + pub amounts: HashMap, // amounts[tokenId] = BigNumber(volume) } diff --git a/lib/ain-ocean/src/repository/mod.rs b/lib/ain-ocean/src/repository/mod.rs index 26401c21b9b..8a71164bb49 100644 --- a/lib/ain-ocean/src/repository/mod.rs +++ b/lib/ain-ocean/src/repository/mod.rs @@ -34,7 +34,7 @@ pub use oracle_price_aggregated_interval::*; pub use oracle_price_feed::*; pub use oracle_token_currency::*; pub use pool_swap::*; -// pub use pool_swap_aggregated::*; +pub use pool_swap_aggregated::*; pub use price_ticker::*; pub use raw_block::*; // pub use script_activity::*; diff --git a/lib/ain-ocean/src/repository/pool_swap_aggregated.rs b/lib/ain-ocean/src/repository/pool_swap_aggregated.rs index 8b137891791..991b8053485 100644 --- a/lib/ain-ocean/src/repository/pool_swap_aggregated.rs +++ b/lib/ain-ocean/src/repository/pool_swap_aggregated.rs @@ -1 +1,58 @@ +use std::sync::Arc; +use ain_db::LedgerColumn; +use ain_macros::Repository; + +use super::{RepositoryOps, SecondaryIndex}; +use crate::{ + model::{PoolSwapAggregated, PoolSwapAggregatedId, PoolSwapAggregatedKey}, + storage::{columns, ocean_store::OceanStore}, + Error, Result, +}; + +#[derive(Repository)] +#[repository(K = "PoolSwapAggregatedId", V = "PoolSwapAggregated")] +pub struct PoolSwapAggregatedRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl PoolSwapAggregatedRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} + +#[derive(Repository)] +#[repository(K = "PoolSwapAggregatedKey", V = "PoolSwapAggregatedId")] +pub struct PoolSwapAggregatedKeyRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl PoolSwapAggregatedKeyRepository { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} + +impl SecondaryIndex + for PoolSwapAggregatedKeyRepository +{ + type Value = PoolSwapAggregated; + + fn retrieve_primary_value(&self, el: Self::ListItem) -> Result { + let (_, id) = el?; + + let col = self.store.column::(); + let res = col.get(&id)?.ok_or(Error::SecondaryIndex)?; + + Ok(res) + } +} diff --git a/lib/ain-ocean/src/storage/columns/mod.rs b/lib/ain-ocean/src/storage/columns/mod.rs index 615205ce4bb..f4144451467 100644 --- a/lib/ain-ocean/src/storage/columns/mod.rs +++ b/lib/ain-ocean/src/storage/columns/mod.rs @@ -45,7 +45,7 @@ pub use transaction_vout::*; pub use tx_result::*; pub use vault_auction_history::*; -pub const COLUMN_NAMES: [&str; 32] = [ +pub const COLUMN_NAMES: [&str; 33] = [ block::Block::NAME, block::BlockByHeight::NAME, masternode_stats::MasternodeStats::NAME, @@ -65,6 +65,7 @@ pub const COLUMN_NAMES: [&str; 32] = [ oracle_token_currency::OracleTokenCurrency::NAME, oracle_token_currency::OracleTokenCurrencyKey::NAME, pool_swap_aggregated::PoolSwapAggregated::NAME, + pool_swap_aggregated::PoolSwapAggregatedKey::NAME, pool_swap::PoolSwap::NAME, price_ticker::PriceTicker::NAME, raw_block::RawBlock::NAME, diff --git a/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs b/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs index 090fcec8277..f3cb8826b87 100644 --- a/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs +++ b/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs @@ -1,4 +1,7 @@ -use ain_db::{Column, ColumnName, TypedColumn}; +use crate::model; +use ain_db::{Column, ColumnName, DBError, TypedColumn}; +use anyhow::format_err; +use bitcoin::{hashes::Hash, BlockHash}; #[derive(Debug)] pub struct PoolSwapAggregated; @@ -8,9 +11,90 @@ impl ColumnName for PoolSwapAggregated { } impl Column for PoolSwapAggregated { - type Index = String; + type Index = model::PoolSwapAggregatedId; + + fn key(index: &Self::Index) -> Result, DBError> { + let (pool_id, interval, block_hash) = index; + let mut vec = Vec::with_capacity(40); + + vec.extend_from_slice(&pool_id.to_be_bytes()); + vec.extend_from_slice(&interval.to_be_bytes()); + vec.extend_from_slice(block_hash.as_byte_array()); + + Ok(vec) + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + if raw_key.len() != 40 { + return Err(format_err!("Length of the slice is not 40").into()); + } + + let pool_id = u32::from_be_bytes( + raw_key[0..4] + .try_into() + .map_err(|_| DBError::WrongKeyLength)?, + ); + let interval = u32::from_be_bytes( + raw_key[4..8] + .try_into() + .map_err(|_| DBError::WrongKeyLength)?, + ); + let block_hash = BlockHash::from_byte_array( + raw_key[8..40] + .try_into() + .map_err(|_| DBError::WrongKeyLength)?, + ); + Ok((pool_id, interval, block_hash)) + } } impl TypedColumn for PoolSwapAggregated { - type Type = String; + type Type = model::PoolSwapAggregated; +} + +#[derive(Debug)] +pub struct PoolSwapAggregatedKey; + +impl ColumnName for PoolSwapAggregatedKey { + const NAME: &'static str = "pool_swap_aggregated_key"; +} + +impl Column for PoolSwapAggregatedKey { + type Index = model::PoolSwapAggregatedKey; + + fn key(index: &Self::Index) -> Result, DBError> { + let (pool_id, interval, bucket) = index; + let mut vec = Vec::with_capacity(16); + vec.extend_from_slice(&pool_id.to_be_bytes()); + vec.extend_from_slice(&interval.to_be_bytes()); + vec.extend_from_slice(&bucket.to_be_bytes()); + Ok(vec) + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + if raw_key.len() != 16 { + return Err(format_err!("length of the slice is not 40").into()); + } + let pool_id = u32::from_be_bytes( + raw_key[0..4] + .try_into() + .map_err(|_| DBError::WrongKeyLength)?, + ); + let interval = u32::from_be_bytes( + raw_key[4..8] + .try_into() + .map_err(|_| DBError::WrongKeyLength)?, + ); + let bucket = i64::from_be_bytes( + raw_key[8..16] + .try_into() + .map_err(|_| DBError::WrongKeyLength)?, + ); + + Ok((pool_id, interval, bucket)) + } +} + +impl TypedColumn for PoolSwapAggregatedKey { + type Type = model::PoolSwapAggregatedId; } diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index abbcde05ad8..bcb622f6209 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -167,6 +167,11 @@ pub mod ffi { pub tx_hash: [u8; 32], } + pub struct PoolCreationHeight { + pub id: u32, + pub creation_height: u32, + } + extern "Rust" { type BlockTemplateWrapper; // In-fallible functions @@ -346,7 +351,11 @@ pub mod ffi { fn evm_try_flush_db(result: &mut CrossBoundaryResult); - fn ocean_index_block(result: &mut CrossBoundaryResult, block_str: String); + fn ocean_index_block( + result: &mut CrossBoundaryResult, + block_str: String, + pools: Vec, + ); fn ocean_invalidate_block(result: &mut CrossBoundaryResult, block: String); fn ocean_try_set_tx_result( diff --git a/lib/ain-rs-exports/src/ocean.rs b/lib/ain-rs-exports/src/ocean.rs index a1748ae8076..fc8926959f4 100644 --- a/lib/ain-rs-exports/src/ocean.rs +++ b/lib/ain-rs-exports/src/ocean.rs @@ -1,5 +1,5 @@ use ain_macros::ffi_fallible; -use ain_ocean::Result; +use ain_ocean::{PoolCreationHeight, Result}; use defichain_rpc::json::blockchain::{Block, Transaction}; use crate::{ @@ -8,9 +8,16 @@ use crate::{ }; #[ffi_fallible] -pub fn ocean_index_block(block_str: String) -> Result<()> { +pub fn ocean_index_block(block_str: String, pools: Vec) -> Result<()> { let block: Block = serde_json::from_str(&block_str)?; - ain_ocean::index_block(&ain_ocean::SERVICES, block) + let pools = pools + .into_iter() + .map(|p| PoolCreationHeight { + id: p.id, + creation_height: p.creation_height, + }) + .collect::>(); + ain_ocean::index_block(&ain_ocean::SERVICES, block, pools) } #[ffi_fallible] diff --git a/src/dfi/validation.cpp b/src/dfi/validation.cpp index bc944c9e350..7412406c5b6 100644 --- a/src/dfi/validation.cpp +++ b/src/dfi/validation.cpp @@ -3135,7 +3135,18 @@ Res ProcessDeFiEventFallible(const CBlock &block, if (gArgs.GetBoolArg("-oceanarchive", DEFAULT_OCEAN_ARCHIVE_ENABLED)) { const UniValue b = blockToJSON(block, ::ChainActive().Tip(), pindex, true, 2); CrossBoundaryResult result; - ocean_index_block(result, b.write()); + + rust::cxxbridge1::Vec pools; + pcustomcsview->ForEachPoolPair( + [&](DCT_ID const &id, CPoolPair pool) { + const auto token = pcustomcsview->GetToken(id); + if (token) { + pools.push_back({id.v, pool.creationHeight}); + }; + return true; + }, + {0}); + ocean_index_block(result, b.write(), pools); if (!result.ok) { return Res::Err(result.reason.c_str()); } diff --git a/src/init.cpp b/src/init.cpp index 9607af2f422..70c49ae6cba 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2485,8 +2485,18 @@ bool AppInitMain(InitInterfaces& interfaces) const UniValue b = blockToJSON(block, tip, pblockindex, true, 2); + rust::cxxbridge1::Vec pools; + pcustomcsview->ForEachPoolPair( + [&](DCT_ID const &id, CPoolPair pool) { + const auto token = pcustomcsview->GetToken(id); + if (token) { + pools.push_back({id.v, pool.creationHeight}); + }; + return true; + }, {0}); + CrossBoundaryResult result; - ocean_index_block(result, b.write()); + ocean_index_block(result, b.write(), pools); if (!result.ok) { LogPrintf("Error indexing genesis block: %s\n", result.reason); return false; From 34b620172fce49a01545007b18745ba86ffbd0b4 Mon Sep 17 00:00:00 2001 From: jouzo Date: Tue, 28 May 2024 09:43:30 +0100 Subject: [PATCH 096/185] Impl new in repository macro --- lib/ain-macros/src/lib.rs | 9 +++++++++ lib/ain-ocean/src/repository/block.rs | 18 ------------------ lib/ain-ocean/src/repository/masternode.rs | 18 ------------------ .../src/repository/masternode_stats.rs | 9 --------- lib/ain-ocean/src/repository/oracle.rs | 9 --------- lib/ain-ocean/src/repository/oracle_history.rs | 17 ----------------- .../src/repository/oracle_price_active.rs | 18 ------------------ .../src/repository/oracle_price_aggregated.rs | 18 ------------------ .../oracle_price_aggregated_interval.rs | 18 ------------------ .../src/repository/oracle_price_feed.rs | 18 ------------------ .../src/repository/oracle_token_currency.rs | 18 ------------------ lib/ain-ocean/src/repository/pool_swap.rs | 9 --------- .../src/repository/pool_swap_aggregated.rs | 18 ------------------ lib/ain-ocean/src/repository/price_ticker.rs | 9 --------- lib/ain-ocean/src/repository/raw_block.rs | 9 --------- lib/ain-ocean/src/repository/transaction.rs | 18 ------------------ .../src/repository/transaction_vin.rs | 9 --------- .../src/repository/transaction_vout.rs | 9 --------- lib/ain-ocean/src/repository/tx_result.rs | 9 --------- .../repository/vault_auction_batch_history.rs | 18 ------------------ 20 files changed, 9 insertions(+), 269 deletions(-) diff --git a/lib/ain-macros/src/lib.rs b/lib/ain-macros/src/lib.rs index a60b48532f3..276e0524000 100644 --- a/lib/ain-macros/src/lib.rs +++ b/lib/ain-macros/src/lib.rs @@ -102,6 +102,15 @@ pub fn repository_derive(input: TokenStream) -> TokenStream { // Generate the implementation let expanded = quote! { + impl #name { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } + } + impl RepositoryOps<#key_type_ident, #value_type_ident> for #name { type ListItem = std::result::Result<(#key_type_ident, #value_type_ident), ain_db::DBError>; diff --git a/lib/ain-ocean/src/repository/block.rs b/lib/ain-ocean/src/repository/block.rs index bbe26505868..691632795e5 100644 --- a/lib/ain-ocean/src/repository/block.rs +++ b/lib/ain-ocean/src/repository/block.rs @@ -18,15 +18,6 @@ pub struct BlockRepository { col: LedgerColumn, } -impl BlockRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - #[derive(Repository)] #[repository(K = "u32", V = "BlockHash")] pub struct BlockByHeightRepository { @@ -34,15 +25,6 @@ pub struct BlockByHeightRepository { col: LedgerColumn, } -impl BlockByHeightRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - impl BlockByHeightRepository { pub fn get_highest(&self) -> Result> { match self.col.iter(None, SortOrder::Descending.into())?.next() { diff --git a/lib/ain-ocean/src/repository/masternode.rs b/lib/ain-ocean/src/repository/masternode.rs index 42dbc3a7aa6..1f8ce1a72e0 100644 --- a/lib/ain-ocean/src/repository/masternode.rs +++ b/lib/ain-ocean/src/repository/masternode.rs @@ -18,15 +18,6 @@ pub struct MasternodeRepository { col: LedgerColumn, } -impl MasternodeRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - type MasternodeByHeightKey = (u32, Txid); #[derive(Repository)] @@ -36,15 +27,6 @@ pub struct MasternodeByHeightRepository { col: LedgerColumn, } -impl MasternodeByHeightRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - impl SecondaryIndex for MasternodeByHeightRepository { type Value = Masternode; diff --git a/lib/ain-ocean/src/repository/masternode_stats.rs b/lib/ain-ocean/src/repository/masternode_stats.rs index e81657a564a..3605b3f1471 100644 --- a/lib/ain-ocean/src/repository/masternode_stats.rs +++ b/lib/ain-ocean/src/repository/masternode_stats.rs @@ -17,15 +17,6 @@ pub struct MasternodeStatsRepository { col: LedgerColumn, } -impl MasternodeStatsRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - impl MasternodeStatsRepository { pub fn get_latest(&self) -> Result> { match self.col.iter(None, SortOrder::Descending.into())?.next() { diff --git a/lib/ain-ocean/src/repository/oracle.rs b/lib/ain-ocean/src/repository/oracle.rs index 15ff392b05b..eb1bf65eeca 100644 --- a/lib/ain-ocean/src/repository/oracle.rs +++ b/lib/ain-ocean/src/repository/oracle.rs @@ -17,12 +17,3 @@ pub struct OracleRepository { pub store: Arc, col: LedgerColumn, } - -impl OracleRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} diff --git a/lib/ain-ocean/src/repository/oracle_history.rs b/lib/ain-ocean/src/repository/oracle_history.rs index 8b6aa45c14b..6f355dd5817 100644 --- a/lib/ain-ocean/src/repository/oracle_history.rs +++ b/lib/ain-ocean/src/repository/oracle_history.rs @@ -18,26 +18,9 @@ pub struct OracleHistoryRepository { col: LedgerColumn, } -impl OracleHistoryRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} #[derive(Repository)] #[repository(K = "Txid", V = "OracleHistoryId")] pub struct OracleHistoryRepositoryKey { pub store: Arc, col: LedgerColumn, } - -impl OracleHistoryRepositoryKey { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} diff --git a/lib/ain-ocean/src/repository/oracle_price_active.rs b/lib/ain-ocean/src/repository/oracle_price_active.rs index 367a6a3a562..de1cfcf5157 100644 --- a/lib/ain-ocean/src/repository/oracle_price_active.rs +++ b/lib/ain-ocean/src/repository/oracle_price_active.rs @@ -17,27 +17,9 @@ pub struct OraclePriceActiveRepository { col: LedgerColumn, } -impl OraclePriceActiveRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - #[derive(Repository)] #[repository(K = "OraclePriceActiveKey", V = "OraclePriceActiveId")] pub struct OraclePriceActiveKeyRepository { pub store: Arc, col: LedgerColumn, } - -impl OraclePriceActiveKeyRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} diff --git a/lib/ain-ocean/src/repository/oracle_price_aggregated.rs b/lib/ain-ocean/src/repository/oracle_price_aggregated.rs index 3b8d9b926d1..ba957faffe1 100644 --- a/lib/ain-ocean/src/repository/oracle_price_aggregated.rs +++ b/lib/ain-ocean/src/repository/oracle_price_aggregated.rs @@ -17,27 +17,9 @@ pub struct OraclePriceAggregatedRepository { col: LedgerColumn, } -impl OraclePriceAggregatedRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - #[derive(Repository)] #[repository(K = "OraclePriceAggregatedKey", V = "OraclePriceAggregatedId")] pub struct OraclePriceAggregatedRepositorykey { pub store: Arc, col: LedgerColumn, } - -impl OraclePriceAggregatedRepositorykey { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} diff --git a/lib/ain-ocean/src/repository/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/repository/oracle_price_aggregated_interval.rs index 95aa9180d6c..cba9367f540 100644 --- a/lib/ain-ocean/src/repository/oracle_price_aggregated_interval.rs +++ b/lib/ain-ocean/src/repository/oracle_price_aggregated_interval.rs @@ -23,15 +23,6 @@ pub struct OraclePriceAggregatedIntervalRepository { col: LedgerColumn, } -impl OraclePriceAggregatedIntervalRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - #[derive(Repository)] #[repository( K = "OraclePriceAggregatedIntervalKey", @@ -41,12 +32,3 @@ pub struct OraclePriceAggregatedIntervalKeyRepository { pub store: Arc, col: LedgerColumn, } - -impl OraclePriceAggregatedIntervalKeyRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} diff --git a/lib/ain-ocean/src/repository/oracle_price_feed.rs b/lib/ain-ocean/src/repository/oracle_price_feed.rs index dbeddeabed7..875e162cdc1 100644 --- a/lib/ain-ocean/src/repository/oracle_price_feed.rs +++ b/lib/ain-ocean/src/repository/oracle_price_feed.rs @@ -17,27 +17,9 @@ pub struct OraclePriceFeedRepository { col: LedgerColumn, } -impl OraclePriceFeedRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - #[derive(Repository)] #[repository(K = "OraclePriceFeedkey", V = "OraclePriceFeedId")] pub struct OraclePriceFeedKeyRepository { pub store: Arc, col: LedgerColumn, } - -impl OraclePriceFeedKeyRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} diff --git a/lib/ain-ocean/src/repository/oracle_token_currency.rs b/lib/ain-ocean/src/repository/oracle_token_currency.rs index 7c99c954ffb..7d5a755840a 100644 --- a/lib/ain-ocean/src/repository/oracle_token_currency.rs +++ b/lib/ain-ocean/src/repository/oracle_token_currency.rs @@ -17,27 +17,9 @@ pub struct OracleTokenCurrencyRepository { col: LedgerColumn, } -impl OracleTokenCurrencyRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - #[derive(Repository)] #[repository(K = "OracleTokenCurrencyKey", V = "OracleTokenCurrencyId")] pub struct OracleTokenCurrencyKeyRepository { pub store: Arc, col: LedgerColumn, } - -impl OracleTokenCurrencyKeyRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} diff --git a/lib/ain-ocean/src/repository/pool_swap.rs b/lib/ain-ocean/src/repository/pool_swap.rs index 2a9e05a1d5f..5e93c9d34c7 100644 --- a/lib/ain-ocean/src/repository/pool_swap.rs +++ b/lib/ain-ocean/src/repository/pool_swap.rs @@ -17,15 +17,6 @@ pub struct PoolSwapRepository { col: LedgerColumn, } -impl PoolSwapRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - impl InitialKeyProvider for PoolSwapRepository { type PartialKey = u32; fn initial_key(pk: Self::PartialKey) -> PoolSwapKey { diff --git a/lib/ain-ocean/src/repository/pool_swap_aggregated.rs b/lib/ain-ocean/src/repository/pool_swap_aggregated.rs index 991b8053485..1360bda61d1 100644 --- a/lib/ain-ocean/src/repository/pool_swap_aggregated.rs +++ b/lib/ain-ocean/src/repository/pool_swap_aggregated.rs @@ -17,15 +17,6 @@ pub struct PoolSwapAggregatedRepository { col: LedgerColumn, } -impl PoolSwapAggregatedRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - #[derive(Repository)] #[repository(K = "PoolSwapAggregatedKey", V = "PoolSwapAggregatedId")] pub struct PoolSwapAggregatedKeyRepository { @@ -33,15 +24,6 @@ pub struct PoolSwapAggregatedKeyRepository { col: LedgerColumn, } -impl PoolSwapAggregatedKeyRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - impl SecondaryIndex for PoolSwapAggregatedKeyRepository { diff --git a/lib/ain-ocean/src/repository/price_ticker.rs b/lib/ain-ocean/src/repository/price_ticker.rs index fa22f13be42..8f83a3d032c 100644 --- a/lib/ain-ocean/src/repository/price_ticker.rs +++ b/lib/ain-ocean/src/repository/price_ticker.rs @@ -16,12 +16,3 @@ pub struct PriceTickerRepository { pub store: Arc, col: LedgerColumn, } - -impl PriceTickerRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} diff --git a/lib/ain-ocean/src/repository/raw_block.rs b/lib/ain-ocean/src/repository/raw_block.rs index b2f04f6be23..81f2d248c8f 100644 --- a/lib/ain-ocean/src/repository/raw_block.rs +++ b/lib/ain-ocean/src/repository/raw_block.rs @@ -16,12 +16,3 @@ pub struct RawBlockRepository { pub store: Arc, col: LedgerColumn, } - -impl RawBlockRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} diff --git a/lib/ain-ocean/src/repository/transaction.rs b/lib/ain-ocean/src/repository/transaction.rs index 51ad7295642..38b725bd4a6 100644 --- a/lib/ain-ocean/src/repository/transaction.rs +++ b/lib/ain-ocean/src/repository/transaction.rs @@ -18,15 +18,6 @@ pub struct TransactionRepository { col: LedgerColumn, } -impl TransactionRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - #[derive(Repository)] #[repository(K = "TransactionByBlockHashKey", V = "Txid")] pub struct TransactionByBlockHashRepository { @@ -34,15 +25,6 @@ pub struct TransactionByBlockHashRepository { col: LedgerColumn, } -impl TransactionByBlockHashRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - impl InitialKeyProvider for TransactionByBlockHashRepository { type PartialKey = BlockHash; diff --git a/lib/ain-ocean/src/repository/transaction_vin.rs b/lib/ain-ocean/src/repository/transaction_vin.rs index cb8e3552a88..cfd2ce3510e 100644 --- a/lib/ain-ocean/src/repository/transaction_vin.rs +++ b/lib/ain-ocean/src/repository/transaction_vin.rs @@ -21,15 +21,6 @@ pub struct TransactionVinRepository { col: LedgerColumn, } -impl TransactionVinRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - impl InitialKeyProvider for TransactionVinRepository { type PartialKey = Txid; diff --git a/lib/ain-ocean/src/repository/transaction_vout.rs b/lib/ain-ocean/src/repository/transaction_vout.rs index 72549b7785a..e9e994b3f4f 100644 --- a/lib/ain-ocean/src/repository/transaction_vout.rs +++ b/lib/ain-ocean/src/repository/transaction_vout.rs @@ -16,12 +16,3 @@ pub struct TransactionVoutRepository { pub store: Arc, col: LedgerColumn, } - -impl TransactionVoutRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} diff --git a/lib/ain-ocean/src/repository/tx_result.rs b/lib/ain-ocean/src/repository/tx_result.rs index 6ca87229d75..126e3acea28 100644 --- a/lib/ain-ocean/src/repository/tx_result.rs +++ b/lib/ain-ocean/src/repository/tx_result.rs @@ -17,12 +17,3 @@ pub struct TxResultRepository { pub store: Arc, col: LedgerColumn, } - -impl TxResultRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} diff --git a/lib/ain-ocean/src/repository/vault_auction_batch_history.rs b/lib/ain-ocean/src/repository/vault_auction_batch_history.rs index e6d1fca3194..2a05894bed9 100644 --- a/lib/ain-ocean/src/repository/vault_auction_batch_history.rs +++ b/lib/ain-ocean/src/repository/vault_auction_batch_history.rs @@ -17,15 +17,6 @@ pub struct AuctionHistoryRepository { col: LedgerColumn, } -impl AuctionHistoryRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - #[derive(Repository)] #[repository(K = "AuctionHistoryByHeightKey", V = "AuctionHistoryKey")] pub struct AuctionHistoryByHeightRepository { @@ -33,15 +24,6 @@ pub struct AuctionHistoryByHeightRepository { col: LedgerColumn, } -impl AuctionHistoryByHeightRepository { - pub fn new(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - impl AuctionHistoryByHeightRepository { // pub fn get_latest(&self) -> Result> { // match self.list(None::Descending)?.next() { From e5a556ba7dd52bc8bf8cf3e120a271042d08737b Mon Sep 17 00:00:00 2001 From: canonbrother Date: Wed, 29 May 2024 15:42:25 +0800 Subject: [PATCH 097/185] Ocean: list dex prices api (#2923) * fix unwrap * wip * fix query * filter untradable token * fmt_rs --- lib/ain-ocean/src/api/cache.rs | 18 ++++- lib/ain-ocean/src/api/pool_pair/mod.rs | 25 ++++--- lib/ain-ocean/src/api/pool_pair/path.rs | 7 +- lib/ain-ocean/src/api/pool_pair/price.rs | 83 ++++++++++++++++++++++ lib/ain-ocean/src/api/pool_pair/service.rs | 7 +- lib/ain-ocean/src/error.rs | 2 + 6 files changed, 129 insertions(+), 13 deletions(-) create mode 100644 lib/ain-ocean/src/api/pool_pair/price.rs diff --git a/lib/ain-ocean/src/api/cache.rs b/lib/ain-ocean/src/api/cache.rs index 5703ba45c68..eb17e1115d0 100644 --- a/lib/ain-ocean/src/api/cache.rs +++ b/lib/ain-ocean/src/api/cache.rs @@ -4,7 +4,7 @@ use cached::proc_macro::cached; use defichain_rpc::{ json::{ poolpair::{PoolPairInfo, PoolPairPagination, PoolPairsResult}, - token::TokenInfo, + token::{TokenInfo, TokenPagination, TokenResult}, }, jsonrpc_async::error::{Error as JsonRpcError, RpcError}, Error, MasternodeRPC, PoolPairRPC, TokenRPC, @@ -49,6 +49,22 @@ pub async fn get_token_cached( Ok(token) } +pub async fn list_token_cached(ctx: &Arc) -> Result { + let tokens = ctx + .client + .list_tokens( + Some(TokenPagination { + start: 0, + including_start: true, + limit: 1000, + }), + Some(true), + ) + .await?; + + Ok(tokens) +} + #[cached( result = true, key = "String", diff --git a/lib/ain-ocean/src/api/pool_pair/mod.rs b/lib/ain-ocean/src/api/pool_pair/mod.rs index e9a16a8b4c8..a3d380afe88 100644 --- a/lib/ain-ocean/src/api/pool_pair/mod.rs +++ b/lib/ain-ocean/src/api/pool_pair/mod.rs @@ -43,9 +43,11 @@ use path::{ SwapPathsResponse, }; +use price::DexPriceResponse; use service::{get_aggregated_in_usd, get_apr, get_total_liquidity_usd}; pub mod path; +pub mod price; pub mod service; // #[derive(Deserialize)] @@ -59,10 +61,10 @@ struct SwapAggregate { interval: u32, } -// #[derive(Debug, Deserialize)] -// struct DexPrices { -// denomination: Option, -// } +#[derive(Debug, Deserialize, Default)] +struct DexPrices { + denomination: String, +} #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] @@ -661,10 +663,15 @@ async fn get_best_path( })) } -// #[ocean_endpoint] -// async fn list_dex_prices(Query(DexPrices { denomination }): Query) -> String { -// format!("List of DEX prices with denomination {:?}", denomination) -// } +#[ocean_endpoint] +async fn list_dex_prices( + Query(DexPrices { denomination }): Query, + Extension(ctx): Extension>, +) -> Result> { + let prices = price::list_dex_prices(&ctx, denomination).await?; + + Ok(Response::new(prices)) +} pub fn router(ctx: Arc) -> Router { Router::new() @@ -682,6 +689,6 @@ pub fn router(ctx: Arc) -> Router { get(list_pool_swap_aggregates), ) .route("/paths/swappable/:tokenId", get(get_swappable_tokens)) - // .route("/dexprices", get(list_dex_prices)) + .route("/dexprices", get(list_dex_prices)) .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/api/pool_pair/path.rs b/lib/ain-ocean/src/api/pool_pair/path.rs index e481300c619..65d63ca44c1 100644 --- a/lib/ain-ocean/src/api/pool_pair/path.rs +++ b/lib/ain-ocean/src/api/pool_pair/path.rs @@ -13,8 +13,9 @@ use crate::{ cache::{get_pool_pair_cached, get_token_cached, list_pool_pairs_cached}, common::{format_number, parse_dat_symbol}, }, + error::NotFoundKind, network::Network, - Result, TokenIdentifier, + Error, Result, TokenIdentifier, }; #[derive(Debug, Serialize)] @@ -101,7 +102,9 @@ impl StackSet { } pub async fn get_token_identifier(ctx: &Arc, id: &str) -> Result { - let (id, token) = get_token_cached(ctx, id).await?.unwrap(); + let (id, token) = get_token_cached(ctx, id) + .await? + .ok_or(Error::NotFound(NotFoundKind::Token))?; Ok(TokenIdentifier { id, display_symbol: parse_dat_symbol(&token.symbol), diff --git a/lib/ain-ocean/src/api/pool_pair/price.rs b/lib/ain-ocean/src/api/pool_pair/price.rs new file mode 100644 index 00000000000..e4d1bf6f320 --- /dev/null +++ b/lib/ain-ocean/src/api/pool_pair/price.rs @@ -0,0 +1,83 @@ +use serde::Serialize; +use std::{collections::HashMap, sync::Arc}; + +use defichain_rpc::json::token::TokenInfo; + +use super::{path::get_best_path, AppContext}; + +use crate::{ + api::{ + cache::{get_token_cached, list_token_cached}, + common::parse_display_symbol, + }, + error::{Error, NotFoundKind}, + Result, TokenIdentifier, +}; + +#[derive(Clone, Debug, Serialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct DexPrice { + pub token: TokenIdentifier, + pub denomination_price: String, +} + +#[derive(Clone, Debug, Serialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct DexPriceResponse { + pub denomination: TokenIdentifier, + pub dex_prices: HashMap, +} + +fn is_untradable_token(token: &TokenInfo) -> bool { + token.is_lps || !token.is_dat || token.symbol == *"BURN" || !token.tradeable +} + +pub async fn list_dex_prices(ctx: &Arc, symbol: String) -> Result { + let (denomination_token_id, denomination_token_info) = get_token_cached(ctx, &symbol) + .await? + .ok_or(Error::NotFound(NotFoundKind::Token))?; + + if is_untradable_token(&denomination_token_info) { + return Err(Error::UntradeableTokenError(denomination_token_info.symbol)); + }; + + let tokens = list_token_cached(ctx) + .await? + .0 + .into_iter() + .filter(|(_, info)| !is_untradable_token(info)) + .collect::>(); + + let mut dex_prices = HashMap::::new(); + + // For every token available, compute estimated return in denomination token + for (id, info) in tokens { + if id == denomination_token_id { + continue; + } + let best_path = get_best_path(ctx, &id, &denomination_token_id).await?; + + dex_prices.insert( + info.clone().symbol, + DexPrice { + token: TokenIdentifier { + id, + display_symbol: parse_display_symbol(&info), + name: info.name, + symbol: info.symbol, + }, + denomination_price: best_path.estimated_return, + }, + ); + } + + Ok(DexPriceResponse { + denomination: TokenIdentifier { + id: denomination_token_id, + display_symbol: parse_display_symbol(&denomination_token_info), + name: denomination_token_info.name, + symbol: denomination_token_info.symbol, + }, + dex_prices, + }) +} diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index 3083fa9660d..0650d1df679 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -69,7 +69,12 @@ async fn get_total_liquidity_usd_by_best_path( ctx: &Arc, p: &PoolPairInfo, ) -> Result { - let (usdt_id, _) = get_token_cached(ctx, "USDT").await?.unwrap(); + let usdt = get_token_cached(ctx, "USDT").await?; + if usdt.is_none() { + return Ok(dec!(0)); + }; + + let (usdt_id, _) = usdt.unwrap(); let mut a_token_rate = dec!(1); let mut b_token_rate = dec!(1); diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 1f8d2efb6c6..617b1e6c063 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -59,6 +59,8 @@ pub enum Error { UnderflowError, #[error("Error fetching primary value")] SecondaryIndex, + #[error("Token {0:?} is invalid as it is not tradeable")] + UntradeableTokenError(String), #[error(transparent)] Other(#[from] anyhow::Error), } From b892a42e436da4235a92f95a5e38e7de320ebba3 Mon Sep 17 00:00:00 2001 From: Nagaraj <144004792+nagarajm22@users.noreply.github.com> Date: Wed, 29 May 2024 16:57:55 +0800 Subject: [PATCH 098/185] ocean indexing active price (#2892) * indexing active price * index implemetation for active_price SetLoanToken * updated price ticker storage * updated active price * updated SetLoanToken from active_price * handling empty loan_value * updated pirces api and oracles * fixed comments * fixed comments * updated api method name get_feed and response * fixed duplicated insertion of oracle * fixed duplicated insertion * fixed oracle map_price_feeds * testing for oralces * fixed oracles repeating data * added testcase for oracle_price_feed * updated api query for oracle get feed and test cases * updated price api * price changes made in map_aggregated * fixed the api amount decimal point * fix list_prices order * updated index interval for oracle * fixed conflicts * remove of script.sh * Clippy fix * Clippy tests --------- Co-authored-by: canonbrother Co-authored-by: jouzo --- lib/Cargo.lock | 1 + lib/Cargo.toml | 1 + lib/ain-ocean/Cargo.toml | 1 + lib/ain-ocean/src/api/common.rs | 12 + lib/ain-ocean/src/api/masternode/mod.rs | 1 - lib/ain-ocean/src/api/mod.rs | 2 + lib/ain-ocean/src/api/oracle.rs | 81 +- lib/ain-ocean/src/api/pool_pair/mod.rs | 16 +- lib/ain-ocean/src/api/pool_pair/path.rs | 1 - lib/ain-ocean/src/api/pool_pair/service.rs | 14 +- lib/ain-ocean/src/api/prices.rs | 384 +++--- lib/ain-ocean/src/bin/cli.rs | 1 + lib/ain-ocean/src/indexer/loan_token.rs | 185 +++ lib/ain-ocean/src/indexer/mod.rs | 4 +- lib/ain-ocean/src/indexer/oracle.rs | 367 +++--- lib/ain-ocean/src/indexer/oracle_test.rs | 1037 ++++++++++++++++- lib/ain-ocean/src/lib.rs | 15 +- lib/ain-ocean/src/model/mod.rs | 2 - lib/ain-ocean/src/model/oracle.rs | 15 +- .../src/model/oracle_price_active.rs | 8 +- .../src/model/oracle_price_aggregated.rs | 16 +- lib/ain-ocean/src/model/oracle_price_feed.rs | 16 + .../src/model/oracle_token_currency.rs | 2 +- .../src/model/poolswap_aggregated.rs | 5 +- lib/ain-ocean/src/model/price_ticker.rs | 12 +- lib/ain-ocean/src/model/prices.rs | 14 - lib/ain-ocean/src/repository/price_ticker.rs | 27 +- lib/ain-ocean/src/storage/columns/mod.rs | 3 +- .../storage/columns/pool_swap_aggregated.rs | 3 +- .../src/storage/columns/price_ticker.rs | 40 +- 30 files changed, 1883 insertions(+), 403 deletions(-) create mode 100644 lib/ain-ocean/src/indexer/loan_token.rs delete mode 100644 lib/ain-ocean/src/model/prices.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 7c057de0627..b944da3bddc 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -254,6 +254,7 @@ dependencies = [ "futures", "hex", "hyper 0.14.28", + "indexmap 2.2.6", "json", "jsonrpc-async", "jsonrpsee 0.16.3", diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 1f05d06f708..353dc5ba9d7 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -39,6 +39,7 @@ serde_json = "1.0" tokio = { version = "1.1", features = ["rt-multi-thread"] } async-trait = "0.1" regex = "1.5" +indexmap = "2.2.6" ## build diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index c5e5ee1287d..6130290514d 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -46,6 +46,7 @@ clap = { version = "4.5.0", features = ["derive"] } num_cpus.workspace = true petgraph = { version = "0.6.4", features = ["serde-1"] } parking_lot.workspace = true +indexmap.workspace = true [dev-dependencies] tempdir.workspace = true diff --git a/lib/ain-ocean/src/api/common.rs b/lib/ain-ocean/src/api/common.rs index 5d91fe75a53..8bb6293655d 100644 --- a/lib/ain-ocean/src/api/common.rs +++ b/lib/ain-ocean/src/api/common.rs @@ -160,3 +160,15 @@ where Box::new(self.skip(query.next.is_some() as usize).take(query.size)) } } + +pub fn split_key(key: &str) -> Result<(String, String), String> { + let parts: Vec<&str> = key.split('-').collect(); + if parts.len() == 2 { + Ok((parts[0].to_owned(), parts[1].to_owned())) + } else { + Err(format!( + "Invalid key format: '{}'. Expected format 'token-currency'.", + key + )) + } +} diff --git a/lib/ain-ocean/src/api/masternode/mod.rs b/lib/ain-ocean/src/api/masternode/mod.rs index 438f2923f68..3c9a95020c2 100644 --- a/lib/ain-ocean/src/api/masternode/mod.rs +++ b/lib/ain-ocean/src/api/masternode/mod.rs @@ -13,7 +13,6 @@ use bitcoin::Txid; use serde::{Deserialize, Serialize}; use self::state::{MasternodeService, MasternodeState}; - use super::{ query::PaginationQuery, response::{ApiPagedResponse, Response}, diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index 8e253717539..d3fce25083f 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -81,6 +81,8 @@ pub async fn ocean_router( .nest("/oracles", oracle::router(Arc::clone(&context))) .nest("/poolpairs", pool_pair::router(Arc::clone(&context))) // .nest("/prices", prices::router(Arc::clone(&context))) + // .nest("/poolpairs", poolpairs::router(Arc::clone(&context))) + .nest("/prices", prices::router(Arc::clone(&context))) // .nest("/rawtx", rawtx::router(Arc::clone(&context))) .nest("/stats", stats::router(Arc::clone(&context))) .nest("/tokens", tokens::router(Arc::clone(&context))) diff --git a/lib/ain-ocean/src/api/oracle.rs b/lib/ain-ocean/src/api/oracle.rs index d46d674642c..a275cd26801 100644 --- a/lib/ain-ocean/src/api/oracle.rs +++ b/lib/ain-ocean/src/api/oracle.rs @@ -1,21 +1,25 @@ use std::{str::FromStr, sync::Arc}; use ain_macros::ocean_endpoint; +use anyhow::anyhow; use axum::{ extract::{Path, Query}, routing::get, Extension, Router, }; use bitcoin::Txid; +use rust_decimal::{prelude::FromPrimitive, Decimal}; use super::{ + common::split_key, query::PaginationQuery, response::{ApiPagedResponse, Response}, AppContext, }; use crate::{ + api::common::Paginate, error::{ApiError, Error, NotFoundKind}, - model::{Oracle, OraclePriceFeed}, + model::{ApiResponseOraclePriceFeed, Oracle}, repository::RepositoryOps, storage::SortOrder, Result, @@ -44,35 +48,57 @@ async fn list_oracles( oracles.id })) } + #[ocean_endpoint] -async fn get_price_feed( +async fn get_feed( Path((oracle_id, key)): Path<(String, String)>, Query(query): Query, Extension(ctx): Extension>, -) -> Result> { +) -> Result> { let txid = Txid::from_str(&oracle_id)?; - let (token, currency) = split_key(&key); - let oracle_price_feed = ctx + let (token, currency) = match split_key(&key) { + Ok((t, c)) => (t, c), + Err(e) => return Err(Error::Other(anyhow!("Failed to split key: {}", e))), + }; + let key = (token.clone(), currency.clone(), txid); + + let price_feed_list = ctx .services .oracle_price_feed - .by_key - .list(Some((token, currency, txid)), SortOrder::Descending)? - .take(query.size) - .map(|item| { - let (_, id) = item?; - let b = ctx - .services - .oracle_price_feed - .by_id - .get(&id)? - .ok_or("Missing price feed index")?; + .by_id + .list(None, SortOrder::Descending)? + .paginate(&query) + .map(|res| res.expect("Error retrieving key")) + .collect::>(); - Ok(b) - }) - .collect::>>()?; - Ok(ApiPagedResponse::of(oracle_price_feed, 2, |price_feed| { - price_feed.sort.clone() - })) + let mut oracle_price_feeds = Vec::new(); + + for (_, feed) in &price_feed_list { + let (token, currency, oracle_id, _) = &feed.id; + if key.0.eq(token) && key.1.eq(currency) && key.2.eq(oracle_id) { + let amount_decimal = Decimal::from_i64(feed.amount).unwrap_or_default(); + let conversion_factor = Decimal::from_i32(100000000).unwrap_or_default(); + let amount = amount_decimal / conversion_factor; + oracle_price_feeds.push(ApiResponseOraclePriceFeed { + id: format!("{}-{}-{}-{}", token, currency, feed.oracle_id, feed.txid), + key: format!("{}-{}-{}", token, currency, feed.oracle_id), + sort: feed.sort.clone(), + token: feed.token.clone(), + currency: feed.currency.clone(), + oracle_id: feed.oracle_id, + txid: feed.txid, + time: feed.time, + amount: amount.to_string(), + block: feed.block.clone(), + }); + } + } + + Ok(ApiPagedResponse::of( + oracle_price_feeds, + query.size, + |price_feed| price_feed.sort.clone(), + )) } #[ocean_endpoint] @@ -99,19 +125,10 @@ async fn get_oracle_by_address( Ok(Response::new(oracle)) } -fn split_key(key: &str) -> (String, String) { - let parts: Vec<&str> = key.split('-').collect(); - if parts.len() == 2 { - (parts[0].to_owned(), parts[1].to_owned()) - } else { - (String::new(), String::new()) - } -} - pub fn router(ctx: Arc) -> Router { Router::new() .route("/", get(list_oracles)) - .route("/:oracleId/:key/feed", get(get_price_feed)) + .route("/:oracleId/:key/feed", get(get_feed)) .route("/:address", get(get_oracle_by_address)) .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/api/pool_pair/mod.rs b/lib/ain-ocean/src/api/pool_pair/mod.rs index a3d380afe88..ea2927678bb 100644 --- a/lib/ain-ocean/src/api/pool_pair/mod.rs +++ b/lib/ain-ocean/src/api/pool_pair/mod.rs @@ -1,4 +1,3 @@ -use petgraph::graphmap::UnGraphMap; use std::{ collections::{HashMap, HashSet}, sync::Arc, @@ -15,10 +14,17 @@ use defichain_rpc::{ RpcApi, }; use futures::future::try_join_all; +use path::{ + compute_return_less_dex_fees_in_destination_token, get_all_swap_paths, get_token_identifier, + sync_token_graph_if_empty, BestSwapPathResponse, EstimatedLessDexFeeInfo, SwapPathPoolPair, + SwapPathsResponse, +}; +use petgraph::graphmap::UnGraphMap; use rust_decimal::Decimal; use rust_decimal_macros::dec; use serde::{Deserialize, Serialize}; use serde_json::json; +use service::{get_aggregated_in_usd, get_apr, get_total_liquidity_usd}; use super::{ cache::{get_pool_pair_cached, get_token_cached}, @@ -28,7 +34,6 @@ use super::{ response::{ApiPagedResponse, Response}, AppContext, }; - use crate::{ error::{ApiError, Error}, model::{BlockContext, PoolSwap, PoolSwapAggregated}, @@ -37,14 +42,7 @@ use crate::{ Result, TokenIdentifier, }; -use path::{ - compute_return_less_dex_fees_in_destination_token, get_all_swap_paths, get_token_identifier, - sync_token_graph_if_empty, BestSwapPathResponse, EstimatedLessDexFeeInfo, SwapPathPoolPair, - SwapPathsResponse, -}; - use price::DexPriceResponse; -use service::{get_aggregated_in_usd, get_apr, get_total_liquidity_usd}; pub mod path; pub mod price; diff --git a/lib/ain-ocean/src/api/pool_pair/path.rs b/lib/ain-ocean/src/api/pool_pair/path.rs index 65d63ca44c1..ec10f53e66d 100644 --- a/lib/ain-ocean/src/api/pool_pair/path.rs +++ b/lib/ain-ocean/src/api/pool_pair/path.rs @@ -7,7 +7,6 @@ use rust_decimal_macros::dec; use serde::Serialize; use super::AppContext; - use crate::{ api::{ cache::{get_pool_pair_cached, get_token_cached, list_pool_pairs_cached}, diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index 0650d1df679..1a11d494fbd 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -1,14 +1,16 @@ -use super::{AppContext, PoolPairAprResponse}; -use anyhow::format_err; -use anyhow::Context; +use std::{str::FromStr, sync::Arc}; + +use anyhow::{format_err, Context}; use defichain_rpc::{json::poolpair::PoolPairInfo, BlockchainRPC}; use rust_decimal::{prelude::FromPrimitive, Decimal}; use rust_decimal_macros::dec; -use std::{str::FromStr, sync::Arc}; +use super::{AppContext, PoolPairAprResponse}; use crate::{ - api::cache::{get_gov_cached, get_pool_pair_cached, get_token_cached}, - api::pool_pair::path::{get_best_path, BestSwapPathResponse}, + api::{ + cache::{get_gov_cached, get_pool_pair_cached, get_token_cached}, + pool_pair::path::{get_best_path, BestSwapPathResponse}, + }, error::{Error, NotFoundKind}, model::PoolSwapAggregatedAggregated, Result, diff --git a/lib/ain-ocean/src/api/prices.rs b/lib/ain-ocean/src/api/prices.rs index 192ad4694c2..f5d96ef2266 100644 --- a/lib/ain-ocean/src/api/prices.rs +++ b/lib/ain-ocean/src/api/prices.rs @@ -1,13 +1,17 @@ -use std::sync::Arc; +use std::{str::FromStr, sync::Arc}; use ain_macros::ocean_endpoint; +use anyhow::anyhow; use axum::{ extract::{Path, Query}, routing::get, Extension, Router, }; +use indexmap::IndexSet; +use rust_decimal::{prelude::FromPrimitive, Decimal}; use super::{ + common::split_key, query::PaginationQuery, response::{ApiPagedResponse, Response}, AppContext, @@ -15,9 +19,10 @@ use super::{ use crate::{ error::{ApiError, Error, NotFoundKind}, model::{ - OracleIntervalSeconds, OraclePriceActive, OraclePriceAggregated, + ApiResponseOraclePriceFeed, OracleIntervalSeconds, OraclePriceActive, + OraclePriceAggregated, OraclePriceAggregatedAggregated, OraclePriceAggregatedApi, OraclePriceAggregatedInterval, OraclePriceAggregatedIntervalAggregated, - OracleTokenCurrency, PriceTicker, + OracleTokenCurrency, PriceOracles, PriceTickerApi, }, repository::RepositoryOps, storage::SortOrder, @@ -28,24 +33,61 @@ use crate::{ async fn list_prices( Query(query): Query, Extension(ctx): Extension>, -) -> Result> { - "List of prices".to_string(); - let prices = ctx +) -> Result> { + let sorted_ids = ctx .services .price_ticker - .by_id + .by_key .list(None, SortOrder::Descending)? - .take(query.size) .map(|item| { - let (id, priceticker) = item?; - Ok((id, priceticker)) + let (_, id) = item?; + Ok(id) }) .collect::>>()?; - let prices: Vec = prices + // use IndexSet to rm dup without changing order + let mut sorted_ids_set = IndexSet::new(); + for id in sorted_ids { + sorted_ids_set.insert(id); + } + + let prices = sorted_ids_set .into_iter() - .map(|(_, price_ticker)| price_ticker) - .collect(); + .take(query.size) + .map(|id| { + let price_ticker = ctx + .services + .price_ticker + .by_id + .get(&id)? + .ok_or("Missing price ticker index")?; + + let original_amount = price_ticker.price.aggregated.amount; + let amount_decimal = Decimal::from_str(&original_amount).unwrap_or_default(); + let conversion_factor = Decimal::from_i32(100000000).unwrap_or_default(); + let amount = amount_decimal / conversion_factor; + Ok(PriceTickerApi { + id: format!("{}-{}", price_ticker.id.0, price_ticker.id.1), + sort: price_ticker.sort, + price: OraclePriceAggregatedApi { + id: format!( + "{}-{}-{}", + price_ticker.price.id.0, price_ticker.price.id.1, price_ticker.price.id.2 + ), + key: format!("{}-{}", price_ticker.price.key.0, price_ticker.price.key.1), + sort: price_ticker.price.sort, + token: price_ticker.price.token, + currency: price_ticker.price.currency, + aggregated: OraclePriceAggregatedAggregated { + amount: amount.to_string(), + weightage: price_ticker.price.aggregated.weightage, + oracles: price_ticker.price.aggregated.oracles, + }, + block: price_ticker.price.block, + }, + }) + }) + .collect::>>()?; Ok(ApiPagedResponse::of(prices, query.size, |price| { price.sort.to_string() @@ -53,13 +95,46 @@ async fn list_prices( } #[ocean_endpoint] async fn get_price( - Path(token): Path, - Path(curreny): Path, + Path(key): Path, Extension(ctx): Extension>, -) -> Result> { - let price_ticker_id = (token, curreny); +) -> Result> { + let (token, currency) = match split_key(&key) { + Ok((t, c)) => (t, c), + Err(e) => return Err(Error::Other(anyhow!("Failed to split key: {}", e))), + }; + let price_ticker_id = (token, currency); if let Some(price_ticker) = ctx.services.price_ticker.by_id.get(&price_ticker_id)? { - Ok(Response::new(price_ticker)) + if price_ticker.price.token.eq(&price_ticker_id.0) + && price_ticker.price.currency.eq(&price_ticker_id.1) + { + let original_amount = price_ticker.price.aggregated.amount; + let amount_decimal = Decimal::from_str(&original_amount).unwrap_or_default(); + let conversion_factor = Decimal::from_i32(100000000).unwrap_or_default(); + let amount = amount_decimal / conversion_factor; + let ticker = PriceTickerApi { + id: format!("{}-{}", price_ticker.id.0, price_ticker.id.1), + sort: price_ticker.sort, + price: OraclePriceAggregatedApi { + id: format!( + "{}-{}-{}", + price_ticker.price.id.0, price_ticker.price.id.1, price_ticker.price.id.2 + ), + key: format!("{}-{}", price_ticker.price.key.0, price_ticker.price.key.1), + sort: price_ticker.price.sort, + token: price_ticker.price.token, + currency: price_ticker.price.currency, + aggregated: OraclePriceAggregatedAggregated { + amount: amount.to_string(), + weightage: price_ticker.price.aggregated.weightage, + oracles: price_ticker.price.aggregated.oracles, + }, + block: price_ticker.price.block, + }, + }; + Ok(Response::new(ticker)) + } else { + Err(Error::NotFound(NotFoundKind::Oracle)) + } } else { Err(Error::NotFound(NotFoundKind::Oracle)) } @@ -67,194 +142,220 @@ async fn get_price( #[ocean_endpoint] async fn get_feed( + Path(key): Path, Query(query): Query, Extension(ctx): Extension>, ) -> Result> { - let next = query - .next - .map(|q| { - let parts: Vec<&str> = q.split('-').collect(); - if parts.len() != 2 { - return Err("Invalid query format"); - } - let token = parts[0].parse::().map_err(|_| "Invalid token")?; - let currency = parts[1].parse::().map_err(|_| "Invalid currency")?; - Ok((token, currency)) - }) - .transpose()?; + let (token, currency) = match split_key(&key) { + Ok((t, c)) => (t, c), + Err(e) => return Err(Error::Other(anyhow!("Failed to split key: {}", e))), + }; + let aggregated_key = (token, currency); + let mut oracle_aggrigated = Vec::new(); let aggregated = ctx .services .oracle_price_aggregated - .by_key - .list(next, SortOrder::Descending)? + .by_id + .list(None, SortOrder::Ascending)? .take(query.size) .map(|item| { - let (_, id) = item?; - let b = ctx - .services - .oracle_price_aggregated - .by_id - .get(&id)? - .ok_or("Missing price_aggregated index")?; - - Ok(b) + let (_, price_aggrigated) = item?; + Ok(price_aggrigated) }) .collect::>>()?; - Ok(ApiPagedResponse::of(aggregated, query.size, |aggre| { - aggre.sort.to_string() - })) + for aggre in aggregated { + let (token, currency, _) = &aggre.id; + if aggregated_key.0.eq(token) && aggregated_key.1.eq(currency) { + oracle_aggrigated.push(aggre); + } + } + Ok(ApiPagedResponse::of( + oracle_aggrigated, + query.size, + |aggre| aggre.sort.to_string(), + )) } #[ocean_endpoint] async fn get_feed_active( + Path(key): Path, Query(query): Query, Extension(ctx): Extension>, ) -> Result> { - let next = query - .next - .map(|q| { - let parts: Vec<&str> = q.split('-').collect(); - if parts.len() != 2 { - return Err("Invalid query format"); - } - let token = parts[0].parse::().map_err(|_| "Invalid token")?; - let currency = parts[1].parse::().map_err(|_| "Invalid currency")?; - Ok((token, currency)) - }) - .transpose()?; + let (token, currency) = match split_key(&key) { + Ok((t, c)) => (t, c), + Err(e) => return Err(Error::Other(anyhow!("Failed to split key: {}", e))), + }; + let price_active_key = (token, currency); + let mut price_list = Vec::new(); let price_active = ctx .services .oracle_price_active - .by_key - .list(next, SortOrder::Descending)? + .by_id + .list(None, SortOrder::Descending)? .take(query.size) .map(|item| { - let (_, id) = item?; - let b = ctx - .services - .oracle_price_active - .by_id - .get(&id)? - .ok_or("Missing price active index")?; - Ok(b) + let (_, data) = item?; + Ok(data) }) .collect::>>()?; + for active in price_active { + let (token, currency, _) = &active.id; + if price_active_key.0.eq(token) && price_active_key.1.eq(currency) { + price_list.push(active); + } + } Ok(ApiPagedResponse::of( - price_active, + price_list, query.size, |price_active| price_active.sort.to_string(), )) } #[ocean_endpoint] async fn get_feed_with_interval( + Path((key, interval)): Path<(String, String)>, Query(query): Query, Extension(ctx): Extension>, ) -> Result> { - let next = query - .next - .map(|q| { - let parts: Vec<&str> = q.split('-').collect(); - if parts.len() != 3 { - return Err("Invalid query format"); - } - let token = parts[0].parse::().map_err(|_| "Invalid token")?; - let currency = parts[1].parse::().map_err(|_| "Invalid currency")?; - let interval = match parts[2] { - "900" => OracleIntervalSeconds::FifteenMinutes, - "3600" => OracleIntervalSeconds::OneHour, - "86400" => OracleIntervalSeconds::OneDay, - _ => return Err("Invalid interval"), - }; - Ok((token, currency, interval)) - }) - .transpose()?; + println!("the value {:?} {:?}", key, interval); + let (token, currency) = match split_key(&key) { + Ok((t, c)) => (t, c), + Err(e) => return Err(Error::Other(anyhow!("Failed to split key: {}", e))), + }; + let interval = match interval.as_str() { + "900" => OracleIntervalSeconds::FifteenMinutes, + "3600" => OracleIntervalSeconds::OneHour, + "86400" => OracleIntervalSeconds::OneDay, + _ => return Err(From::from("Invalid interval")), + }; + let mut feed_intervals = Vec::new(); + let price_aggregated_interval = (&token, ¤cy, interval.clone()); let items = ctx .services .oracle_price_aggregated_interval - .by_key - .list(next.clone(), SortOrder::Descending)? + .by_id + .list(None, SortOrder::Descending)? .take(query.size) .map(|item| { - let (_, id) = item?; - let price_agrregated_interval = ctx - .services - .oracle_price_aggregated_interval - .by_id - .get(&id)? - .ok_or("Missing oracle price aggregated interval index")?; - Ok(price_agrregated_interval) + let (_, data) = item?; + Ok(data) }) .collect::>>()?; - let mapped: Vec = items - .into_iter() - .map(|item| { - let _start = - item.block.median_time - (item.block.median_time % next.clone().unwrap().2 as i64); - OraclePriceAggregatedInterval { - id: item.id, - key: item.key, - sort: item.sort, - token: item.token, - currency: item.currency, + for oracle_intervals in items { + let (token, currency, _) = &oracle_intervals.key; + if price_aggregated_interval.0.eq(token) && price_aggregated_interval.1.eq(currency) { + feed_intervals.push(OraclePriceAggregatedInterval { + id: oracle_intervals.id, + key: oracle_intervals.key, + sort: oracle_intervals.sort, + token: oracle_intervals.token, + currency: oracle_intervals.currency, aggregated: OraclePriceAggregatedIntervalAggregated { - amount: item.aggregated.amount, - weightage: item.aggregated.weightage, - count: item.aggregated.count, - oracles: item.aggregated.oracles, + amount: oracle_intervals.aggregated.amount, + weightage: oracle_intervals.aggregated.weightage, + count: oracle_intervals.aggregated.count, + oracles: oracle_intervals.aggregated.oracles, }, - block: item.block, - } - }) - .collect(); + block: oracle_intervals.block, + }); + } + } - Ok(ApiPagedResponse::of(mapped, query.size, |item| { + Ok(ApiPagedResponse::of(feed_intervals, query.size, |item| { item.sort.clone() })) } #[ocean_endpoint] async fn get_oracles( + Path(key): Path, Query(query): Query, Extension(ctx): Extension>, -) -> Result> { - let next = query - .next - .map(|q| { - let parts: Vec<&str> = q.split('-').collect(); - if parts.len() != 2 { - return Err("Invalid query format"); - } - let token = parts[0].parse::().map_err(|_| "Invalid token")?; - let currency = parts[1].parse::().map_err(|_| "Invalid currency")?; - Ok((token, currency)) - }) - .transpose()?; - let items = ctx +) -> Result> { + let (token, currency) = match split_key(&key) { + Ok((t, c)) => (t, c), + Err(e) => return Err(Error::Other(anyhow!("Failed to split key: {}", e))), + }; + let mut oracles_feed = Vec::new(); + let oracle_token_currency_key = (token, currency); + let token_currency: Vec = ctx .services .oracle_token_currency - .by_key - .list(next, SortOrder::Descending)? + .by_id + .list(None, SortOrder::Ascending)? .take(query.size) .map(|item| { - let (_, id) = item?; - let b = ctx - .services - .oracle_token_currency - .by_id - .get(&id)? - .ok_or("Missing token-currency index")?; - Ok(b) + let (_, data) = item?; + Ok(data) }) .collect::>>()?; - Ok(ApiPagedResponse::of(items, query.size, |item| { + let price_feed = ctx + .services + .oracle_price_feed + .by_id + .list(None, SortOrder::Ascending)? + .take(query.size) + .map(|item| { + let (_, data) = item?; + Ok(data) + }) + .collect::>>()?; + + for item in token_currency { + let (token, currency, _) = &item.id; + if oracle_token_currency_key.clone().0.eq(token) + && oracle_token_currency_key.clone().1.eq(currency) + { + let mut oracleprice = None; + for pricefeed in &price_feed { + let (token, currency, _, _) = &pricefeed.id; + if oracle_token_currency_key.clone().0.eq(token) + && oracle_token_currency_key.clone().1.eq(currency) + { + oracleprice = Some(ApiResponseOraclePriceFeed { + id: format!( + "{}{}{}{}", + pricefeed.token, + pricefeed.currency, + pricefeed.oracle_id, + pricefeed.txid + ), + key: format!( + "{}{}{}", + pricefeed.token, pricefeed.currency, pricefeed.oracle_id + ), + sort: pricefeed.sort.clone(), + token: pricefeed.token.clone(), + currency: pricefeed.currency.clone(), + oracle_id: item.oracle_id, + txid: pricefeed.txid, + time: pricefeed.time, + amount: pricefeed.amount.to_string(), + block: pricefeed.block.clone(), + }); + } + } + oracles_feed.push(PriceOracles { + id: format!("{}-{}-{}", item.id.0, item.id.1, item.id.2), + key: format!("{}-{}", item.key.0, item.key.1), + token: item.token, + currency: item.currency, + oracle_id: item.oracle_id.to_string(), + feed: oracleprice, + block: item.block, + weightage: item.weightage, + }); + } + } + Ok(ApiPagedResponse::of(oracles_feed, query.size, |item| { item.oracle_id.to_string() })) } -pub fn router(_ctx: Arc) -> Router { +pub fn router(ctx: Arc) -> Router { Router::new() .route("/", get(list_prices)) .route("/:key", get(get_price)) @@ -262,4 +363,5 @@ pub fn router(_ctx: Arc) -> Router { .route("/:key/feed", get(get_feed)) .route("/:key/feed/interval/:interval", get(get_feed_with_interval)) .route("/:key/oracles", get(get_oracles)) + .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/bin/cli.rs b/lib/ain-ocean/src/bin/cli.rs index 0fbc9136ebe..8604e28608e 100644 --- a/lib/ain-ocean/src/bin/cli.rs +++ b/lib/ain-ocean/src/bin/cli.rs @@ -74,6 +74,7 @@ async fn main() -> Result<()> { .get_highest()? .map_or(0, |b| b.height); let new_height = highest_block + 1; + println!("Processed height in {:?}", new_height); let hash = if let Some(hash) = next_block_hash { hash } else { diff --git a/lib/ain-ocean/src/indexer/loan_token.rs b/lib/ain-ocean/src/indexer/loan_token.rs new file mode 100644 index 00000000000..b62abe22dc1 --- /dev/null +++ b/lib/ain-ocean/src/indexer/loan_token.rs @@ -0,0 +1,185 @@ +use std::sync::Arc; + +use ain_dftx::loans::SetLoanToken; +use rust_decimal::{prelude::Zero, Decimal}; + +use crate::{ + indexer::{Context, Index, Result}, + model::{ + OraclePriceActive, OraclePriceActiveActive, OraclePriceActiveActiveOracles, + OraclePriceActiveNext, OraclePriceActiveNextOracles, OraclePriceAggregated, + }, + repository::RepositoryOps, + storage::SortOrder, + Services, +}; +impl Index for SetLoanToken { + fn index(self, services: &Arc, ctx: &Context) -> Result<()> { + let ticker_id = (self.currency_pair.token, self.currency_pair.currency); + let aggregated_price = services + .oracle_price_aggregated + .by_key + .list(Some(ticker_id.clone()), SortOrder::Descending)? + .map(|item| { + let (_, id) = item?; + let b = services + .oracle_price_aggregated + .by_id + .get(&id)? + .ok_or("Missing oracle previous history index")?; + + Ok(b) + }) + .collect::, Box>>()?; + + if !aggregated_price.is_empty() { + let previous_price = services + .oracle_price_active + .by_key + .list(Some(ticker_id.clone()), SortOrder::Descending)? + .map(|item| { + let (_, id) = item?; + let b = services + .oracle_price_active + .by_id + .get(&id)? + .ok_or("Missing oracle previous history index")?; + + Ok(b) + }) + .collect::, Box>>()?; + let price_active_id = ( + ticker_id.0.clone(), + ticker_id.1.clone(), + aggregated_price[0].block.height, + ); + + let oracle_price_key = (ticker_id.0, ticker_id.1); + let next_price = match aggregated_validate(aggregated_price[0].clone(), ctx) { + true => OraclePriceActiveNext { + amount: aggregated_price[0].aggregated.amount.clone(), + weightage: aggregated_price[0].aggregated.weightage, + oracles: OraclePriceActiveNextOracles { + active: aggregated_price[0].aggregated.oracles.active, + total: aggregated_price[0].aggregated.oracles.total, + }, + }, + false => Default::default(), + }; + + let active_price: OraclePriceActiveActive; + + if previous_price.is_empty() { + active_price = OraclePriceActiveActive { + amount: Default::default(), + weightage: Default::default(), + oracles: OraclePriceActiveActiveOracles { + active: Default::default(), + total: Default::default(), + }, + }; + } else if let Some(next) = previous_price.first().map(|price| &price.next) { + active_price = OraclePriceActiveActive { + amount: next.amount.clone(), + weightage: next.weightage, + oracles: OraclePriceActiveActiveOracles { + active: next.oracles.active, + total: next.oracles.total, + }, + }; + } else { + let oracles = OraclePriceActiveActiveOracles { + active: previous_price[0].active.oracles.active, + total: previous_price[0].active.oracles.total, + }; + active_price = OraclePriceActiveActive { + amount: previous_price[0].active.amount.clone(), + weightage: previous_price[0].active.weightage, + oracles, + }; + } + + let oracle_price_active = OraclePriceActive { + id: price_active_id.clone(), + key: oracle_price_key, + sort: hex::encode(ctx.block.height.to_be_bytes()), + active: active_price.clone(), + next: next_price.clone(), + is_live: is_live(Some(active_price), Some(next_price)), + block: ctx.block.clone(), + }; + services + .oracle_price_active + .by_id + .put(&price_active_id, &oracle_price_active)?; + services + .oracle_price_active + .by_key + .put(&oracle_price_active.key, &oracle_price_active.id)?; + } + + Ok(()) + } + fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { + let ticker_id = ( + self.currency_pair.token.clone(), + self.currency_pair.currency.clone(), + context.block.height, + ); + services.oracle_price_active.by_id.delete(&ticker_id)?; + services + .oracle_price_active + .by_key + .delete(&(ticker_id.0, ticker_id.1))?; + Ok(()) + } +} +pub fn aggregated_validate(aggrigated_price: OraclePriceAggregated, context: &Context) -> bool { + let minimum_live_oracles = 2; + if (aggrigated_price.block.time - context.block.time).abs() >= 3600 { + return false; + } + if aggrigated_price.aggregated.oracles.active < minimum_live_oracles { + return false; + } + + if aggrigated_price.aggregated.weightage <= 0 { + return false; + } + + true +} + +pub fn is_live( + active: Option, + next: Option, +) -> bool { + if let (Some(active), Some(next)) = (active, next) { + let active_price = match Decimal::from_str_exact(&active.amount) { + Ok(num) => num, + Err(_) => return false, + }; + + let next_price = match Decimal::from_str_exact(&next.amount) { + Ok(num) => num, + Err(_) => return false, + }; + + if active_price <= Decimal::zero() || next_price <= Decimal::zero() { + return false; + } + + let deviation_threshold = Decimal::new(5, 1); // This represents 0.5 + + let diff = next_price - active_price; + let abs_diff = diff.abs(); + let threshold = active_price * deviation_threshold; + if abs_diff >= threshold { + return false; + } + + true + } else { + false + } +} diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 004fe427d66..6f33867b15b 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -1,4 +1,5 @@ mod auction; +pub mod loan_token; mod masternode; pub mod oracle; pub mod oracle_test; @@ -11,7 +12,6 @@ use std::{sync::Arc, time::Instant}; use ain_dftx::{deserialize, DfTx, Stack}; use defichain_rpc::json::blockchain::{Block, Transaction}; use log::debug; - pub use pool::AGGREGATED_INTERVALS; use crate::{ @@ -121,7 +121,6 @@ pub fn index_block( ) -> Result<()> { debug!("[index_block] Indexing block..."); let start = Instant::now(); - let block_hash = block.hash; let transaction_count = block.tx.len(); let block_ctx = BlockContext { @@ -166,6 +165,7 @@ pub fn index_block( DfTx::UpdateOracle(data) => data.index(services, &ctx)?, DfTx::SetOracleData(data) => data.index(services, &ctx)?, DfTx::PoolSwap(data) => data.index(services, &ctx)?, + DfTx::SetLoanToken(data) => data.index(services, &ctx)?, // DfTx::CompositeSwap(data) => data.index(services, &ctx)?, // DfTx::PlaceAuctionBid(data) => data.index(services, &ctx)?, _ => (), diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index 667893d0d7d..2d2df15c4ec 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -3,7 +3,7 @@ use std::{str::FromStr, sync::Arc, vec}; use ain_dftx::{common::CompactVec, oracles::*}; use bitcoin::Txid; use rust_decimal::{ - prelude::{ToPrimitive, Zero}, + prelude::{FromPrimitive, ToPrimitive, Zero}, Decimal, }; @@ -15,7 +15,7 @@ use crate::{ OraclePriceAggregatedAggregated, OraclePriceAggregatedAggregatedOracles, OraclePriceAggregatedInterval, OraclePriceAggregatedIntervalAggregated, OraclePriceAggregatedIntervalAggregatedOracles, OraclePriceFeed, OracleTokenCurrency, - PriceFeedsItem, + PriceFeedsItem, PriceTicker, }, repository::RepositoryOps, storage::SortOrder, @@ -25,7 +25,6 @@ use crate::{ impl Index for AppointOracle { fn index(self, services: &Arc, ctx: &Context) -> Result<()> { let oracle_id = ctx.tx.txid; - let price_feeds_items: Vec = self .price_feeds .iter() @@ -34,7 +33,6 @@ impl Index for AppointOracle { currency: pair.currency.clone(), }) .collect(); - let oracle = Oracle { id: oracle_id, owner_address: self.script.to_hex_string(), @@ -53,7 +51,7 @@ impl Index for AppointOracle { ), owner_address: self.script.to_hex_string(), weightage: self.weightage, - price_feeds: price_feeds_items, + price_feeds: price_feeds_items.clone(), block: ctx.block.clone(), }; services @@ -64,18 +62,23 @@ impl Index for AppointOracle { .oracle_history .by_key .put(&oracle_history.oracle_id, &oracle_history.id)?; - let prices_feeds = self.price_feeds.as_ref(); + + let prices_feeds = price_feeds_items; for token_currency in prices_feeds { + let id = ( + token_currency.token.clone(), + token_currency.currency.clone(), + oracle_id, + ); + let oracle_token_currency = OracleTokenCurrency { - id: ( - token_currency.token.to_owned(), - token_currency.currency.to_owned(), - oracle_id, - ), + id, key: ( token_currency.token.to_owned(), token_currency.currency.to_owned(), + ctx.block.height, ), + token: token_currency.token.to_owned(), currency: token_currency.currency.to_owned(), oracle_id, @@ -112,6 +115,7 @@ impl Index for AppointOracle { let token_currency_key = ( currency_pair.token.to_owned(), currency_pair.currency.to_owned(), + context.block.height, ); services .oracle_token_currency @@ -129,7 +133,6 @@ impl Index for AppointOracle { impl Index for RemoveOracle { fn index(self, services: &Arc, ctx: &Context) -> Result<()> { let oracle_id = ctx.tx.txid; - //delete for oracle data from oracle services.oracle.by_id.delete(&oracle_id)?; let previous_hsitory = get_previous_oracle_history_list(services, oracle_id); match previous_hsitory { @@ -148,7 +151,7 @@ impl Index for RemoveOracle { Err(err) => { let error_message = format!("Error: remove_oracle: {:?}", err); eprintln!("{}", error_message); - return Err(Error::NotFound(NotFoundKind::Oracle)); + return Err(Error::DBError(ain_db::DBError::Custom(err.into()))); } } } @@ -188,6 +191,7 @@ impl Index for RemoveOracle { key: ( prev_token_currency.token.clone(), prev_token_currency.currency.clone(), + context.block.height, ), token: prev_token_currency.token, currency: prev_token_currency.currency.to_owned(), @@ -240,20 +244,34 @@ impl Index for UpdateOracle { Ok(previous_oracle) => { for oracle in previous_oracle { for price_feed_item in &oracle.price_feeds { - // Assuming `oracle_id` is a field in `data` that you want to use for deletion - let deletion_key = ( + let deletion_id = ( price_feed_item.token.clone(), price_feed_item.currency.clone(), oracle_id, ); - match services.oracle_token_currency.by_id.delete(&deletion_key) { + match services.oracle_token_currency.by_id.delete(&deletion_id) { Ok(_) => { // Successfully deleted } Err(err) => { let error_message = format!("Error:update oracle: {:?}", err); eprintln!("{}", error_message); - return Err(Error::NotFound(NotFoundKind::Oracle)); + return Err(Error::DBError(ain_db::DBError::Custom(err.into()))); + } + } + let deletion_key = ( + price_feed_item.token.clone(), + price_feed_item.currency.clone(), + ctx.block.height, + ); + match services.oracle_token_currency.by_key.delete(&deletion_key) { + Ok(_) => { + // Successfully deleted + } + Err(err) => { + let error_message = format!("Error: update_oracle: {:?}", err); + eprintln!("{}", error_message); + return Err(Error::DBError(ain_db::DBError::Custom(err.into()))); } } } @@ -278,6 +296,7 @@ impl Index for UpdateOracle { key: ( token_currency.token.clone(), token_currency.currency.clone(), + ctx.block.height, ), token: token_currency.token.clone(), currency: token_currency.currency.clone(), @@ -309,7 +328,6 @@ impl Index for UpdateOracle { price_feeds: vec![], block: ctx.block.clone(), }; - //saving value in oracle_history services .oracle_history .by_key @@ -358,7 +376,7 @@ impl Index for UpdateOracle { let error_message = format!("Error updating oracle invalidate: {:?}", err); eprintln!("{}", error_message); - return Err(Error::NotFound(NotFoundKind::Oracle)); + return Err(Error::DBError(ain_db::DBError::Custom(err.into()))); } } } @@ -381,35 +399,156 @@ impl Index for SetOracleData { timestamp: self.timestamp, token_prices: self.token_prices, }; - let feeds = map_price_feeds(vec![&set_oracle_data], vec![context])?; - let mut pairs: Vec<(String, String)> = Vec::new(); - for feed in feeds { - pairs.push((feed.token.clone(), feed.currency.clone())); + let feeds = map_price_feeds(&set_oracle_data, context)?; + let mut pairs: Vec<(String, String, Txid)> = Vec::new(); + for feed in &feeds { + pairs.push((feed.token.clone(), feed.currency.clone(), feed.oracle_id)); services.oracle_price_feed.by_key.put(&feed.key, &feed.id)?; - services.oracle_price_feed.by_id.put(&feed.id, &feed)?; + services.oracle_price_feed.by_id.put(&feed.id, feed)?; } let intervals: Vec = vec![ OracleIntervalSeconds::FifteenMinutes, OracleIntervalSeconds::OneHour, OracleIntervalSeconds::OneDay, ]; - for (token, currency) in pairs.iter() { - let aggregated_value = map_price_aggregated(services, context, token, currency); - if let Ok(Some(value)) = aggregated_value { + for (token, currency, oracle) in pairs.iter() { + let oracle_token_id: (String, String, Txid) = + (token.to_string(), currency.to_string(), *oracle); + let oracle_entries = services + .oracle_token_currency + .by_key + .list( + Some((token.clone(), currency.clone(), u32::zero())), + SortOrder::Ascending, + )? + .filter_map(|item| { + match item { + Ok((_, id)) => { + if id.0 == oracle_token_id.0.clone() + && id.1 == oracle_token_id.1.clone() + { + match services.oracle_token_currency.by_id.get(&id) { + Ok(b) => Some(Ok(b?)), + Err(e) => Some(Err(e)), + } + } else { + None + } + } + Err(e) => Some(Err(e).map_err(|e| e.into())), // Convert DBError to error::Error + } + }) + .collect::>>()?; + + if oracle_entries.is_empty() { + continue; + } + let total_count = oracle_entries.len(); + let mut total = Decimal::zero(); + let mut count = 0; + let mut weightage = 0; + + for oracle in oracle_entries { + if oracle.weightage == 0 { + println!("Skipping oracle with zero weightage: {:?}", oracle); + continue; + } + + let key = ( + oracle.token.to_string(), + oracle.currency.to_string(), + oracle.oracle_id, + ); + let oracle_price_id = services.oracle_price_feed.by_key.get(&key)?; + match oracle_price_id { + Some((token, currency, oracle_id, some_other_id)) => { + let oracle_price = services.oracle_price_feed.by_id.get(&( + token, + currency, + oracle_id, + some_other_id, + ))?; + if let Some(oracle_price) = oracle_price { + if (oracle_price.time - context.block.time as i32) < 3600 { + count += 1; + weightage += oracle.weightage as i32; + let amount = oracle_price.amount; + let weighted_amount = amount * oracle.weightage as i64; + total += Decimal::from(weighted_amount); + } + } + } + None => { + continue; + } + } + } + let result = (total / Decimal::from_i32(weightage).unwrap_or_default()).to_string(); + let amount = format!("{:.8}", result.parse::().unwrap()); + let aggregated_value = Some(OraclePriceAggregated { + id: ( + token.to_string(), + currency.to_string(), + context.block.height, + ), + key: (token.to_string(), currency.to_string()), + sort: format!( + "{}{}", + hex::encode(context.block.median_time.to_be_bytes()), + hex::encode(context.block.height.to_be_bytes()) + ), + token: token.to_string(), + currency: currency.to_string(), + aggregated: OraclePriceAggregatedAggregated { + amount, + weightage, + oracles: OraclePriceAggregatedAggregatedOracles { + active: count, + total: total_count as i32, + }, + }, + block: context.block.clone(), + }); + + if let Some(value) = aggregated_value { let aggreated_id = ( value.token.clone(), value.currency.clone(), value.block.height, ); - let aggreated_key = (value.token.clone(), value.currency.clone()); + let price_ticker_id = (value.token.clone(), value.currency.clone()); + let price_ticker_key = ( + value.aggregated.oracles.total, + value.block.height, + value.token.clone(), + value.currency.clone(), + ); + services .oracle_price_aggregated .by_id .put(&aggreated_id, &value)?; + + let price_ticker = PriceTicker { + id: price_ticker_id, + sort: format!( + "{}{}{}-{}", + hex::encode(value.aggregated.oracles.total.to_be_bytes()), + hex::encode(value.block.height.to_be_bytes()), + value.token.clone(), + value.currency.clone(), + ), + price: value, + }; + services - .oracle_price_aggregated + .price_ticker .by_key - .put(&aggreated_key, &aggreated_id)?; + .put(&price_ticker_key, &price_ticker.id)?; + services + .price_ticker + .by_id + .put(&price_ticker.id, &price_ticker)?; //SetOracleInterval let aggregated = services.oracle_price_aggregated.by_id.get(&( @@ -444,13 +583,14 @@ impl Index for SetOracleData { OracleIntervalSeconds::OneHour, OracleIntervalSeconds::OneDay, ]; - let feeds = map_price_feeds(vec![&set_oracle_data], vec![context])?; + let feeds = map_price_feeds(&set_oracle_data, context)?; let mut pairs: Vec<(String, String)> = Vec::new(); for feed in feeds { pairs.push((feed.token.clone(), feed.currency.clone())); - services.oracle_price_feed.by_key.delete(&feed.key)?; services.oracle_price_feed.by_id.delete(&feed.id)?; + services.oracle_price_feed.by_key.delete(&feed.key)?; } + for (token, currency) in pairs.iter() { let aggreated_id = (token.to_owned(), currency.to_owned(), context.block.height); let aggregated_price = services.oracle_price_aggregated.by_id.get(&aggreated_id)?; @@ -475,136 +615,38 @@ impl Index for SetOracleData { } } -pub fn map_price_aggregated( - services: &Arc, - ctx: &Context, - token: &str, - currency: &str, -) -> Result> { - let key = (token.to_string(), currency.to_string()); - let oracle_token_currency = services - .oracle_token_currency - .by_key - .list(Some(key), SortOrder::Descending)? - .map(|item| { - let (_, id) = item?; - let b = services - .oracle_token_currency - .by_id - .get(&id)? - .ok_or("Error mapping price aggregated index")?; - - Ok(b) - }) - .collect::>>()?; - - let result = oracle_token_currency; - let mut aggregated = OraclePriceAggregatedAggregated { - amount: "0".to_string(), - weightage: 0, - oracles: OraclePriceAggregatedAggregatedOracles { - active: 0, - total: 0, - }, - }; - - for oracle in result { - if oracle.weightage == 0 { - continue; - } - - let key = (token.to_string(), currency.to_string(), oracle.oracle_id); - let feed_id = services.oracle_price_feed.by_key.get(&key); - - let feeds = match feed_id { - Ok(feed_ids) => { - feed_ids.map_or_else(|| Ok(None), |id| services.oracle_price_feed.by_id.get(&id)) - } - Err(err) => { - println!("the err {:?}", err); - Err(err) - } - }; - - let oracle_price_feed: Option = match feeds { - Ok(Some(feed)) => Some(feed), - _ => None, - }; - - if oracle_price_feed.is_none() { - continue; - } - - if let Some(oracle_price_feed) = oracle_price_feed { - if (oracle_price_feed.time - ctx.block.time as i32) < 3600 { - aggregated.oracles.active += 1; - aggregated.weightage += oracle.weightage as i32; - let amount = oracle_price_feed.amount; - let weighted_amount = amount * oracle.weightage as i64; - if let Ok(current_amount) = aggregated.amount.parse::() { - aggregated.amount = (current_amount + weighted_amount).to_string(); - } - } - } else { - continue; - } - } - - if aggregated.oracles.active == 0 { - return Ok(None); - }; - - Ok(Some(OraclePriceAggregated { - id: (token.to_string(), currency.to_string(), ctx.block.height), - key: (token.to_string(), currency.to_string()), - sort: format!( - "{}{}", - hex::encode(ctx.block.median_time.to_be_bytes()), - hex::encode(ctx.block.height.to_be_bytes()) - ), - token: token.to_string(), - currency: currency.to_string(), - aggregated, - block: ctx.block.clone(), - })) -} - -pub fn map_price_feeds( - set_oracle_data: Vec<&SetOracleData>, - context: Vec<&Context>, +fn map_price_feeds( + set_oracle_data: &SetOracleData, + context: &Context, ) -> Result> { let mut result: Vec = Vec::new(); - for (idx, ctx) in context.into_iter().enumerate() { - // Use indexing to access elements in set_oracle_data - let set_data = set_oracle_data[idx]; - let token_prices = set_data.token_prices.as_ref(); - for token_price in token_prices { - for token_amount in token_price.prices.as_ref() { - let oracle_price_feed = OraclePriceFeed { - id: ( - token_price.token.clone(), - token_amount.currency.clone(), - set_data.oracle_id, - ctx.tx.txid, - ), - - key: ( - token_price.token.clone(), - token_amount.currency.clone(), - set_data.oracle_id, - ), - sort: hex::encode(ctx.block.height.to_string() + &ctx.tx.txid.to_string()), - amount: token_amount.amount, - currency: token_amount.currency.clone(), - block: ctx.block.clone(), - oracle_id: set_data.oracle_id, - time: set_data.timestamp as i32, - token: token_price.token.clone(), - txid: ctx.tx.txid, - }; + let token_prices = set_oracle_data.token_prices.as_ref(); + for token_price in token_prices { + for token_amount in token_price.prices.as_ref() { + let token = token_price.token.clone(); + let currency = token_amount.currency.clone(); + let id = ( + token.clone(), + currency.clone(), + set_oracle_data.oracle_id, + context.tx.txid, + ); - result.push(oracle_price_feed); - } + let key = (token.clone(), currency.clone(), set_oracle_data.oracle_id); + + let oracle_price_feed = OraclePriceFeed { + id: id.clone(), + key, + sort: hex::encode(context.block.height.to_string() + &context.tx.txid.to_string()), + amount: token_amount.amount, + currency: currency.clone(), + block: context.block.clone(), + oracle_id: set_oracle_data.oracle_id, + time: set_oracle_data.timestamp as i32, + token, + txid: context.tx.txid, + }; + result.push(oracle_price_feed); } } Ok(result) @@ -623,7 +665,7 @@ pub fn index_interval_mapper( .by_key .list( Some((token.to_owned(), currency.to_owned(), interval.clone())), - SortOrder::Descending, + SortOrder::Ascending, )? .take(1) .map(|item| { @@ -638,7 +680,10 @@ pub fn index_interval_mapper( .collect::>>(); if let Ok(previous_oracle_price_aggreated) = previous_aggrigated_interval { - if previous_oracle_price_aggreated.is_empty() { + if previous_oracle_price_aggreated.is_empty() + || (block.median_time - previous_oracle_price_aggreated[0].block.median_time + > interval.clone() as i64) + { let oracle_price_aggregated_interval = OraclePriceAggregatedInterval { id: ( token.to_owned(), diff --git a/lib/ain-ocean/src/indexer/oracle_test.rs b/lib/ain-ocean/src/indexer/oracle_test.rs index 6f1afc9fd87..57cf171015d 100644 --- a/lib/ain-ocean/src/indexer/oracle_test.rs +++ b/lib/ain-ocean/src/indexer/oracle_test.rs @@ -2,18 +2,1002 @@ mod tests { use std::{str::FromStr, sync::Arc}; - use ain_dftx::{common::CompactVec, price::CurrencyPair, types::oracles::AppointOracle}; + use ain_dftx::{ + common::CompactVec, + oracles::SetOracleData, + price::{CurrencyPair, TokenAmount, TokenPrice}, + types::oracles::AppointOracle, + }; use bitcoin::{BlockHash, ScriptBuf, Txid}; use defichain_rpc::json::blockchain::Transaction; use tempfile::tempdir; use crate::{ indexer::{Context, Index}, - model::BlockContext, - storage::ocean_store, + model::{BlockContext, Oracle, OraclePriceFeed, OracleTokenCurrency, PriceFeedsItem}, + repository::RepositoryOps, + storage::{ocean_store, SortOrder}, Services, }; + #[test] + fn test_save_and_retrieve_oracle() { + // Setup the temporary storage for testing + let temp_dir = tempdir().expect("Failed to create temporary directory"); + let path = temp_dir.path(); + let ocean_store_result = ocean_store::OceanStore::new(path); + let ocean_store = match ocean_store_result { + Ok(store) => Arc::new(store), + Err(error) => panic!("Failed to create OceanStore: {}", error), + }; + + let services = Arc::new(Services::new(ocean_store)); + + // Create an example Oracle instance + let oracle = Oracle { + id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5") + .unwrap(), + owner_address: "a9149cd82492b8fadde74486ecebdb497934492b061187".to_string(), + weightage: 1, + price_feeds: vec![ + PriceFeedsItem { + token: "TA".to_string(), + currency: "USD".to_string(), + }, + PriceFeedsItem { + token: "TB".to_string(), + currency: "USD".to_string(), + }, + PriceFeedsItem { + token: "TC".to_string(), + currency: "USD".to_string(), + }, + PriceFeedsItem { + token: "TD".to_string(), + currency: "USD".to_string(), + }, + ], + block: BlockContext { + hash: BlockHash::from_str( + "84ac36b14a377fa47ed062e06fe949c448b34e543a98d6a00b8738e9d1cd27f1", + ) + .unwrap(), + height: 121, + time: 1714980074, + median_time: 1714980074, + }, + }; + + // Save the oracle to the ocean db + services + .oracle + .by_id + .put(&oracle.id, &oracle) + .expect("Failed to save oracle"); + // Retrieve the oracle from the system + let retrieved_oracle = services + .oracle + .by_id + .get(&oracle.id) + .expect("Failed to retrieve oracle") + .expect("Oracle not found"); + // Assert that the retrieved oracle matches the saved oracle + assert_eq!( + oracle.id, retrieved_oracle.id, + "Retrieved oracle does not match saved oracle" + ); + } + + #[test] + fn test_save_and_retrieve_oracle_price_feed() { + // Setup the temporary storage for testing + let temp_dir = tempdir().expect("Failed to create temporary directory"); + let path = temp_dir.path(); + let ocean_store_result = ocean_store::OceanStore::new(path); + let ocean_store = match ocean_store_result { + Ok(store) => Arc::new(store), + Err(error) => panic!("Failed to create OceanStore: {}", error), + }; + let services = Arc::new(Services::new(ocean_store)); + let feeds = vec![ + OraclePriceFeed { + id: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap()), + key: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323464366639356634323366303963663033663137626264633961653033666361366433613261656462633565303631356137613264323762663835616537633239".to_string(), + token: "TA".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980187, + amount: 110000000, + block: BlockContext { + hash: BlockHash::from_str("175b254878fba4ec32b9de754330b4cc6c577d1999439ffa37e6348109c779fb").unwrap(), + height: 124, + time: 1714980187, + median_time: 1714980136, + } + }, + OraclePriceFeed { + id: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap()), + key: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323464366639356634323366303963663033663137626264633961653033666361366433613261656462633565303631356137613264323762663835616537633239".to_string(), + token: "TB".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980187, + amount: 210000000, + block: BlockContext { + hash: BlockHash::from_str("175b254878fba4ec32b9de754330b4cc6c577d1999439ffa37e6348109c779fb").unwrap(), + height: 124, + time: 1714980187, + median_time: 1714980136, + } + }, + OraclePriceFeed { + id: ("TC".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap()), + key: ("TC".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323464366639356634323366303963663033663137626264633961653033666361366433613261656462633565303631356137613264323762663835616537633239".to_string(), + token: "TC".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980187, + amount: 310000000, + block: BlockContext { + hash: BlockHash::from_str("175b254878fba4ec32b9de754330b4cc6c577d1999439ffa37e6348109c779fb").unwrap(), + height: 124, + time: 1714980187, + median_time: 1714980136, + } + }, + OraclePriceFeed { + id: ("TD".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap()), + key: ("TD".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323464366639356634323366303963663033663137626264633961653033666361366433613261656462633565303631356137613264323762663835616537633239".to_string(), + token: "TD".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980187, + amount: 410000000, + block: BlockContext { + hash: BlockHash::from_str("175b254878fba4ec32b9de754330b4cc6c577d1999439ffa37e6348109c779fb").unwrap(), + height: 124, + time: 1714980187, + median_time: 1714980136, + } + }, + ]; + // Save each OraclePriceFeed to the system + for feed in &feeds { + services + .oracle_price_feed + .by_id + .put(&feed.id, feed) + .expect("Failed to save OraclePriceFeed"); + } + let retrieve_key_list = services + .oracle_price_feed + .by_id + .list(None, SortOrder::Descending) + .expect("Failed to retrieve oracle_price_feed_key list") + .map(|res| res.expect("Error retrieving key")) + .collect::>(); + + // Check if the retrieved feed ID matches the expected format + for (_, feed) in &retrieve_key_list { + let (token, currency, oracle_id, _) = &feed.id; + if token.eq(&feeds[0].token) + && currency.eq(&feeds[0].currency) + && oracle_id.eq(&feeds[0].oracle_id) + { + println!("Found matching feed: {:?}", feed); + } + } + assert!( + !retrieve_key_list.is_empty(), + "The filtered list should not be empty" + ); + } + + #[test] + fn test_save_and_retrieve_multiple_oracle_price_feed() { + // Setup the temporary storage for testing + let temp_dir = tempdir().expect("Failed to create temporary directory"); + let path = temp_dir.path(); + let ocean_store_result = ocean_store::OceanStore::new(path); + let ocean_store = match ocean_store_result { + Ok(store) => Arc::new(store), + Err(error) => panic!("Failed to create OceanStore: {}", error), + }; + let services = Arc::new(Services::new(ocean_store)); + let feeds = vec![ + OraclePriceFeed { + id: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap()), + key: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323464366639356634323366303963663033663137626264633961653033666361366433613261656462633565303631356137613264323762663835616537633239".to_string(), + token: "TA".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980187, + amount: 110000000, + block: BlockContext { + hash: BlockHash::from_str("175b254878fba4ec32b9de754330b4cc6c577d1999439ffa37e6348109c779fb").unwrap(), + height: 124, + time: 1714980187, + median_time: 1714980136, + } + }, + OraclePriceFeed { + id: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap()), + key: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323464366639356634323366303963663033663137626264633961653033666361366433613261656462633565303631356137613264323762663835616537633239".to_string(), + token: "TB".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980187, + amount: 210000000, + block: BlockContext { + hash: BlockHash::from_str("175b254878fba4ec32b9de754330b4cc6c577d1999439ffa37e6348109c779fb").unwrap(), + height: 124, + time: 1714980187, + median_time: 1714980136, + } + }, + OraclePriceFeed { + id: ("TC".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap()), + key: ("TC".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323464366639356634323366303963663033663137626264633961653033666361366433613261656462633565303631356137613264323762663835616537633239".to_string(), + token: "TC".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980187, + amount: 310000000, + block: BlockContext { + hash: BlockHash::from_str("175b254878fba4ec32b9de754330b4cc6c577d1999439ffa37e6348109c779fb").unwrap(), + height: 124, + time: 1714980187, + median_time: 1714980136, + } + }, + OraclePriceFeed { + id: ("TD".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap()), + key: ("TD".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323464366639356634323366303963663033663137626264633961653033666361366433613261656462633565303631356137613264323762663835616537633239".to_string(), + token: "TD".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980187, + amount: 410000000, + block: BlockContext { + hash: BlockHash::from_str("175b254878fba4ec32b9de754330b4cc6c577d1999439ffa37e6348109c779fb").unwrap(), + height: 124, + time: 1714980187, + median_time: 1714980136, + } + }, + ]; + + let feeds_1 = vec![ + OraclePriceFeed { + id: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("94e0883205b425de5b5dd52a208f4cd1f3d7e09d066b0fd091b9bc7513b33a34").unwrap()), + key: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323539346530383833323035623432356465356235646435326132303866346364316633643765303964303636623066643039316239626337353133623333613334".to_string(), + token: "TA".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980243, + amount: 100000000, + block: BlockContext { + hash: BlockHash::from_str("a93730388be038ac52d1f0ed869877a5b0189bb786a9809c0205a45d98b0d948").unwrap(), + height: 125, + time: 1714980243, + median_time: 1714980167, + } + }, + OraclePriceFeed { + id: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("94e0883205b425de5b5dd52a208f4cd1f3d7e09d066b0fd091b9bc7513b33a34").unwrap()), + key: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323539346530383833323035623432356465356235646435326132303866346364316633643765303964303636623066643039316239626337353133623333613334".to_string(), + token: "TB".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980243, + amount: 200000000, + block: BlockContext { + hash: BlockHash::from_str("a93730388be038ac52d1f0ed869877a5b0189bb786a9809c0205a45d98b0d948").unwrap(), + height: 125, + time: 1714980243, + median_time: 1714980167, + } + }, + OraclePriceFeed { + id: ("TC".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("94e0883205b425de5b5dd52a208f4cd1f3d7e09d066b0fd091b9bc7513b33a34").unwrap()), + key: ("TC".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323539346530383833323035623432356465356235646435326132303866346364316633643765303964303636623066643039316239626337353133623333613334".to_string(), + token: "TC".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980243, + amount: 300000000, + block: BlockContext { + hash: BlockHash::from_str("a93730388be038ac52d1f0ed869877a5b0189bb786a9809c0205a45d98b0d948").unwrap(), + height: 125, + time: 1714980243, + median_time: 1714980167, + } + }, + ]; + + let feeds_2 = vec![ + OraclePriceFeed { + id: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("574b3c7ef4cc572618a639c568b6b4dee0f6c99da9057e7756e9b3b338feae7c").unwrap()), + key: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323635373462336337656634636335373236313861363339633536386236623464656530663663393964613930353765373735366539623362333338666561653763".to_string(), + token: "TA".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980270, + amount: 100000000, + block: BlockContext { + hash: BlockHash::from_str("134894c63b9469a18f2ab314b10012baf658a122cae877d62cfbbfae3ab64ec2").unwrap(), + height: 126, + time: 1714980270, + median_time: 1714980187, + } + }, + OraclePriceFeed { + id: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("574b3c7ef4cc572618a639c568b6b4dee0f6c99da9057e7756e9b3b338feae7c").unwrap()), + key: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323635373462336337656634636335373236313861363339633536386236623464656530663663393964613930353765373735366539623362333338666561653763".to_string(), + token: "TB".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980270, + amount: 200000000, + block: BlockContext { + hash: BlockHash::from_str("134894c63b9469a18f2ab314b10012baf658a122cae877d62cfbbfae3ab64ec2").unwrap(), + height: 126, + time: 1714980270, + median_time: 1714980187, + } + }, + ]; + + for feed in &feeds { + services + .oracle_price_feed + .by_id + .put(&feed.id, feed) + .expect("Failed to save OraclePriceFeed"); + } + + for feed_1 in &feeds_1 { + services + .oracle_price_feed + .by_id + .put(&feed_1.id, feed_1) + .expect("Failed to save OraclePriceFeed"); + } + + for feed_2 in &feeds_2 { + services + .oracle_price_feed + .by_id + .put(&feed_2.id, feed_2) + .expect("Failed to save OraclePriceFeed"); + } + + let price_feed_list = services + .oracle_price_feed + .by_id + .list(None, SortOrder::Descending) + .expect("Failed to retrieve oracle_price_feed_key list") + .map(|res| res.expect("Error retrieving key")) + .collect::>(); + + for (_, feed) in &price_feed_list { + let (token, currency, oracle_id, _) = &feed.id; + if token.eq(&feeds[1].token) + && currency.eq(&feeds[1].currency) + && oracle_id.eq(&feeds[1].oracle_id) + { + println!("Found matching feed: {:?}", feed); + } + } + assert!( + !price_feed_list.is_empty(), + "The filtered list should not be empty" + ); + } + + #[test] + fn test_get_oracle_price_feed_list() { + // Setup the temporary storage for testing + let temp_dir = tempdir().expect("Failed to create temporary directory"); + let path = temp_dir.path(); + let ocean_store_result = ocean_store::OceanStore::new(path); + let ocean_store = match ocean_store_result { + Ok(store) => Arc::new(store), + Err(error) => panic!("Failed to create OceanStore: {}", error), + }; + let services = Arc::new(Services::new(ocean_store)); + let feeds = vec![ + OraclePriceFeed { + id: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap()), + key: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323464366639356634323366303963663033663137626264633961653033666361366433613261656462633565303631356137613264323762663835616537633239".to_string(), + token: "TA".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980187, + amount: 110000000, + block: BlockContext { + hash: BlockHash::from_str("175b254878fba4ec32b9de754330b4cc6c577d1999439ffa37e6348109c779fb").unwrap(), + height: 124, + time: 1714980187, + median_time: 1714980136, + } + }, + OraclePriceFeed { + id: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap()), + key: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323464366639356634323366303963663033663137626264633961653033666361366433613261656462633565303631356137613264323762663835616537633239".to_string(), + token: "TB".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980187, + amount: 210000000, + block: BlockContext { + hash: BlockHash::from_str("175b254878fba4ec32b9de754330b4cc6c577d1999439ffa37e6348109c779fb").unwrap(), + height: 124, + time: 1714980187, + median_time: 1714980136, + } + }, + OraclePriceFeed { + id: ("TC".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap()), + key: ("TC".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323464366639356634323366303963663033663137626264633961653033666361366433613261656462633565303631356137613264323762663835616537633239".to_string(), + token: "TC".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980187, + amount: 310000000, + block: BlockContext { + hash: BlockHash::from_str("175b254878fba4ec32b9de754330b4cc6c577d1999439ffa37e6348109c779fb").unwrap(), + height: 124, + time: 1714980187, + median_time: 1714980136, + } + }, + OraclePriceFeed { + id: ("TD".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap()), + key: ("TD".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323464366639356634323366303963663033663137626264633961653033666361366433613261656462633565303631356137613264323762663835616537633239".to_string(), + token: "TD".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980187, + amount: 410000000, + block: BlockContext { + hash: BlockHash::from_str("175b254878fba4ec32b9de754330b4cc6c577d1999439ffa37e6348109c779fb").unwrap(), + height: 124, + time: 1714980187, + median_time: 1714980136, + } + }, + ]; + + let feeds_1 = vec![ + OraclePriceFeed { + id: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("94e0883205b425de5b5dd52a208f4cd1f3d7e09d066b0fd091b9bc7513b33a34").unwrap()), + key: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323539346530383833323035623432356465356235646435326132303866346364316633643765303964303636623066643039316239626337353133623333613334".to_string(), + token: "TA".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980243, + amount: 100000000, + block: BlockContext { + hash: BlockHash::from_str("a93730388be038ac52d1f0ed869877a5b0189bb786a9809c0205a45d98b0d948").unwrap(), + height: 125, + time: 1714980243, + median_time: 1714980167, + } + }, + OraclePriceFeed { + id: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("94e0883205b425de5b5dd52a208f4cd1f3d7e09d066b0fd091b9bc7513b33a34").unwrap()), + key: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323539346530383833323035623432356465356235646435326132303866346364316633643765303964303636623066643039316239626337353133623333613334".to_string(), + token: "TB".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980243, + amount: 200000000, + block: BlockContext { + hash: BlockHash::from_str("a93730388be038ac52d1f0ed869877a5b0189bb786a9809c0205a45d98b0d948").unwrap(), + height: 125, + time: 1714980243, + median_time: 1714980167, + } + }, + OraclePriceFeed { + id: ("TC".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("94e0883205b425de5b5dd52a208f4cd1f3d7e09d066b0fd091b9bc7513b33a34").unwrap()), + key: ("TC".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323539346530383833323035623432356465356235646435326132303866346364316633643765303964303636623066643039316239626337353133623333613334".to_string(), + token: "TC".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980243, + amount: 300000000, + block: BlockContext { + hash: BlockHash::from_str("a93730388be038ac52d1f0ed869877a5b0189bb786a9809c0205a45d98b0d948").unwrap(), + height: 125, + time: 1714980243, + median_time: 1714980167, + } + }, + ]; + + let feeds_2 = vec![ + OraclePriceFeed { + id: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("574b3c7ef4cc572618a639c568b6b4dee0f6c99da9057e7756e9b3b338feae7c").unwrap()), + key: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323635373462336337656634636335373236313861363339633536386236623464656530663663393964613930353765373735366539623362333338666561653763".to_string(), + token: "TA".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980270, + amount: 100000000, + block: BlockContext { + hash: BlockHash::from_str("134894c63b9469a18f2ab314b10012baf658a122cae877d62cfbbfae3ab64ec2").unwrap(), + height: 126, + time: 1714980270, + median_time: 1714980187, + } + }, + OraclePriceFeed { + id: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("574b3c7ef4cc572618a639c568b6b4dee0f6c99da9057e7756e9b3b338feae7c").unwrap()), + key: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323635373462336337656634636335373236313861363339633536386236623464656530663663393964613930353765373735366539623362333338666561653763".to_string(), + token: "TB".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980270, + amount: 200000000, + block: BlockContext { + hash: BlockHash::from_str("134894c63b9469a18f2ab314b10012baf658a122cae877d62cfbbfae3ab64ec2").unwrap(), + height: 126, + time: 1714980270, + median_time: 1714980187, + } + }, + ]; + + for feed in &feeds { + services + .oracle_price_feed + .by_id + .put(&feed.id, feed) + .expect("Failed to save OraclePriceFeed"); + } + + for feed_1 in &feeds_1 { + services + .oracle_price_feed + .by_id + .put(&feed_1.id, feed_1) + .expect("Failed to save OraclePriceFeed"); + } + + for feed_2 in &feeds_2 { + services + .oracle_price_feed + .by_id + .put(&feed_2.id, feed_2) + .expect("Failed to save OraclePriceFeed"); + } + + let price_feed_list = services + .oracle_price_feed + .by_id + .list(None, SortOrder::Descending) + .expect("Failed to retrieve oracle_price_feed_key list") + .map(|res| res.expect("Error retrieving key")) + .collect::>(); + + for (_, feed) in &price_feed_list { + let (token, currency, oracle_id, _) = &feed.id; + if token.eq(&feeds[1].token) + && currency.eq(&feeds[1].currency) + && oracle_id.eq(&feeds[1].oracle_id) + { + println!("Found matching feed: {:?}", feed); + } + } + assert!( + !price_feed_list.is_empty(), + "The filtered list should not be empty" + ); + } + + #[test] + fn test_index_set_oracle_oracle() { + let temp_dir = tempdir().expect("Failed to create temporary directory"); + let path = temp_dir.path(); + let ocean_store_result = ocean_store::OceanStore::new(path); + let ocean_store = match ocean_store_result { + Ok(ocean_store) => Arc::new(ocean_store), + Err(error) => { + panic!("Failed to create OceanStore: {}", error); + } + }; + + let feeds = vec![ + OraclePriceFeed { + id: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap()), + key: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323464366639356634323366303963663033663137626264633961653033666361366433613261656462633565303631356137613264323762663835616537633239".to_string(), + token: "TA".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980187, + amount: 110000000, + block: BlockContext { + hash: BlockHash::from_str("175b254878fba4ec32b9de754330b4cc6c577d1999439ffa37e6348109c779fb").unwrap(), + height: 124, + time: 1714980187, + median_time: 1714980136, + } + }, + OraclePriceFeed { + id: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap()), + key: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323464366639356634323366303963663033663137626264633961653033666361366433613261656462633565303631356137613264323762663835616537633239".to_string(), + token: "TB".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980187, + amount: 210000000, + block: BlockContext { + hash: BlockHash::from_str("175b254878fba4ec32b9de754330b4cc6c577d1999439ffa37e6348109c779fb").unwrap(), + height: 124, + time: 1714980187, + median_time: 1714980136, + } + }, + OraclePriceFeed { + id: ("TC".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap()), + key: ("TC".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323464366639356634323366303963663033663137626264633961653033666361366433613261656462633565303631356137613264323762663835616537633239".to_string(), + token: "TC".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980187, + amount: 310000000, + block: BlockContext { + hash: BlockHash::from_str("175b254878fba4ec32b9de754330b4cc6c577d1999439ffa37e6348109c779fb").unwrap(), + height: 124, + time: 1714980187, + median_time: 1714980136, + } + }, + OraclePriceFeed { + id: ("TD".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap()), + key: ("TD".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323464366639356634323366303963663033663137626264633961653033666361366433613261656462633565303631356137613264323762663835616537633239".to_string(), + token: "TD".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980187, + amount: 410000000, + block: BlockContext { + hash: BlockHash::from_str("175b254878fba4ec32b9de754330b4cc6c577d1999439ffa37e6348109c779fb").unwrap(), + height: 124, + time: 1714980187, + median_time: 1714980136, + } + }, + ]; + + let _feeds_1 = vec![ + OraclePriceFeed { + id: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("94e0883205b425de5b5dd52a208f4cd1f3d7e09d066b0fd091b9bc7513b33a34").unwrap()), + key: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323539346530383833323035623432356465356235646435326132303866346364316633643765303964303636623066643039316239626337353133623333613334".to_string(), + token: "TA".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980243, + amount: 100000000, + block: BlockContext { + hash: BlockHash::from_str("a93730388be038ac52d1f0ed869877a5b0189bb786a9809c0205a45d98b0d948").unwrap(), + height: 125, + time: 1714980243, + median_time: 1714980167, + } + }, + OraclePriceFeed { + id: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("94e0883205b425de5b5dd52a208f4cd1f3d7e09d066b0fd091b9bc7513b33a34").unwrap()), + key: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323539346530383833323035623432356465356235646435326132303866346364316633643765303964303636623066643039316239626337353133623333613334".to_string(), + token: "TB".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980243, + amount: 200000000, + block: BlockContext { + hash: BlockHash::from_str("a93730388be038ac52d1f0ed869877a5b0189bb786a9809c0205a45d98b0d948").unwrap(), + height: 125, + time: 1714980243, + median_time: 1714980167, + } + }, + OraclePriceFeed { + id: ("TC".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("94e0883205b425de5b5dd52a208f4cd1f3d7e09d066b0fd091b9bc7513b33a34").unwrap()), + key: ("TC".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323539346530383833323035623432356465356235646435326132303866346364316633643765303964303636623066643039316239626337353133623333613334".to_string(), + token: "TC".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980243, + amount: 300000000, + block: BlockContext { + hash: BlockHash::from_str("a93730388be038ac52d1f0ed869877a5b0189bb786a9809c0205a45d98b0d948").unwrap(), + height: 125, + time: 1714980243, + median_time: 1714980167, + } + }, + ]; + + let _feeds_2 = vec![ + OraclePriceFeed { + id: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("574b3c7ef4cc572618a639c568b6b4dee0f6c99da9057e7756e9b3b338feae7c").unwrap()), + key: ("TA".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323635373462336337656634636335373236313861363339633536386236623464656530663663393964613930353765373735366539623362333338666561653763".to_string(), + token: "TA".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980270, + amount: 120000000, + block: BlockContext { + hash: BlockHash::from_str("134894c63b9469a18f2ab314b10012baf658a122cae877d62cfbbfae3ab64ec2").unwrap(), + height: 126, + time: 1714980270, + median_time: 1714980187, + } + }, + OraclePriceFeed { + id: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), Txid::from_str("574b3c7ef4cc572618a639c568b6b4dee0f6c99da9057e7756e9b3b338feae7c").unwrap()), + key: ("TB".to_string(), "USD".to_string(), Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap()), + sort: "31323635373462336337656634636335373236313861363339633536386236623464656530663663393964613930353765373735366539623362333338666561653763".to_string(), + token: "TB".to_string(), + currency: "USD".to_string(), + oracle_id: Txid::from_str("33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5").unwrap(), + txid: Txid::from_str("d6f95f423f09cf03f17bbdc9ae03fca6d3a2aedbc5e0615a7a2d27bf85ae7c29").unwrap(), + time: 1714980270, + amount: 200000000, + block: BlockContext { + hash: BlockHash::from_str("134894c63b9469a18f2ab314b10012baf658a122cae877d62cfbbfae3ab64ec2").unwrap(), + height: 126, + time: 1714980270, + median_time: 1714980187, + } + }, + ]; + + let services = Arc::new(Services::new(ocean_store)); + for feed in feeds { + let oracle_token_currency = OracleTokenCurrency { + id: feed.key, + key: (feed.token.to_owned(), feed.currency.to_owned(), 0), + + token: feed.token.to_owned(), + currency: feed.currency.to_owned(), + oracle_id: feed.oracle_id, + weightage: 1, + block: feed.block.clone(), + }; + + services + .oracle_token_currency + .by_id + .put(&oracle_token_currency.id, &oracle_token_currency) + .expect("Failed to save oracle_token_currency"); + + let block_context = BlockContext { + hash: feed.block.hash, + height: feed.block.height, + time: feed.block.time, + median_time: feed.block.median_time, + }; + + let transaction = Transaction { + txid: feed.txid, + hash: feed.block.hash.to_string(), + version: 1, + size: 100, + vsize: 90, + weight: 80, + locktime: 0, + vin: vec![], + vout: vec![], + hex: "transaction_hex".to_string(), + }; + + let set_oracle = SetOracleData { + oracle_id: feed.oracle_id, + timestamp: feed.time as i64, + token_prices: vec![TokenPrice { + token: feed.token, + prices: vec![TokenAmount { + currency: feed.currency, + amount: feed.amount, + }] + .into(), + }] + .into(), + }; + let ctx = &Context { + block: block_context, + tx: transaction, + tx_idx: 2, + }; + let _result = set_oracle.index(&services, ctx); + } + + // for feed_1 in feeds_1 { + // let oracle_token_currency = OracleTokenCurrency { + // id: feed_1.key, + // key: (feed_1.token.to_owned(), feed_1.currency.to_owned()), + + // token: feed_1.token.to_owned(), + // currency: feed_1.currency.to_owned(), + // oracle_id: feed_1.oracle_id, + // weightage: 1, + // block: feed_1.block.clone(), + // }; + + // services + // .oracle_token_currency + // .by_id + // .put(&oracle_token_currency.id, &oracle_token_currency) + // .expect("Failed to save oracle_token_currency"); + + // let block_context = BlockContext { + // hash: feed_1.block.hash, + // height: feed_1.block.height, + // time: feed_1.block.time, + // median_time: feed_1.block.median_time, + // }; + + // let transaction = Transaction { + // txid: feed_1.txid, + // hash: feed_1.block.hash.to_string(), + // version: 1, + // size: 100, + // vsize: 90, + // weight: 80, + // locktime: 0, + // vin: vec![], + // vout: vec![], + // hex: "transaction_hex".to_string(), + // }; + + // let set_oracle = SetOracleData { + // oracle_id: feed_1.oracle_id, + // timestamp: feed_1.time as i64, + // token_prices: vec![TokenPrice { + // token: feed_1.token, + // prices: vec![TokenAmount { + // currency: feed_1.currency, + // amount: feed_1.amount, + // }] + // .into(), + // }] + // .into(), + // }; + // let ctx = &Context { + // block: block_context, + // tx: transaction, + // tx_idx: 2, + // }; + // let result = set_oracle.index(&services, ctx); + // } + // for feed_2 in feeds_2 { + // let oracle_token_currency = OracleTokenCurrency { + // id: feed_2.key, + // key: (feed_2.token.to_owned(), feed_2.currency.to_owned()), + + // token: feed_2.token.to_owned(), + // currency: feed_2.currency.to_owned(), + // oracle_id: feed_2.oracle_id, + // weightage: 1, + // block: feed_2.block.clone(), + // }; + + // services + // .oracle_token_currency + // .by_id + // .put(&oracle_token_currency.id, &oracle_token_currency) + // .expect("Failed to save oracle_token_currency"); + + // let block_context = BlockContext { + // hash: feed_2.block.hash, + // height: feed_2.block.height, + // time: feed_2.block.time, + // median_time: feed_2.block.median_time, + // }; + + // let transaction = Transaction { + // txid: feed_2.txid, + // hash: feed_2.block.hash.to_string(), + // version: 1, + // size: 100, + // vsize: 90, + // weight: 80, + // locktime: 0, + // vin: vec![], + // vout: vec![], + // hex: "transaction_hex".to_string(), + // }; + + // let set_oracle: SetOracleData = SetOracleData { + // oracle_id: feed_2.oracle_id, + // timestamp: feed_2.time as i64, + // token_prices: vec![TokenPrice { + // token: feed_2.token, + // prices: vec![TokenAmount { + // currency: feed_2.currency, + // amount: feed_2.amount, + // }] + // .into(), + // }] + // .into(), + // }; + // let ctx = &Context { + // block: block_context, + // tx: transaction, + // tx_idx: 2, + // }; + // let result = set_oracle.index(&services, ctx); + // } + let result = services + .price_ticker + .by_id + .get(&("TA".to_string(), "USD".to_string())); + println!("{:?}", result); + } + #[test] fn test_index_appoint_oracle() { let temp_dir = tempdir().expect("Failed to create temporary directory"); @@ -28,6 +1012,43 @@ mod tests { let services = Arc::new(Services::new(ocean_store)); + let oracle = Oracle { + id: Txid::from_str( + "0x33f23658be827bd0f23a48c8db205fcf275dcf666d63cbd3e06089decea217d5", + ) + .unwrap(), + owner_address: "a9149cd82492b8fadde74486ecebdb497934492b061187".to_string(), + weightage: 1, + price_feeds: vec![ + PriceFeedsItem { + token: "TA".to_string(), + currency: "USD".to_string(), + }, + PriceFeedsItem { + token: "TB".to_string(), + currency: "USD".to_string(), + }, + PriceFeedsItem { + token: "TC".to_string(), + currency: "USD".to_string(), + }, + PriceFeedsItem { + token: "TD".to_string(), + currency: "USD".to_string(), + }, + ], + block: BlockContext { + hash: BlockHash::from_str( + "0x84ac36b14a377fa47ed062e06fe949c448b34e543a98d6a00b8738e9d1cd27f1", + ) + .unwrap(), + height: 121, + time: 1714980074, + median_time: 1714980074, + }, + }; + services.oracle.by_id.put(&oracle.id, &oracle).unwrap(); + let block_context = BlockContext { hash: BlockHash::from_str( "0000000000000000000076b72aeedd65368d07d945a6321916a7e8fc4e3babb0", @@ -77,14 +1098,4 @@ mod tests { assert!(result.is_ok()); // Add assertions to check if data is stored correctly in the database } - - #[test] - fn test_index_with_invalid_input() { - // Test with invalid input data, like an empty script or invalid weightage - } - - #[test] - fn test_index_error_handling() { - // Test error handling scenarios, like database errors - } } diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index d418c1a00ae..9c75b2712e5 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -2,9 +2,6 @@ pub mod error; mod indexer; pub mod network; -use parking_lot::Mutex; -use petgraph::graphmap::UnGraphMap; -use serde::Serialize; use std::{path::PathBuf, sync::Arc}; pub use api::ocean_router; @@ -13,6 +10,8 @@ pub use indexer::{ index_block, invalidate_block, oracle::invalidate_oracle_interval, transaction::index_transaction, tx_result, PoolCreationHeight, }; +use parking_lot::Mutex; +use petgraph::graphmap::UnGraphMap; use repository::{ AuctionHistoryByHeightRepository, AuctionHistoryRepository, BlockByHeightRepository, BlockRepository, MasternodeByHeightRepository, MasternodeRepository, MasternodeStatsRepository, @@ -22,9 +21,11 @@ use repository::{ OraclePriceAggregatedRepositorykey, OraclePriceFeedKeyRepository, OraclePriceFeedRepository, OracleRepository, OracleTokenCurrencyKeyRepository, OracleTokenCurrencyRepository, PoolSwapAggregatedKeyRepository, PoolSwapAggregatedRepository, PoolSwapRepository, - PriceTickerRepository, RawBlockRepository, TransactionByBlockHashRepository, - TransactionRepository, TransactionVinRepository, TransactionVoutRepository, TxResultRepository, + PriceTickerKeyRepository, PriceTickerRepository, RawBlockRepository, + TransactionByBlockHashRepository, TransactionRepository, TransactionVinRepository, + TransactionVoutRepository, TxResultRepository, }; +use serde::Serialize; pub mod api; mod model; mod repository; @@ -109,6 +110,7 @@ pub struct OracleHistoryService { pub struct PriceTickerService { by_id: PriceTickerRepository, + by_key: PriceTickerKeyRepository, } #[derive(Clone, Debug, Serialize, Eq, PartialEq, Hash)] @@ -198,7 +200,8 @@ impl Services { by_key: OracleHistoryRepositoryKey::new(Arc::clone(&store)), }, price_ticker: PriceTickerService { - by_id: PriceTickerRepository::new(Arc::clone(&store)), + by_id: PriceTickerRepository::new_id(Arc::clone(&store)), + by_key: PriceTickerKeyRepository::new_key(Arc::clone(&store)), }, token_graph: Arc::new(Mutex::new(UnGraphMap::new())), } diff --git a/lib/ain-ocean/src/model/mod.rs b/lib/ain-ocean/src/model/mod.rs index 4ff98fec0d1..44afffc91cb 100644 --- a/lib/ain-ocean/src/model/mod.rs +++ b/lib/ain-ocean/src/model/mod.rs @@ -11,7 +11,6 @@ mod oracle_token_currency; mod poolswap; mod poolswap_aggregated; mod price_ticker; -mod prices; mod raw_block; mod script_activity; mod script_aggregation; @@ -34,7 +33,6 @@ pub use oracle_token_currency::*; pub use poolswap::*; pub use poolswap_aggregated::*; pub use price_ticker::*; -// pub use prices::*; // pub use raw_block::*; // pub use script_activity::*; // pub use script_aggregation::*; diff --git a/lib/ain-ocean/src/model/oracle.rs b/lib/ain-ocean/src/model/oracle.rs index e5cfac3bc33..40fb7b19099 100644 --- a/lib/ain-ocean/src/model/oracle.rs +++ b/lib/ain-ocean/src/model/oracle.rs @@ -1,7 +1,7 @@ use bitcoin::Txid; use serde::{Deserialize, Serialize}; -use super::BlockContext; +use super::{ApiResponseOraclePriceFeed, BlockContext}; #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] @@ -19,3 +19,16 @@ pub struct PriceFeedsItem { pub token: String, pub currency: String, } + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PriceOracles { + pub id: String, + pub key: String, + pub token: String, + pub currency: String, + pub oracle_id: String, + pub weightage: u8, + pub feed: Option, + pub block: BlockContext, +} diff --git a/lib/ain-ocean/src/model/oracle_price_active.rs b/lib/ain-ocean/src/model/oracle_price_active.rs index 47b234342b6..9185cb03d3a 100644 --- a/lib/ain-ocean/src/model/oracle_price_active.rs +++ b/lib/ain-ocean/src/model/oracle_price_active.rs @@ -16,7 +16,7 @@ pub struct OraclePriceActive { pub block: BlockContext, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct OraclePriceActiveActive { pub amount: String, @@ -24,7 +24,7 @@ pub struct OraclePriceActiveActive { pub oracles: OraclePriceActiveActiveOracles, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct OraclePriceActiveNext { pub amount: String, @@ -32,14 +32,14 @@ pub struct OraclePriceActiveNext { pub oracles: OraclePriceActiveNextOracles, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct OraclePriceActiveActiveOracles { pub active: i32, pub total: i32, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct OraclePriceActiveNextOracles { pub active: i32, diff --git a/lib/ain-ocean/src/model/oracle_price_aggregated.rs b/lib/ain-ocean/src/model/oracle_price_aggregated.rs index 539eb3c43d0..ecc30eb2209 100644 --- a/lib/ain-ocean/src/model/oracle_price_aggregated.rs +++ b/lib/ain-ocean/src/model/oracle_price_aggregated.rs @@ -15,7 +15,7 @@ pub struct OraclePriceAggregated { pub block: BlockContext, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedAggregated { pub amount: String, @@ -23,9 +23,21 @@ pub struct OraclePriceAggregatedAggregated { pub oracles: OraclePriceAggregatedAggregatedOracles, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedAggregatedOracles { pub active: i32, pub total: i32, } + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceAggregatedApi { + pub id: String, + pub key: String, + pub sort: String, + pub token: String, + pub currency: String, + pub aggregated: OraclePriceAggregatedAggregated, + pub block: BlockContext, +} diff --git a/lib/ain-ocean/src/model/oracle_price_feed.rs b/lib/ain-ocean/src/model/oracle_price_feed.rs index 55451533647..69901ed96d9 100644 --- a/lib/ain-ocean/src/model/oracle_price_feed.rs +++ b/lib/ain-ocean/src/model/oracle_price_feed.rs @@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize}; use super::BlockContext; pub type OraclePriceFeedId = (String, String, Txid, Txid); // token-currency-oracle_id-txid pub type OraclePriceFeedkey = (String, String, Txid); // token-currency-oracle_id + #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OraclePriceFeed { @@ -18,3 +19,18 @@ pub struct OraclePriceFeed { pub amount: i64, pub block: BlockContext, } + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ApiResponseOraclePriceFeed { + pub id: String, + pub key: String, + pub sort: String, + pub token: String, + pub currency: String, + pub oracle_id: Txid, + pub txid: Txid, + pub time: i32, + pub amount: String, + pub block: BlockContext, +} diff --git a/lib/ain-ocean/src/model/oracle_token_currency.rs b/lib/ain-ocean/src/model/oracle_token_currency.rs index decfaa2d89a..2fe9c8acbf9 100644 --- a/lib/ain-ocean/src/model/oracle_token_currency.rs +++ b/lib/ain-ocean/src/model/oracle_token_currency.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use super::BlockContext; pub type OracleTokenCurrencyId = (String, String, Txid); //token-currency-oracleId -pub type OracleTokenCurrencyKey = (String, String); //token-currency +pub type OracleTokenCurrencyKey = (String, String, u32); //token-currency-height #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OracleTokenCurrency { diff --git a/lib/ain-ocean/src/model/poolswap_aggregated.rs b/lib/ain-ocean/src/model/poolswap_aggregated.rs index 2823cf15332..be01ac7490c 100644 --- a/lib/ain-ocean/src/model/poolswap_aggregated.rs +++ b/lib/ain-ocean/src/model/poolswap_aggregated.rs @@ -1,8 +1,9 @@ -use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use super::BlockContext; use bitcoin::BlockHash; +use serde::{Deserialize, Serialize}; + +use super::BlockContext; pub type PoolSwapAggregatedId = (u32, u32, BlockHash); // (pool_id, interval, block_hash) pub type PoolSwapAggregatedKey = (u32, u32, i64); // (pool_id, interval, bucket) diff --git a/lib/ain-ocean/src/model/price_ticker.rs b/lib/ain-ocean/src/model/price_ticker.rs index 2a4a6cfcdfc..7d386ce9c7a 100644 --- a/lib/ain-ocean/src/model/price_ticker.rs +++ b/lib/ain-ocean/src/model/price_ticker.rs @@ -1,8 +1,10 @@ use serde::{Deserialize, Serialize}; -use super::oracle_price_aggregated::OraclePriceAggregated; +use super::{oracle_price_aggregated::OraclePriceAggregated, OraclePriceAggregatedApi}; pub type PriceTickerId = (String, String); //token-currency +pub type PriceTickerKey = (i32, u32, String, String); // total-height-token-currency + #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct PriceTicker { @@ -10,3 +12,11 @@ pub struct PriceTicker { pub sort: String, //count-height-token-currency pub price: OraclePriceAggregated, } + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PriceTickerApi { + pub id: String, //token-currency + pub sort: String, //count-height-token-currency + pub price: OraclePriceAggregatedApi, +} diff --git a/lib/ain-ocean/src/model/prices.rs b/lib/ain-ocean/src/model/prices.rs deleted file mode 100644 index 10c555b27a5..00000000000 --- a/lib/ain-ocean/src/model/prices.rs +++ /dev/null @@ -1,14 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use super::{BlockContext, OraclePriceFeed}; - -#[derive(Debug, Serialize, Deserialize)] -pub struct PriceOracles { - pub id: String, - pub key: String, - pub token: String, - pub currency: String, - pub oracle_id: String, - pub feed: OraclePriceFeed, - pub block: BlockContext, -} diff --git a/lib/ain-ocean/src/repository/price_ticker.rs b/lib/ain-ocean/src/repository/price_ticker.rs index 8f83a3d032c..97eef7b2989 100644 --- a/lib/ain-ocean/src/repository/price_ticker.rs +++ b/lib/ain-ocean/src/repository/price_ticker.rs @@ -5,7 +5,7 @@ use ain_macros::Repository; use super::RepositoryOps; use crate::{ - model::{PriceTicker, PriceTickerId}, + model::{PriceTicker, PriceTickerId, PriceTickerKey}, storage::{columns, ocean_store::OceanStore}, Result, }; @@ -16,3 +16,28 @@ pub struct PriceTickerRepository { pub store: Arc, col: LedgerColumn, } + +impl PriceTickerRepository { + pub fn new_id(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} + +#[derive(Repository)] +#[repository(K = "PriceTickerKey", V = "PriceTickerId")] +pub struct PriceTickerKeyRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl PriceTickerKeyRepository { + pub fn new_key(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } +} diff --git a/lib/ain-ocean/src/storage/columns/mod.rs b/lib/ain-ocean/src/storage/columns/mod.rs index f4144451467..b405505abde 100644 --- a/lib/ain-ocean/src/storage/columns/mod.rs +++ b/lib/ain-ocean/src/storage/columns/mod.rs @@ -45,7 +45,7 @@ pub use transaction_vout::*; pub use tx_result::*; pub use vault_auction_history::*; -pub const COLUMN_NAMES: [&str; 33] = [ +pub const COLUMN_NAMES: [&str; 34] = [ block::Block::NAME, block::BlockByHeight::NAME, masternode_stats::MasternodeStats::NAME, @@ -68,6 +68,7 @@ pub const COLUMN_NAMES: [&str; 33] = [ pool_swap_aggregated::PoolSwapAggregatedKey::NAME, pool_swap::PoolSwap::NAME, price_ticker::PriceTicker::NAME, + price_ticker::PriceTickerKey::NAME, raw_block::RawBlock::NAME, script_activity::ScriptActivity::NAME, script_aggregation::ScriptAggregation::NAME, diff --git a/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs b/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs index f3cb8826b87..3924838ea6a 100644 --- a/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs +++ b/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs @@ -1,8 +1,9 @@ -use crate::model; use ain_db::{Column, ColumnName, DBError, TypedColumn}; use anyhow::format_err; use bitcoin::{hashes::Hash, BlockHash}; +use crate::model; + #[derive(Debug)] pub struct PoolSwapAggregated; diff --git a/lib/ain-ocean/src/storage/columns/price_ticker.rs b/lib/ain-ocean/src/storage/columns/price_ticker.rs index db73d7219ba..871a682b522 100644 --- a/lib/ain-ocean/src/storage/columns/price_ticker.rs +++ b/lib/ain-ocean/src/storage/columns/price_ticker.rs @@ -1,4 +1,4 @@ -use ain_db::{Column, ColumnName, TypedColumn}; +use ain_db::{Column, ColumnName, DBError, TypedColumn}; use crate::model; @@ -16,3 +16,41 @@ impl Column for PriceTicker { impl TypedColumn for PriceTicker { type Type = model::PriceTicker; } + +#[derive(Debug)] +pub struct PriceTickerKey; + +impl ColumnName for PriceTickerKey { + const NAME: &'static str = "price_ticker_key"; +} + +impl Column for PriceTickerKey { + type Index = model::PriceTickerKey; + + fn key(index: &Self::Index) -> Result, DBError> { + let (total, height, token, currency) = index; + let mut vec = Vec::new(); + vec.extend_from_slice(&total.to_be_bytes()); + vec.extend_from_slice(&height.to_be_bytes()); + vec.extend_from_slice(token.as_bytes()); + vec.extend_from_slice(currency.as_bytes()); + Ok(vec) + } + + fn get_key(raw_key: Box<[u8]>) -> Result { + let total = i32::from_be_bytes(raw_key[0..4].try_into().unwrap()); + let height = u32::from_be_bytes(raw_key[4..8].try_into().unwrap()); + let currency_n = raw_key.len() - 3; // 3 letters of currency code + let token = std::str::from_utf8(&raw_key[8..currency_n]) + .map_err(|_| DBError::ParseKey)? + .to_string(); + let currency = std::str::from_utf8(&raw_key[currency_n..]) + .map_err(|_| DBError::ParseKey)? + .to_string(); + Ok((total, height, token, currency)) + } +} + +impl TypedColumn for PriceTickerKey { + type Type = model::PriceTickerId; +} From 0fe051aba314b0ad098a976512aec3dc8bc866eb Mon Sep 17 00:00:00 2001 From: canonbrother Date: Fri, 31 May 2024 18:36:07 +0800 Subject: [PATCH 099/185] Ocean: poolpair apr & volume (#2925) * finishing poolpair apr and volume * fix get_apr * set default apr instead of none * grab 2e948d7 defichain-rpc * fmt * poolpair fee typo * get_dex_fees_pct * fmt_rs * log path * enum TokenDirection --- lib/Cargo.lock | 4 +- lib/ain-ocean/src/api/pool_pair/mod.rs | 86 +++++----------- lib/ain-ocean/src/api/pool_pair/path.rs | 99 ++++++++++-------- lib/ain-ocean/src/api/pool_pair/service.rs | 113 +++++++++++++++++---- lib/ain-ocean/src/indexer/mod.rs | 4 +- 5 files changed, 176 insertions(+), 130 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index b944da3bddc..26e1f9276bb 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -1527,7 +1527,7 @@ dependencies = [ [[package]] name = "defichain-rpc" version = "0.18.0" -source = "git+https://github.com/defich/rust-defichain-rpc.git#ef716fe7080188ddfe5674e88a3aaed9e2c0497d" +source = "git+https://github.com/defich/rust-defichain-rpc.git#2e948d7d7ebb9df548c5773903acb0e46c67ab1b" dependencies = [ "async-trait", "defichain-rpc-json", @@ -1540,7 +1540,7 @@ dependencies = [ [[package]] name = "defichain-rpc-json" version = "0.18.0" -source = "git+https://github.com/defich/rust-defichain-rpc.git#ef716fe7080188ddfe5674e88a3aaed9e2c0497d" +source = "git+https://github.com/defich/rust-defichain-rpc.git#2e948d7d7ebb9df548c5773903acb0e46c67ab1b" dependencies = [ "bitcoin", "serde", diff --git a/lib/ain-ocean/src/api/pool_pair/mod.rs b/lib/ain-ocean/src/api/pool_pair/mod.rs index ea2927678bb..f58d159ed72 100644 --- a/lib/ain-ocean/src/api/pool_pair/mod.rs +++ b/lib/ain-ocean/src/api/pool_pair/mod.rs @@ -15,20 +15,20 @@ use defichain_rpc::{ }; use futures::future::try_join_all; use path::{ - compute_return_less_dex_fees_in_destination_token, get_all_swap_paths, get_token_identifier, - sync_token_graph_if_empty, BestSwapPathResponse, EstimatedLessDexFeeInfo, SwapPathPoolPair, + get_all_swap_paths, get_token_identifier, sync_token_graph_if_empty, BestSwapPathResponse, SwapPathsResponse, }; use petgraph::graphmap::UnGraphMap; use rust_decimal::Decimal; -use rust_decimal_macros::dec; use serde::{Deserialize, Serialize}; use serde_json::json; -use service::{get_aggregated_in_usd, get_apr, get_total_liquidity_usd}; +use service::{ + get_aggregated_in_usd, get_apr, get_total_liquidity_usd, get_usd_volume, PoolPairVolumeResponse, +}; use super::{ cache::{get_pool_pair_cached, get_token_cached}, - common::{format_number, parse_dat_symbol}, + common::parse_dat_symbol, path::Path, query::{PaginationQuery, Query}, response::{ApiPagedResponse, Response}, @@ -190,12 +190,6 @@ pub struct PoolPairAprResponse { pub commission: Decimal, } -#[derive(Serialize, Debug, Clone, Default)] -struct PoolPairVolumeResponse { - d30: f64, - h24: f64, -} - #[derive(Serialize, Debug, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct PoolPairResponse { @@ -215,8 +209,8 @@ pub struct PoolPairResponse { reward_loan_pct: String, custom_rewards: Option>, creation: PoolPairCreationResponse, - apr: Option, - volume: Option, + apr: PoolPairAprResponse, + volume: PoolPairVolumeResponse, } impl PoolPairResponse { @@ -226,6 +220,8 @@ impl PoolPairResponse { a_token_name: String, b_token_name: String, total_liquidity_usd: Decimal, + apr: PoolPairAprResponse, + volume: PoolPairVolumeResponse, ) -> Result { let parts = p.symbol.split('-').collect::>(); let [a, b] = <[&str; 2]>::try_from(parts) @@ -246,7 +242,7 @@ impl PoolPairResponse { name: a_token_name, reserve: p.reserve_a.to_string(), block_commission: p.block_commission_a.to_string(), - fee: p.dex_fee_in_pct_token_a.map(|_| PoolPairFeeResponse { + fee: p.dex_fee_pct_token_a.map(|_| PoolPairFeeResponse { pct: p.dex_fee_pct_token_a.map(|fee| fee.to_string()), in_pct: p.dex_fee_in_pct_token_a.map(|fee| fee.to_string()), out_pct: p.dex_fee_out_pct_token_a.map(|fee| fee.to_string()), @@ -259,7 +255,7 @@ impl PoolPairResponse { name: b_token_name, reserve: p.reserve_b.to_string(), block_commission: p.block_commission_b.to_string(), - fee: p.dex_fee_in_pct_token_b.map(|_| PoolPairFeeResponse { + fee: p.dex_fee_pct_token_b.map(|_| PoolPairFeeResponse { pct: p.dex_fee_pct_token_b.map(|fee| fee.to_string()), in_pct: p.dex_fee_in_pct_token_b.map(|fee| fee.to_string()), out_pct: p.dex_fee_out_pct_token_b.map(|fee| fee.to_string()), @@ -283,8 +279,8 @@ impl PoolPairResponse { tx: p.creation_tx, height: p.creation_height, }, - apr: None, // todo: await this.poolPairService.getAPR(id, info) - volume: None, // todo: await this.poolPairService.getUSDVolume(id) + apr, + volume, }) } } @@ -329,13 +325,16 @@ async fn list_pool_pairs( .ok_or(format_err!("None is not valid"))?; let total_liquidity_usd = get_total_liquidity_usd(&ctx, &p).await?; - let _apr = get_apr(&ctx, &id, &p).await?; + let apr = get_apr(&ctx, &id, &p).await?; + let volume = get_usd_volume(&ctx, &id).await?; let res = PoolPairResponse::from_with_id( id, p, a_token_name, b_token_name, total_liquidity_usd, + apr, + volume, )?; Ok::(res) }) @@ -355,7 +354,8 @@ async fn get_pool_pair( ) -> Result>> { if let Some((id, pool)) = get_pool_pair_cached(&ctx, id).await? { let total_liquidity_usd = get_total_liquidity_usd(&ctx, &pool).await?; - let _apr = get_apr(&ctx, &id, &pool).await?; + let apr = get_apr(&ctx, &id, &pool).await?; + let volume = get_usd_volume(&ctx, &id).await?; let ( _, TokenInfo { @@ -378,6 +378,8 @@ async fn get_pool_pair( a_token_name, b_token_name, total_liquidity_usd, + apr, + volume, )?; return Ok(Response::new(Some(res))); }; @@ -615,50 +617,8 @@ async fn get_best_path( Path((from_token_id, to_token_id)): Path<(String, String)>, Extension(ctx): Extension>, ) -> Result> { - let SwapPathsResponse { - from_token, - to_token, - paths, - } = get_all_swap_paths(&ctx, &from_token_id, &to_token_id).await?; - - let mut best_path = Vec::::new(); - let mut best_return = dec!(0); - let mut best_return_less_dex_fees = dec!(0); - - for path in paths { - let path_len = path.len(); - let EstimatedLessDexFeeInfo { - estimated_return, - estimated_return_less_dex_fees, - } = compute_return_less_dex_fees_in_destination_token(&path, &from_token_id).await?; - - if path_len == 1 { - return Ok(Response::new(BestSwapPathResponse { - from_token, - to_token, - best_path: path, - estimated_return: format_number(estimated_return), - estimated_return_less_dex_fees: format_number(estimated_return_less_dex_fees), - })); - }; - - if estimated_return > best_return { - best_return = estimated_return; - } - - if estimated_return_less_dex_fees > best_return_less_dex_fees { - best_return_less_dex_fees = estimated_return_less_dex_fees; - best_path = path; - }; - } - - Ok(Response::new(BestSwapPathResponse { - from_token, - to_token, - best_path, - estimated_return: format_number(best_return), - estimated_return_less_dex_fees: format_number(best_return_less_dex_fees), - })) + let res = path::get_best_path(&ctx, &from_token_id, &to_token_id).await?; + Ok(Response::new(res)) } #[ocean_endpoint] diff --git a/lib/ain-ocean/src/api/pool_pair/path.rs b/lib/ain-ocean/src/api/pool_pair/path.rs index ec10f53e66d..9ec0ea74e05 100644 --- a/lib/ain-ocean/src/api/pool_pair/path.rs +++ b/lib/ain-ocean/src/api/pool_pair/path.rs @@ -17,6 +17,11 @@ use crate::{ Error, Result, TokenIdentifier, }; +enum TokenDirection { + In, + Out +} + #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] struct PriceRatio { @@ -275,6 +280,53 @@ fn all_simple_paths( Ok(paths) } +fn get_dex_fees_pct( + pool_pair_info: PoolPairInfo, + from_token_id: &String, + to_token_id: &String, +) -> Option { + let PoolPairInfo { + id_token_a, + id_token_b, + dex_fee_in_pct_token_a, + dex_fee_out_pct_token_a, + dex_fee_in_pct_token_b, + dex_fee_out_pct_token_b, + .. + } = pool_pair_info; + + let token_a_direction = if id_token_a == *from_token_id { + TokenDirection::In + } else { + TokenDirection::Out + }; + + let token_b_direction = if id_token_b == *to_token_id { + TokenDirection::Out + } else { + TokenDirection::In + }; + + if dex_fee_in_pct_token_a.is_none() + && dex_fee_out_pct_token_a.is_none() + && dex_fee_in_pct_token_b.is_none() + && dex_fee_out_pct_token_b.is_none() + { + return None; + } + + Some(EstimatedDexFeesInPct { + ba: match token_a_direction { + TokenDirection::In => format!("{:.8}", dex_fee_in_pct_token_a.unwrap_or_default()), + TokenDirection::Out => format!("{:.8}", dex_fee_out_pct_token_a.unwrap_or_default()), + }, + ab: match token_b_direction { + TokenDirection::In => format!("{:.8}", dex_fee_in_pct_token_b.unwrap_or_default()), + TokenDirection::Out => format!("{:.8}", dex_fee_out_pct_token_b.unwrap_or_default()), + } + }) +} + pub async fn compute_paths_between_tokens( ctx: &Arc, from_token_id: &String, @@ -316,6 +368,9 @@ pub async fn compute_paths_between_tokens( let (_, pool_pair_info) = pool.unwrap(); + let estimated_dex_fees_in_pct = + get_dex_fees_pct(pool_pair_info.clone(), from_token_id, to_token_id); + let PoolPairInfo { symbol, id_token_a, @@ -323,52 +378,9 @@ pub async fn compute_paths_between_tokens( reserve_a_reserve_b: ab, reserve_b_reserve_a: ba, commission, - dex_fee_in_pct_token_a, - dex_fee_out_pct_token_a, - dex_fee_in_pct_token_b, - dex_fee_out_pct_token_b, .. } = pool_pair_info; - let token_a_direction = if id_token_a == *from_token_id { - "in" - } else { - "out" - }; - - let token_b_direction = if id_token_b == *to_token_id { - "out" - } else { - "in" - }; - - let estimated_dex_fees_in_pct = if let ( - Some(dex_fee_in_pct_token_a), - Some(dex_fee_out_pct_token_a), - Some(dex_fee_in_pct_token_b), - Some(dex_fee_out_pct_token_b), - ) = ( - dex_fee_in_pct_token_a, - dex_fee_out_pct_token_a, - dex_fee_in_pct_token_b, - dex_fee_out_pct_token_b, - ) { - Some(EstimatedDexFeesInPct { - ba: if token_a_direction == "in" { - format!("{:.8}", dex_fee_in_pct_token_a) - } else { - format!("{:.8}", dex_fee_out_pct_token_a) - }, - ab: if token_b_direction == "in" { - format!("{:.8}", dex_fee_in_pct_token_b) - } else { - format!("{:.8}", dex_fee_out_pct_token_b) - }, - }) - } else { - None - }; - let swap_path_pool_pair = SwapPathPoolPair { pool_pair_id, symbol, @@ -506,6 +518,7 @@ pub async fn sync_token_graph(ctx: &Arc) -> Result<()> { if !graph.lock().contains_edge(id_token_a, id_token_b) { graph.lock().add_edge(id_token_a, id_token_b, k); } + log::debug!("sync_token_graph edges: {:?}", graph.lock().edge_count()); } // wait 120s diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index 1a11d494fbd..19c5f8e28da 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -1,9 +1,10 @@ -use std::{str::FromStr, sync::Arc}; +use std::{collections::HashMap, str::FromStr, sync::Arc}; use anyhow::{format_err, Context}; use defichain_rpc::{json::poolpair::PoolPairInfo, BlockchainRPC}; use rust_decimal::{prelude::FromPrimitive, Decimal}; use rust_decimal_macros::dec; +use serde::Serialize; use super::{AppContext, PoolPairAprResponse}; use crate::{ @@ -12,10 +13,19 @@ use crate::{ pool_pair::path::{get_best_path, BestSwapPathResponse}, }, error::{Error, NotFoundKind}, + indexer::PoolSwapAggregatedInterval, model::PoolSwapAggregatedAggregated, + repository::{RepositoryOps, SecondaryIndex}, + storage::SortOrder, Result, }; +#[derive(Serialize, Debug, Clone, Default)] +pub struct PoolPairVolumeResponse { + pub d30: Decimal, + pub h24: Decimal, +} + async fn get_usd_per_dfi(ctx: &Arc) -> Result { let usdt = get_pool_pair_cached(ctx, "USDT-DFI".to_string()).await?; @@ -306,18 +316,85 @@ async fn get_yearly_reward_loan_usd(ctx: &Arc, id: &String) -> Resul .ok_or_else(|| Error::OverflowError) } -// TODO(): poolswap aggregate required -async fn get_usd_volume(id: &String) -> Result { - println!("id: {:?}", id); - Ok(dec!(0)) +async fn gather_amount( + ctx: &Arc, + pool_id: u32, + interval: u32, + count: usize, +) -> Result { + let repository = &ctx.services.pool_swap_aggregated; + + let swaps = repository + .by_key + .list(Some((pool_id, interval, i64::MAX)), SortOrder::Descending)? + .take(count) + .take_while(|item| match item { + Ok((k, _)) => k.0 == pool_id && k.1 == interval, + _ => true, + }) + .map(|e| repository.by_key.retrieve_primary_value(e)) + .collect::>>()?; + + let mut aggregated = HashMap::::new(); + + for swap in swaps { + let token_ids = swap.aggregated.amounts.keys(); + for token_id in token_ids { + let from_amount = swap + .aggregated + .amounts + .get(token_id) + .map(|amt| Decimal::from_str(amt)) + .transpose()? + .unwrap_or(dec!(0)); + + let amount = if let Some(amount) = aggregated.get(token_id) { + amount + .checked_add(from_amount) + .ok_or(Error::OverflowError)? + } else { + from_amount + }; + + aggregated.insert(token_id.to_string(), amount); + } + } + + let mut volume = dec!(0); + + for token_id in aggregated.keys() { + let token_price = get_token_usd_value(ctx, token_id).await?; + let amount = aggregated.get(token_id).cloned().unwrap_or(dec!(0)); + volume = volume + .checked_add( + token_price + .checked_mul(amount) + .ok_or(Error::OverflowError)?, + ) + .ok_or(Error::OverflowError)?; + } + + Ok(volume) +} + +pub async fn get_usd_volume(ctx: &Arc, id: &str) -> Result { + let pool_id = id.parse::()?; + Ok(PoolPairVolumeResponse { + h24: gather_amount(ctx, pool_id, PoolSwapAggregatedInterval::OneHour as u32, 24).await?, + d30: gather_amount(ctx, pool_id, PoolSwapAggregatedInterval::OneDay as u32, 30).await?, + }) } /// Estimate yearly commission rate by taking 24 hour commission x 365 days -async fn get_yearly_commission_estimate(id: &String, p: &PoolPairInfo) -> Result { - let volume = get_usd_volume(id).await?; +async fn get_yearly_commission_estimate( + ctx: &Arc, + id: &str, + p: &PoolPairInfo, +) -> Result { + let volume = get_usd_volume(ctx, id).await?; let commission = Decimal::from_f64(p.commission).unwrap_or_default(); commission - .checked_mul(volume) + .checked_mul(volume.h24) .ok_or_else(|| Error::OverflowError)? .checked_mul(dec!(365)) .ok_or_else(|| Error::OverflowError) @@ -327,32 +404,28 @@ pub async fn get_apr( ctx: &Arc, id: &String, p: &PoolPairInfo, -) -> Result> { +) -> Result { let custom_usd = get_yearly_custom_reward_usd(ctx, p).await?; let pct_usd = get_yearly_reward_pct_usd(ctx, p).await?; let loan_usd = get_yearly_reward_loan_usd(ctx, id).await?; let total_liquidity_usd = get_total_liquidity_usd(ctx, p).await?; - if custom_usd.is_zero() - || pct_usd.is_zero() - || loan_usd.is_zero() - || total_liquidity_usd.is_zero() - { - return Ok(None); - }; - let yearly_usd = custom_usd .checked_add(pct_usd) .ok_or_else(|| Error::OverflowError)? .checked_add(loan_usd) .ok_or_else(|| Error::OverflowError)?; + if yearly_usd.is_zero() { + return Ok(PoolPairAprResponse::default()); + }; + // 1 == 100%, 0.1 = 10% let reward = yearly_usd .checked_div(total_liquidity_usd) .ok_or_else(|| Error::UnderflowError)?; - let yearly_commission = get_yearly_commission_estimate(id, p).await?; + let yearly_commission = get_yearly_commission_estimate(ctx, id, p).await?; let commission = yearly_commission .checked_div(total_liquidity_usd) .ok_or_else(|| Error::UnderflowError)?; @@ -361,11 +434,11 @@ pub async fn get_apr( .checked_add(commission) .ok_or_else(|| Error::OverflowError)?; - Ok(Some(PoolPairAprResponse { + Ok(PoolPairAprResponse { reward, commission, total, - })) + }) } async fn get_pool_pair(ctx: &Arc, a: &str, b: &str) -> Result> { diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 6f33867b15b..88417cd3391 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -3,7 +3,7 @@ pub mod loan_token; mod masternode; pub mod oracle; pub mod oracle_test; -mod pool; +pub mod pool; pub mod transaction; pub mod tx_result; @@ -12,7 +12,7 @@ use std::{sync::Arc, time::Instant}; use ain_dftx::{deserialize, DfTx, Stack}; use defichain_rpc::json::blockchain::{Block, Transaction}; use log::debug; -pub use pool::AGGREGATED_INTERVALS; +pub use pool::{PoolSwapAggregatedInterval, AGGREGATED_INTERVALS}; use crate::{ index_transaction, From 88719d48cea00d22cb3081a9e64962b05ea52f4d Mon Sep 17 00:00:00 2001 From: canonbrother Date: Thu, 6 Jun 2024 16:52:44 +0800 Subject: [PATCH 100/185] Ocean list pool swap verbose api (#2926) * rm unuse * wip * check_swap_type * fix check_swap_type * 20 per page * enable compositeswap indexer * rm logs * fmt * point rust-bitcoin to main * fix list_pool_swap res from_amount decimal 8 * run set tx_result only while ocean is enabled * rm log --- lib/Cargo.lock | 8 +- lib/ain-ocean/src/api/mod.rs | 2 - lib/ain-ocean/src/api/pool_pair/mod.rs | 63 +++-- lib/ain-ocean/src/api/pool_pair/path.rs | 5 +- lib/ain-ocean/src/api/pool_pair/service.rs | 264 ++++++++++++++++++++- lib/ain-ocean/src/error.rs | 4 + lib/ain-ocean/src/indexer/mod.rs | 2 +- lib/ain-ocean/src/model/poolswap.rs | 2 +- lib/ain-ocean/src/network.rs | 13 + src/dfi/mn_checks.cpp | 3 +- 10 files changed, 317 insertions(+), 49 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 26e1f9276bb..e5a36c970b5 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -738,7 +738,7 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitcoin" version = "0.31.0" -source = "git+https://github.com/defich/rust-bitcoin.git#af64fe422669e2d4fc24fca93561566e22cce1df" +source = "git+https://github.com/defich/rust-bitcoin.git#c68ce40fd7f618105ab7d6e8be49ce083f97d4e8" dependencies = [ "bech32", "bitcoin-internals", @@ -762,7 +762,7 @@ dependencies = [ [[package]] name = "bitcoin-io" version = "0.1.0" -source = "git+https://github.com/defich/rust-bitcoin.git#af64fe422669e2d4fc24fca93561566e22cce1df" +source = "git+https://github.com/defich/rust-bitcoin.git#c68ce40fd7f618105ab7d6e8be49ce083f97d4e8" [[package]] name = "bitcoin_hashes" @@ -1527,7 +1527,7 @@ dependencies = [ [[package]] name = "defichain-rpc" version = "0.18.0" -source = "git+https://github.com/defich/rust-defichain-rpc.git#2e948d7d7ebb9df548c5773903acb0e46c67ab1b" +source = "git+https://github.com/defich/rust-defichain-rpc.git#c2329bcf26c497cdf4f1c22ef1198819542cf70d" dependencies = [ "async-trait", "defichain-rpc-json", @@ -1540,7 +1540,7 @@ dependencies = [ [[package]] name = "defichain-rpc-json" version = "0.18.0" -source = "git+https://github.com/defich/rust-defichain-rpc.git#2e948d7d7ebb9df548c5773903acb0e46c67ab1b" +source = "git+https://github.com/defich/rust-defichain-rpc.git#c2329bcf26c497cdf4f1c22ef1198819542cf70d" dependencies = [ "bitcoin", "serde", diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index d3fce25083f..d3ccc3f51b3 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -80,8 +80,6 @@ pub async fn ocean_router( .nest("/masternodes", masternode::router(Arc::clone(&context))) .nest("/oracles", oracle::router(Arc::clone(&context))) .nest("/poolpairs", pool_pair::router(Arc::clone(&context))) - // .nest("/prices", prices::router(Arc::clone(&context))) - // .nest("/poolpairs", poolpairs::router(Arc::clone(&context))) .nest("/prices", prices::router(Arc::clone(&context))) // .nest("/rawtx", rawtx::router(Arc::clone(&context))) .nest("/stats", stats::router(Arc::clone(&context))) diff --git a/lib/ain-ocean/src/api/pool_pair/mod.rs b/lib/ain-ocean/src/api/pool_pair/mod.rs index f58d159ed72..b2208f69171 100644 --- a/lib/ain-ocean/src/api/pool_pair/mod.rs +++ b/lib/ain-ocean/src/api/pool_pair/mod.rs @@ -22,8 +22,10 @@ use petgraph::graphmap::UnGraphMap; use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; use serde_json::json; +use serde_with::skip_serializing_none; use service::{ - get_aggregated_in_usd, get_apr, get_total_liquidity_usd, get_usd_volume, PoolPairVolumeResponse, + check_swap_type, find_swap_from_to, get_aggregated_in_usd, get_apr, get_total_liquidity_usd, + get_usd_volume, PoolPairVolumeResponse, PoolSwapFromTo, PoolSwapFromToData, SwapType, }; use super::{ @@ -64,15 +66,7 @@ struct DexPrices { denomination: String, } -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct PoolSwapFromToResponse { - address: String, - amount: String, - // symbol: String, - // display_symbol: String, -} - +#[skip_serializing_none] #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct PoolSwapVerboseResponse { @@ -84,35 +78,25 @@ pub struct PoolSwapVerboseResponse { from_amount: String, from_token_id: u64, block: BlockContext, - from: PoolSwapFromToResponse, - to: PoolSwapFromToResponse, - // type: todo()! + from: Option, + to: Option, + r#type: Option, } -impl From for PoolSwapVerboseResponse { - fn from(v: PoolSwap) -> Self { +impl PoolSwapVerboseResponse { + fn map(v: PoolSwap, from_to: Option, swap_type: Option) -> Self { Self { id: v.id, sort: v.sort, txid: v.txid.to_string(), txno: v.txno, pool_pair_id: v.pool_id.to_string(), - from_amount: v.from_amount.to_string(), + from_amount: Decimal::new(v.from_amount, 8).to_string(), from_token_id: v.from_token_id, - from: PoolSwapFromToResponse { - address: v.from.to_hex_string(), - amount: v.from_amount.to_string(), - // symbol: todo!(), - // display_symbol: todo!(), - }, - to: PoolSwapFromToResponse { - address: v.to.to_hex_string(), - amount: v.to_amount.to_string(), - // symbol: todo!(), - // display_symbol: todo!(), - }, + from: from_to.clone().and_then(|item| item.from), + to: from_to.and_then(|item| item.to), block: v.block, - // type: todo!(), + r#type: swap_type, } } } @@ -138,7 +122,7 @@ impl From for PoolSwapResponse { txid: v.txid.to_string(), txno: v.txno, pool_pair_id: v.pool_id.to_string(), - from_amount: v.from_amount.to_string(), + from_amount: Decimal::new(v.from_amount, 8).to_string(), from_token_id: v.from_token_id, block: v.block, } @@ -456,9 +440,9 @@ async fn list_pool_swaps_verbose( .transpose()? .unwrap_or(PoolSwapRepository::initial_key(id)); - let size = if query.size > 200 { 200 } else { query.size }; + let size = if query.size > 20 { 20 } else { query.size }; - let swaps = ctx + let fut = ctx .services .pool .by_id @@ -468,11 +452,20 @@ async fn list_pool_swaps_verbose( Ok((k, _)) => k.0 == id, _ => true, }) - .map(|item| { + .map(|item| async { let (_, swap) = item?; - Ok(PoolSwapVerboseResponse::from(swap)) + let from_to = + find_swap_from_to(&ctx, swap.block.height, swap.txid, swap.txno.try_into()?) + .await?; + + let swap_type = check_swap_type(&ctx, swap.clone()).await?; + + let res = PoolSwapVerboseResponse::map(swap, from_to, swap_type); + Ok::(res) }) - .collect::>>()?; + .collect::>(); + + let swaps = try_join_all(fut).await?; Ok(ApiPagedResponse::of(swaps, query.size, |swap| { swap.sort.to_string() diff --git a/lib/ain-ocean/src/api/pool_pair/path.rs b/lib/ain-ocean/src/api/pool_pair/path.rs index 9ec0ea74e05..12b0015b504 100644 --- a/lib/ain-ocean/src/api/pool_pair/path.rs +++ b/lib/ain-ocean/src/api/pool_pair/path.rs @@ -19,7 +19,7 @@ use crate::{ enum TokenDirection { In, - Out + Out, } #[derive(Debug, Serialize)] @@ -323,7 +323,7 @@ fn get_dex_fees_pct( ab: match token_b_direction { TokenDirection::In => format!("{:.8}", dex_fee_in_pct_token_b.unwrap_or_default()), TokenDirection::Out => format!("{:.8}", dex_fee_out_pct_token_b.unwrap_or_default()), - } + }, }) } @@ -518,7 +518,6 @@ pub async fn sync_token_graph(ctx: &Arc) -> Result<()> { if !graph.lock().contains_edge(id_token_a, id_token_b) { graph.lock().add_edge(id_token_a, id_token_b, k); } - log::debug!("sync_token_graph edges: {:?}", graph.lock().edge_count()); } // wait 120s diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index 19c5f8e28da..59805da9439 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -1,15 +1,20 @@ use std::{collections::HashMap, str::FromStr, sync::Arc}; use anyhow::{format_err, Context}; -use defichain_rpc::{json::poolpair::PoolPairInfo, BlockchainRPC}; +use bitcoin::{Address, Txid}; +use defichain_rpc::{ + json::{account::AccountHistory, poolpair::PoolPairInfo}, + AccountRPC, BlockchainRPC, +}; use rust_decimal::{prelude::FromPrimitive, Decimal}; use rust_decimal_macros::dec; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use super::{AppContext, PoolPairAprResponse}; use crate::{ api::{ cache::{get_gov_cached, get_pool_pair_cached, get_token_cached}, + common::parse_display_symbol, pool_pair::path::{get_best_path, BestSwapPathResponse}, }, error::{Error, NotFoundKind}, @@ -19,6 +24,18 @@ use crate::{ storage::SortOrder, Result, }; +use ain_dftx::{ + deserialize, + pool::{CompositeSwap, PoolSwap}, + DfTx, Stack, +}; + +#[allow(clippy::upper_case_acronyms)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum SwapType { + BUY, + SELL, +} #[derive(Serialize, Debug, Clone, Default)] pub struct PoolPairVolumeResponse { @@ -26,6 +43,22 @@ pub struct PoolPairVolumeResponse { pub h24: Decimal, } +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PoolSwapFromToData { + pub address: String, + pub amount: String, + pub symbol: String, + pub display_symbol: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PoolSwapFromTo { + pub from: Option, + pub to: Option, +} + async fn get_usd_per_dfi(ctx: &Arc) -> Result { let usdt = get_pool_pair_cached(ctx, "USDT-DFI".to_string()).await?; @@ -521,3 +554,230 @@ pub async fn get_aggregated_in_usd( Ok(value) } + +fn call_dftx(ctx: &Arc, txid: Txid) -> Result> { + let vout = ctx + .services + .transaction + .vout_by_id + .list(Some((txid, 0)), SortOrder::Ascending)? + .take(1) + .take_while(|item| match item { + Ok((_, vout)) => vout.txid == txid, + _ => true, + }) + .map(|item| { + let (_, v) = item?; + Ok(v) + }) + .collect::>>()?; + + if vout.is_empty() { + return Ok(None); + } + + let bytes = &vout[0].script.hex; + if bytes.len() > 6 && bytes[0] == 0x6a && bytes[1] <= 0x4e { + let offset = 1 + match bytes[1] { + 0x4c => 2, + 0x4d => 3, + 0x4e => 4, + _ => 1, + }; + + let raw_tx = &bytes[offset..]; + let dftx = match deserialize::(raw_tx) { + Ok(stack) => stack.dftx, + Err(e) => return Err(e.into()), + }; + return Ok(Some(dftx)); + }; + + Ok(None) +} + +fn find_composite_swap_dftx(ctx: &Arc, txid: Txid) -> Result> { + let dftx = call_dftx(ctx, txid)?; + if dftx.is_none() { + return Ok(None); + } + let dftx = dftx.unwrap(); + + let composite_swap_dftx = match dftx { + DfTx::CompositeSwap(data) => Some(data), + _ => None, + }; + + Ok(composite_swap_dftx) +} + +fn find_pool_swap_dftx(ctx: &Arc, txid: Txid) -> Result> { + let dftx = call_dftx(ctx, txid)?; + if dftx.is_none() { + return Ok(None); + } + let dftx = dftx.unwrap(); + let pool_swap_dftx = match dftx { + DfTx::PoolSwap(data) => Some(data), + DfTx::CompositeSwap(data) => Some(data.pool_swap), + _ => None, + }; + + Ok(pool_swap_dftx) +} + +fn find_pool_swap_from_to( + history: AccountHistory, + from: bool, + display_symbol: String, +) -> Result> { + for account in history.amounts { + let parts = account.split('@').collect::>(); + let [value, symbol] = parts + .as_slice() + .try_into() + .context("Invalid amount structure")?; + + let value = Decimal::from_str(value)?; + + if value.is_sign_negative() && from { + return Ok(Some(PoolSwapFromToData { + address: history.owner, + amount: format!("{:.8}", value.abs()), + symbol: symbol.to_string(), + display_symbol, + })); + } + + if value.is_sign_positive() && !from { + return Ok(Some(PoolSwapFromToData { + address: history.owner, + amount: format!("{:.8}", value.abs()), + symbol: symbol.to_string(), + display_symbol, + })); + } + } + + Ok(None) +} + +pub async fn find_swap_from_to( + ctx: &Arc, + height: u32, + txid: Txid, + txno: u32, +) -> Result> { + let dftx = find_pool_swap_dftx(ctx, txid)?; + if dftx.is_none() { + return Ok(None); + } + let dftx = dftx.unwrap(); + + let from_script = dftx.from_script.as_script(); + + let from_address = Address::from_script(from_script, ctx.network.into()); + if from_address.is_err() { + return Ok(None); + } + let from_address = from_address.unwrap().to_string(); + + let to_script = dftx.to_script.as_script(); + let to_address = Address::from_script(to_script, ctx.network.into()); + if to_address.is_err() { + return Ok(None); + } + let to_address = to_address.unwrap().to_string(); + + let from_token = get_token_cached(ctx, &dftx.from_token_id.0.to_string()).await?; + if from_token.is_none() { + return Ok(None); + } + let (_, from_token) = from_token.unwrap(); + + let to_token = get_token_cached(ctx, &dftx.to_token_id.0.to_string()).await?; + if to_token.is_none() { + return Ok(None); + } + let (_, to_token) = to_token.unwrap(); + + let from = PoolSwapFromToData { + address: from_address, + amount: Decimal::new(dftx.from_amount, 8).to_string(), + display_symbol: parse_display_symbol(&from_token), + symbol: from_token.symbol, + }; + + let history = ctx + .client + .get_account_history(&to_address.to_string(), height, txno) + .await?; + + let to = find_pool_swap_from_to(history, false, parse_display_symbol(&to_token))?; + + Ok(Some(PoolSwapFromTo { + from: Some(from), + to, + })) +} + +async fn get_pool_swap_type( + ctx: &Arc, + swap: crate::model::PoolSwap, +) -> Result> { + let pool_pair = get_pool_pair_cached(ctx, swap.pool_id.to_string()).await?; + if pool_pair.is_none() { + return Ok(None); + } + let (_, pool_pair_info) = pool_pair.unwrap(); + let id_token_a = pool_pair_info.id_token_a.parse::()?; + let swap_type = if id_token_a == swap.from_token_id { + SwapType::SELL + } else { + SwapType::BUY + }; + Ok(Some(swap_type)) +} + +pub async fn check_swap_type( + ctx: &Arc, + swap: crate::model::PoolSwap, +) -> Result> { + let dftx = find_composite_swap_dftx(ctx, swap.txid)?; + if dftx.is_none() { + return get_pool_swap_type(ctx, swap).await; + } + let dftx = dftx.unwrap(); + + if dftx.pools.iter().count() <= 1 { + return get_pool_swap_type(ctx, swap).await; + } + + let mut prev = swap.from_token_id.to_string(); + for pool in dftx.pools.iter() { + let pool_id = pool.id.0.to_string(); + let pool_pair = get_pool_pair_cached(ctx, pool_id.clone()).await?; + if pool_pair.is_none() { + break; + } + let (_, pool_pair_info) = pool_pair.unwrap(); + + // if this is current pool pair, if previous token is primary token, indicator = sell + if pool_id == swap.pool_id.to_string() { + let swap_type = if pool_pair_info.id_token_a == prev { + SwapType::SELL + } else { + SwapType::BUY + }; + return Ok(Some(swap_type)); + } + // set previous token as pair swapped out token + prev = if prev == pool_pair_info.id_token_a { + pool_pair_info.id_token_b + } else { + pool_pair_info.id_token_a + } + } + + Ok(None) +} diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 617b1e6c063..fb8e2478f2d 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -61,6 +61,10 @@ pub enum Error { SecondaryIndex, #[error("Token {0:?} is invalid as it is not tradeable")] UntradeableTokenError(String), + #[error("Ocean: BitcoinAddressError: {0:?}")] + BitcoinAddressError(#[from] bitcoin::address::Error), + #[error("Ocean: TryFromIntError: {0:?}")] + TryFromIntError(#[from] std::num::TryFromIntError), #[error(transparent)] Other(#[from] anyhow::Error), } diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 88417cd3391..3fac998c635 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -166,7 +166,7 @@ pub fn index_block( DfTx::SetOracleData(data) => data.index(services, &ctx)?, DfTx::PoolSwap(data) => data.index(services, &ctx)?, DfTx::SetLoanToken(data) => data.index(services, &ctx)?, - // DfTx::CompositeSwap(data) => data.index(services, &ctx)?, + DfTx::CompositeSwap(data) => data.index(services, &ctx)?, // DfTx::PlaceAuctionBid(data) => data.index(services, &ctx)?, _ => (), } diff --git a/lib/ain-ocean/src/model/poolswap.rs b/lib/ain-ocean/src/model/poolswap.rs index ace6dadf4b2..1dee98f7b7a 100644 --- a/lib/ain-ocean/src/model/poolswap.rs +++ b/lib/ain-ocean/src/model/poolswap.rs @@ -5,7 +5,7 @@ use super::BlockContext; pub type PoolSwapKey = (u32, u32, usize); -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct PoolSwap { pub id: String, diff --git a/lib/ain-ocean/src/network.rs b/lib/ain-ocean/src/network.rs index 19d59082b16..911ab641624 100644 --- a/lib/ain-ocean/src/network.rs +++ b/lib/ain-ocean/src/network.rs @@ -22,6 +22,19 @@ impl Network { } } +#[allow(clippy::from_over_into)] +impl Into for Network { + fn into(self) -> bitcoin::Network { + match self { + Network::Mainnet => bitcoin::Network::Mainnet, + Network::Testnet => bitcoin::Network::Testnet, + Network::Devnet => bitcoin::Network::Devnet, + Network::Regtest => bitcoin::Network::Regtest, + _ => bitcoin::Network::Regtest, + } + } +} + impl std::str::FromStr for Network { type Err = &'static str; fn from_str(s: &str) -> Result { diff --git a/src/dfi/mn_checks.cpp b/src/dfi/mn_checks.cpp index 4be0377caae..42763ecaa6c 100644 --- a/src/dfi/mn_checks.cpp +++ b/src/dfi/mn_checks.cpp @@ -1155,7 +1155,8 @@ Res CPoolSwap::ExecuteSwap(CCustomCSView &view, result = swapAmountResult.nValue; // Send final swap amount Rust side for indexer - if (txInfo) { + bool isOceanEnabled = gArgs.GetBoolArg("-oceanarchive", false); + if (txInfo && isOceanEnabled) { const auto &[txType, txHash] = *txInfo; CrossBoundaryResult ffiResult; ocean_try_set_tx_result(ffiResult, From dd360ce88e609b448a30a059ccff0836d3607544 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Fri, 7 Jun 2024 12:07:13 +0100 Subject: [PATCH 101/185] Expose skipped txs to ocean (#2931) --- lib/ain-cpp-imports/src/bridge.rs | 1 + lib/ain-cpp-imports/src/lib.rs | 7 +++++++ lib/ain-ocean/src/indexer/mod.rs | 5 +++++ src/ffi/ffiexports.cpp | 6 ++++++ src/ffi/ffiexports.h | 1 + 5 files changed, 20 insertions(+) diff --git a/lib/ain-cpp-imports/src/bridge.rs b/lib/ain-cpp-imports/src/bridge.rs index 9661b8acabb..53694b6e319 100644 --- a/lib/ain-cpp-imports/src/bridge.rs +++ b/lib/ain-cpp-imports/src/bridge.rs @@ -76,5 +76,6 @@ pub mod ffi { old_amount: TokenAmount, new_amount: &mut TokenAmount, ) -> bool; + fn isSkippedTx(tx_hash: [u8; 32]) -> bool; } } diff --git a/lib/ain-cpp-imports/src/lib.rs b/lib/ain-cpp-imports/src/lib.rs index 6224fc71ec1..7f4c5394467 100644 --- a/lib/ain-cpp-imports/src/lib.rs +++ b/lib/ain-cpp-imports/src/lib.rs @@ -148,6 +148,9 @@ mod ffi { ) -> bool { unimplemented!("{}", UNIMPL_MSG) } + pub fn isSkippedTx(_tx_hash: [u8; 32]) -> bool { + unimplemented!("{}", UNIMPL_MSG) + } } pub use ffi::{Attributes, TokenAmount}; @@ -366,5 +369,9 @@ pub fn split_tokens_from_evm( ffi::migrateTokensFromEVM(mnview_ptr, old_amount, new_amount) } +pub fn is_skipped_tx(tx_hash: [u8; 32]) -> bool { + ffi::isSkippedTx(tx_hash) +} + #[cfg(test)] mod tests {} diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 3fac998c635..44d6dce6235 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -10,6 +10,7 @@ pub mod tx_result; use std::{sync::Arc, time::Instant}; use ain_dftx::{deserialize, DfTx, Stack}; +use bitcoin::hashes::Hash; use defichain_rpc::json::blockchain::{Block, Transaction}; use log::debug; pub use pool::{PoolSwapAggregatedInterval, AGGREGATED_INTERVALS}; @@ -133,6 +134,10 @@ pub fn index_block( index_block_start(services, &block, pools)?; for (tx_idx, tx) in block.tx.into_iter().enumerate() { + if ain_cpp_imports::is_skipped_tx(tx.txid.to_raw_hash().to_byte_array()) { + continue; + } + let start = Instant::now(); let ctx = Context { block: block_ctx.clone(), diff --git a/src/ffi/ffiexports.cpp b/src/ffi/ffiexports.cpp index db3d9302ca8..06a7991bbcb 100644 --- a/src/ffi/ffiexports.cpp +++ b/src/ffi/ffiexports.cpp @@ -416,3 +416,9 @@ uint64_t getDF23Height() { bool migrateTokensFromEVM(std::size_t mnview_ptr, TokenAmount old_amount, TokenAmount &new_amount) { return ExecuteTokenMigrationEVM(mnview_ptr, old_amount, new_amount); } + +bool isSkippedTx(std::array txHash) { + uint256 hash{}; + std::copy(txHash.begin(), txHash.end(), hash.begin()); + return IsSkippedTx(hash); +} diff --git a/src/ffi/ffiexports.h b/src/ffi/ffiexports.h index fa5a95ff555..6caaa4ec6dd 100644 --- a/src/ffi/ffiexports.h +++ b/src/ffi/ffiexports.h @@ -113,5 +113,6 @@ bool isOceanEnabled(); bool isEthSubscriptionEnabled(); uint64_t getDF23Height(); bool migrateTokensFromEVM(std::size_t mnview_ptr, TokenAmount old_amount, TokenAmount &new_amount); +bool isSkippedTx(std::array txHash); #endif // DEFI_FFI_FFIEXPORTS_H From 0e127033f59f05254f50991e00711d662d24299a Mon Sep 17 00:00:00 2001 From: canonbrother Date: Mon, 10 Jun 2024 17:45:11 +0800 Subject: [PATCH 102/185] fix split account by @ (#2934) --- lib/ain-ocean/src/api/pool_pair/service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index 59805da9439..157e423fe17 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -201,7 +201,7 @@ pub async fn get_total_liquidity_usd(ctx: &Arc, p: &PoolPairInfo) -> fn calculate_rewards(accounts: &[String], dfi_price_usdt: Decimal) -> Result { let rewards = accounts.iter().try_fold(dec!(0), |accumulate, account| { - let parts = account.split('-').collect::>(); + let parts = account.split('@').collect::>(); let [amount, token] = parts .as_slice() .try_into() From 86e1d432244895b8083fc6106cf20cea776a6160 Mon Sep 17 00:00:00 2001 From: jouzo Date: Mon, 10 Jun 2024 11:05:08 +0100 Subject: [PATCH 103/185] Ocean: Fix cli linking issue. Add rust native skipped_txs --- lib/Cargo.lock | 1 + lib/ain-dftx/Cargo.toml | 1 + lib/ain-dftx/src/lib.rs | 2 + lib/ain-dftx/src/skipped_tx.rs | 374 +++++++++++++++++++++++++++++++ lib/ain-ocean/src/bin/cli.rs | 15 +- lib/ain-ocean/src/indexer/mod.rs | 5 +- 6 files changed, 391 insertions(+), 7 deletions(-) create mode 100644 lib/ain-dftx/src/skipped_tx.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index e5a36c970b5..cf5b4eea18f 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -125,6 +125,7 @@ dependencies = [ "bitcoin", "bitflags 2.5.0", "hex", + "lazy_static", ] [[package]] diff --git a/lib/ain-dftx/Cargo.toml b/lib/ain-dftx/Cargo.toml index 8845dee779a..8c5ecffb35e 100644 --- a/lib/ain-dftx/Cargo.toml +++ b/lib/ain-dftx/Cargo.toml @@ -11,3 +11,4 @@ anyhow.workspace = true bitcoin.workspace = true hex.workspace = true bitflags = "2.4.1" +lazy_static.workspace = true diff --git a/lib/ain-dftx/src/lib.rs b/lib/ain-dftx/src/lib.rs index 8de5dbc801a..f647a3b40f4 100644 --- a/lib/ain-dftx/src/lib.rs +++ b/lib/ain-dftx/src/lib.rs @@ -1,4 +1,5 @@ pub mod custom_tx; +mod skipped_tx; pub mod types; pub use bitcoin::{ @@ -7,5 +8,6 @@ pub use bitcoin::{ }; pub use crate::types::*; +pub use skipped_tx::is_skipped_tx; pub const COIN: i64 = 100_000_000; diff --git a/lib/ain-dftx/src/skipped_tx.rs b/lib/ain-dftx/src/skipped_tx.rs new file mode 100644 index 00000000000..20f3196bfe2 --- /dev/null +++ b/lib/ain-dftx/src/skipped_tx.rs @@ -0,0 +1,374 @@ +use bitcoin::Txid; +use std::{collections::HashSet, str::FromStr}; + +lazy_static::lazy_static! { + static ref MAINNET_SKIPPED_TXS: HashSet = { + [ + "ffcafd71820269ffe9cbecc12619154a3c5b272f1437d4e0242ff73d2bf09e4e", + "4218d310d9a67b5e9a93d2a9ecf17bd70bda7a3670191efbc755b05c5fb8a6a4", + "e189126e56b85e66144c93b7c2d91baaa2680aed62fed09d3ea954a995d0a8d1", + "80c77656eaec77f893671e66bb2eefbbf73e141b65d8a5e1d151bc97fc9d2ef8", + "a49e34c38fd899bab21fbb01e0bf77df916648b972992bfbf2867fd040261097", + "fa28cb031aa4fdc88302e4c60f4abd9e3822bf5fc2e502fcd264b21b07b823f3", + "9436003f88a641fbaafc6e00fe1bfb2ddd4ca304b55d458f593300f9ca2d3285", + "31cc6209e24332464a7ac7adcfe93c247ca5a3c5b4f9acc340d133b158f95c39", + "5587a6da89e32ba21823f2b4d7cf6cf7f0e3ec4f1e1b286ca311fce0665941df", + "e80649287312ca0200fb057c1defa16015246164af690db9892c5c348b34c937", + "95b399d9fb1ef3b63a5e0f0071204f6046022df2be95849918093a52c35a0c78", + "d97aaefd4397824528132d91b9cab0e4c3abfc08c893be4cea02191cc18c5ded", + "985f8d38d9aa6160be02933d36b6683eb47ebe2d4a7735d068de37781e7c614d", + "35a07b93d238552a4f14294b7f791b2f8293a90ffe25344e55ef97a6008e07a0", + "28d7798ed6c3f7d2fbf4cdcd30aff42035c6a154514263ffacd92f7de5db96b2", + "0444d4825ee094e90ae94f88f19a5a0d1092fbb5d3d882a674ed07ccdb2eb1a7", + "96d86ce92175c714a544f8f45fca08cc17e2f72cf6352b9cd930f152965277e7", + "6f9c9383d72b4548c444ab7bd1159c70b62d16a34aeb49a84a646a35d30c726a", + "681cffe5fc82e2fd544f61050f95f3d8b489de56b4fb48edf72cb4bc5e77bc70", + "af7c6d1a872a5bfca3333b7eebf568091e4e471b81dd3f7bbc84e85ae5c480d8", + "ecf1564390f291f73e0e399aaaa1deeb4ea43cde7777d6435b29d65800fe68f8", + "dc554a7a4a29ad1023beff8e95d8b0d82adba69f5ee1332fd31312b49cc40c1c", + "6480180d1fe751aa650e60f2b6c57a2fea77c97d5e6e8e2ee1316aa5d6b03b88", + "009f8d084c01dfafb11ed86456629240ae71c0ca402f0c22e3b5ce59fa82d5e1", + "a50abd1cb347b5740f87baec6df029951bf45b2d21df3120d7e915ee1d1ff182", + "a87c7a281f4ac908caedbbd06111f4db7e2edae8a14a13b156458047b7747f86", + "2ea0780ee8e987d45dd01840214a3a1840d88029bd679f940b36c80efb91a207", + "cb28e755ff0e4590a6fd558129b5c61872da691140feced04d482b4c69eb344f", + "a5fbe7163536e87d91c36f45b0975542c45fad7284c62cb2592548662dfe3796", + "9c405cbed7db2d50e38592795f6fd5fd04923cf72b0cf601ef300547ff8adae0", + "aa57e4eeaaa603262b8f87284b7b396900c5572587b85795a62b5ccd43fcee44", + "4394684bfd9987f5321a3a32dae684aae76e7bd5949b360a1a0d70cbdf484ede", + "b77e714aea068a5cd9a29d428529476ec06f268efb6ef81592768f172140c00d", + "e8d67ff43e9316538cbae7c7328b0c8b5c9ffc20c7a727aed36d4d12d153de63", + "8b092dd476b64f39b8bbdaee14ddf762df9117dc73eb3315c7b3536e39d9cc68", + "7adc7c48e532fb00719346647d8125fc868699582c072fc92bd50f6e43ac4f52", + "db1b1175e41b998e44c7c6743661b0a80c1633419681ae4d4e5cfef5fd5c538a", + "60b3f187e94a003fb80bb13c6f4f13cea06eab3b2b353c282d0fba5317300eb1", + "1aec8a6c95012b57008cdac7d195bbfa2fd6d656a61039f7fcb60410fe201aa4", + "6c9e7811cb0445688bb596eaf2d217c307d76cb89b7346453d2a2807e7063eb4", + "386322e8dc69d8d27acbd0ac855485d1dbacdc41617c0d22e6ebc893fa31a9cd", + "4fa58b67d30847579414952e5ead0968f2318d8f39562e10fe5943ce31acb509", + "5529972027b390820bac87825d00c8021751bcb6982b42e5ad8afc7e7c1bd4d7", + "4e2170cb14a5aecec592166a8d550af22a0056706cf2b178edd9e01c8296ec66", + "4dc1deee1d1ab15c0d36515c34def7bbec08ab75bdc31b628353f72418e0413a", + "f6df01ac392911db4f7db20a36bdee8ff890e4cbb222308917cc85796ffef454", + "bf0010e6d193e7cfbbdc37ebabdd9a44392faa5f96e5056a64c5393d0cf35c57", + "d82a31354457546bd1f137bb969740d4f7e1b8c55eafbdb53668c94a59def865", + "fc2f320fbd1fe0fa9cee42d77916bcbbed99d708a6179d46fe824b7d81a7d640", + "bdcf70f61811407b1bece47c4d059c120f66271490b53cdaafa3969937d78fac", + "84b89b3ebb27f421f0fb5aca8cb278cb4e923c60a5a7663500abb5d28ed94078", + "f835245b51c96e7644a83e6cc25a97a01bf8937f8aaf07062922568df0ad5bf4", + "711aa9bfd5e257ed96737f443c81be2f11dc293d382db07052651af1e9b23c20", + "b235982686d53f7b3b320f82b9d2e0797a3e01118ce8eeecad001a36be86e71c", + "e5bbe632a8f2de73b69076fc52fd4d5c34ce2ebbd5b764f34c3630716dda81de", + "76a83f2249ce51e1a7bbaf5202b4d97d0b81444b1529fa8cb370dc3e804a7534", + "0801761fcfe11c6e5308988e451759ff2ffa785850a1b926beba59ccd395c4d6", + "d6683e99370460b684227a0e53d2808e28953c320f6dc727f5dccb310ce781c8", + "9d37c6e758035a8fb666862d1e386439c023b0ce287ffac0cc3f3c6d9276173b", + "0abc9dfde8b520373ed087d0e21587fcfde06099db2cb1397162c2aef7960a79", + "bf8ea24e8b67d6a8b54f38d98e3931dbeb2a28fe1175e441a4a6e1e75182b063", + "1b3e3a35fb203ddfdb59c234d11e4cdb2810358bc5d9b2f11347fe565d40dbc1", + "0ab0b76352e2d865761f4c53037041f33e1200183d55cdf6b09500d6f16b7329", + "c05c88e81acc4ceec896f023f881e3a2361168bc2c7d58c705b48c010a73e646", + "d00a428dab82dd77ad1cd98aff19c2bc3e8ea66c12bb69840c01c3d5a9efeffd", + "edc12f97ba7ef5adb5bfaa5bb23dd07845b0b82ae154114750d1f71097ec6d16", + "e19a5096afbaa2813537ba4f58a0ceea8f995384fd4e060bfd275eab5aeb7c8b", + "8c26822077d2067e4a1ddc1c60d63669c800167bff39d6125a359dbb49064a19", + "288d0b2f3b53f664c7767dbd5a74753fd3770f380c7cbf336c24ce3b7ecd60ee", + "75f08b3e30cd781acc0efeb785c37a3c95fc97e92429e84e8c8604dc356ee9e9", + "061a3d67ec232b0a2a7da96bffb33db75bfb8e2a99c4fccd1ed154c150e7e6ba", + "132f565363fb143d6d93386cacd23fcde80da586a1acad157821c4ef7d5404cf", + "fabb98a77e9918bc3a7eaf8dfeb9be868a21f800d5eb765ecbb6214dd3cac1c9", + "fa3e91f15bb99ff620301d0fd5f555bef82271098291f178318e39c7033d7000", + "d320ddf6a776c7c8519f894627a635b86f67712c1f556f4283e27bad1a0cd3c6", + "f7b010a21ea6e5a32b5dfb318df158423e386f5b6409ba3b39ef817fa3441c91", + "4ed05f0b57c558bd649b9cee5bf26b9d8287d0c9cf55b87fcd3734c7d15b71df", + "c26e803c660b8e75afb42e634ae98a8246b95d795f0e10706b9b446746aa65c3", + "256080dbcdd79384641daaf1acdc4d98ada2418e363b8dcf4ffe264f5a98f768", + "aa903d2a785e48d7d56cdb8cc045c7b217805ca8b39e75aeb92cf7d6d924bce6", + "509fee1659ab82b5a98b9c6172c4530cc5cedf0116e13d96de3a4cfa9138f352", + "820d04bdf2fe71ab37cdc3f2b9bd27329c39d0ecf17a01a4cbab145d65c673ce", + "b9c5bd0dcc52e8ab625122246b23f364d1816fdd725573f14f4e4c4b23d5aae9", + "d335014ef95af4c4b43560af2fbe6b7cb5cf7e418f33369de37f2d47ce14df14", + "5bdfabdb059e3d5990e7e34104bb75db2567b1c4e7e70947390ab2eea13a7b79", + "06582a883b4268ac889a88f4b118b7783be19d04955f73e4db3dedbf9e153da2", + "b400a43760311d5c5d5cff76697e409c1f93736a52b2fcfc040ec72102177669", + "43ce52b9cf9413d67833cf4ff218ed83f1577412b775e701de6c0a975877149d", + "70e28ab44d09d20186f5d687bab0aa96c5c50bc9fc4df49656717f9461f8293a", + "52a984f2e987775d1e6f573aa73b9fe29e3c53d99401b9252f47f3911a605835", + "1433fc1db5c6b3f06d547d49335d0001661219bb71a3ebdb946fcbc700cc9118", + "948e9ba6d053bfb6cd46f936e32ed68458cedb679a7ade9639c28fadb17894ee", + "df6570476da12df2b0c872842c4c6db8b14995153d8c82acf1defce526788391", + "01f90a6b8b32002198c31a2f1848594dc54936437391e708c7912229740c2ff7", + "99306b726f16b5d71bd5f119fc544e4fb048690215a61d95a6ad0bd6130cc8ab", + "eeed5a04aecf2eab3d25dfb36493f6658b16de92bc2a45a318d1cac9db0c49d6", + "18e806b716f96a85f897d5eeb884ce5ffe814f4f059c143856362670f98efbfd", + "1aa7f0435c287d1f7afb02418f0ec91a86cf7254b060dafbc721c3c2e84070ac", + "7a8ffa4da5d1c39d42d28d61b8936d345ccdec6f1c8941bf6cf8a072b745a8bf", + "d99d2dbc1a863b3635a41f5c2fb920a9bde40c316b5f2f339fb16837c2b2d2e3", + "2ac7800b0bfe2df8781e92f013f9f23b7ac6f37c5417054bc6f31fe845c4f2ad", + "dfc374165b8e4aad391cb3cb3572c483c813577804bdb702b011d93bb2ec9370", + "b7147548e97017123da2515b5ea350ba4a22ddd65942d0778500bd8cb6cb8899", + "588cc9c95b9f1ce65389b79d7da24c6f67e8651839073dd192528767be228bcf", + "9a1d9b9489ae66af0ab222dc688ae1c0888825def98ea8393f960213471c18e5", + "8ff534b441444245b891b7a6d0e412b190f2cef1b3c829c67748efdff62b88d8", + "8140dd3a265de4ac57500b00ca50685d1e77ad9647a3ae3bb1f494fadfe21e4b", + "29e7f896f333da8b06a9207948f28d4062d3050e9187ae34a98e53bc79e4d3e5", + "123ac611e350aa2cfe125c5817fc53fb01ef82653623137318d0d154981a8cd4", + "eb0522f3ef2b2c0dfb06089ad316fe15821d22fe39aafe1ab590a19c35b669ef", + "bd8fce56da2295796189408b4f45890dcb96354700668a03a83b9cd5f278a97c", + "3184a12cf00029214f37c836a93b829985419bc859e007e45f60837ac1ab143b", + "d6ff9862aa08900591e4d93aa59558c689b6f123ba2a49dc5bc396b2859eb1c7", + "d1e201c417fe9dd5d78a37f8177ac8aba2da52dc3e17cf9df81c74ee52ee4fa0", + "ffbee4e013aae65a27b93d3fd454e7ee1215d9ff0901c103ca02120083994ebf", + "5c31f86eeae9d06f181e524f9aa06b80ddb5424504ee45d6f516c91d9d2cf09e", + "3a7c04eba93a9be69dbfda3ff42a527424de34b9a8fdfa34452426c0df9ef7f8", + "5d5ad9adfe55114a4651a138d60e48f9e8a617b412525e72cc1bd3368ff9bbc3", + "03fa1265fb8b26b571baf6dd95c5018e4b05f69942889948045fc603761a5b3a", + "94707e6bf2e554f3ee3178f32cf1c7faa2b228e2f7f64638465f4f34b1688a5e", + "a371f737969d5721e815c5b8f462f178f0c1138894ae675fd27390f6a6915928", + "6478eaf3069bbd1c2352b9cb7d5d3316978dd56defc11df997542d88310969a0", + "ce2f2ecb4a7480acbb7ed40ea40a23906f5528dd52c6cd7ed43c8b557b228fa7", + "17a6e8df99fcaf396bf039f65dd2fad80d95493a6f77a22087a29eba2238f1fb", + "ef3f52c7d4470093959c2cc206d5ec3e429cda400263b7e129a8eaaeb17dba7d", + "5c34c639ba7bf651fb6ed2482f4d3f4f7da3241f6700606d4b5ad4584d989ce8", + "7adbe577fc9f076bb42fc6d1e868d5ed92e67657babef2f2da0fdc8c793ee2df", + "f426daa5da12162431328007d86c63695f7d21e89d66bb6d32b850df58fbada9", + "812bcc962b5169fe46db31b36b9e91ccb018f7089b9e3e5aeba589dde0b0bab0", + "fb6557bfe280cede8b5d4e1ae65838da70f36ab73862fffe16e567fbdb91b42b", + "7d1878abb072569a0c9be0874de4aa12476f47be3441004af75e563dfd575d8f", + "e9f10e2e06287c15291bf44ec3885ecf01c8412ff4ef7c0486688d5314c2feec", + "d6353ab7516fbeb9acb10b420e62a3465da8d5f59061e0985f0eb7a6b7598e2c", + "875a7a81bae526732cef14bd8a6ee550009dd6f90cd5220a747cd2b8c575ec8a", + "2f8cb458f888ba9986d527d49f8d39f781004faa6aa85593cb5e7cb1defa12f5", + "beff4e88f527995dfaf9fbf3bd49a90a1c6463fd5a90a9fdf78bac2811047df3", + "06ecbca73dfedf0cb235d370e1a427b8fa0cc2bef922d06df5cbd50b589f992b", + "5083598634a96a755b0d103b936470c2786e0c29f9ff42cd8f3cdae3c61528cb", + "277bfe059dcd5f3f4a348b0d3074a91df25974ca1018aaa944bbe339ce05b969", + "5af51fb4aae0a9ecca7a5065c132c1a9d4d328b73eddcd7cd447ef362b84da70", + "157a14f72f2f109a182fec8ed951740218ae26d3a01c0c2240f2e7eccab9999e", + "95de81aeb5440c1d7131a1ad73f17380049f02d9f554f95cb6b58a1214f4ea4e", + "92cbb8851b926c043c2de871301d6c3b7a704ce5a38b345c508e249964d7dfed", + "1a4cf7a044a77a2b13f805afaa676fd8e5495f06cd64e91ea7b022df1c04a820", + "50c55370521bc26feaaf8a6e4586c4fe69cffefe275b70ebc06019f589ab1bea", + "1a98f0e894f6e67880745e4f3479b5394d3ff52ec4b2f352c31f3ec1d96ca537", + "09f8a8bd29a1fb018e5ad5220604ce27ede3b39b6e445b3a1a9bb4f7db6d6f7a", + "e7edd6749d757fdd249b73df3869aab32b65ec14ad881637c3342c855861c59e", + "3adc8cdfecbd3beb91f8b491cd188a021b2e7ed21b5d0356a5a1d3b3cc27f6fa", + "978045603a6de7dbb184d9a382dd2d28d8317f4ecf5b5cd963b8ce4031c6c3cb", + "ed1d1e8f48d5bc1fe4c01ea822d83b3eac7d831cfd36b2a5aaa990a59558ef95", + "63999cc3e7b792bd4b67881d033b6cb7a6bed9527d52feb7ce1472f0727f6fd0", + "03fd7081c9cf4d64e411bd5fb28126846a51824c9d09c88594bcc3f78e9b3592", + "9be31bb296af4b7707ad5b6b5e1633103cb1fc9dfc7f72e1c441456416e9343c", + "aedd9d98046589bf65eecf5e50a36edf0460966384e25976a541acbfa566caa8", + "219795ea1ad60c6756122605162ffc296375ecf4e819c19d3bef9c05563dd2ef", + "829286014c009a0019db9dada32abf06cb46f9add37de7f19cd10a1f864968b8", + "94ad5ff7a9594ab49aa5935ca9027d76e945e0a5b8a807248ae688b5a2d64343", + "cad0e3a95673aec32f0dc003f14c81be366e8c996f55ea9810a1ac32c99440c6", + "622209d0116ec3b96de970d1a518030f5b42680190ccb12888c9cac62cd5b984", + "95e1893be196cadd0ff74348d13d0b264297425076dfebd42bac6f4448d76b83", + "4b9233212376ae74576641939cdd32577b8a982b4e7612ff83218996207c461c", + "c5dd2b39accd01a6a94ea220c7774982b5b299a8c181cda755ea001baf733342", + "c6d65947caeee0616a2f07bed8e8037c2e5707d6962a0017585f588e0d1fceaa", + "1856799bff3fb09ff5f15048f0750c81db025b8719a7292f7aeaeb47ebe28d52", + "ea25bd807290b1fe569bca2b332faa60e7b4ed96fa7389d2a6a124f7bfb512dc", + "d78f7f438bc4f2a8ceacec17329b4a48103ea49252150cba641d9acdb4d6f4b1", + "c6c422fdc2b22b8a540b56404b0fea444e9ba9510556f2520d7c3bb6301a27ab", + "ca5d755250e6e21fa19a40378318c4fc1e8214b46807dee5167a5a0d08237f76", + "8bfce5e34e5377e484854ccb7d782a0425f4251fc197a788bfb50a749098e0da", + "38d6f1edb5d1ffd9dc4f016f3a8de96ca7479a79b5085ecacb7944aefb65ab87", + "df92287851ad5b344963677d506557e71effcca6795cee74e8a8cf0025e7c40c", + "40e831325e39b725c6ce398c590eedaa91d4e41736bfe5a9e45f6d41bc0bfacb", + "96a9bb1896fccc97fb06400128a25b6e93d8fc47ba538963599421cdca20e08d", + "2d543b981b45b9c63296a15acf5ce967fa5972dab279a9048ce2b9a72658f5a8", + "36c4e9e7773454bd92eaff36d077e5da07a610a4ab3f89b5d2e73dde1eab729b", + "78ed73b0370fdf229c2c6feb8eb9c8401e73e861b76065200cc0c7a2d98ff2e2", + "d155250a08ccc1e0799b175e2ccf2a1f7c0cb670b57962aacf1092c7101ec7e6", + "e0078962a2d434ef3fd3631584a19553809de6aab3329b86924e1c01014293f6", + "eff1e9fcc6d1f5766427a1581724649dd9ab480f0aede615b02cfb8b76a9ac76", + "908773fe4b11284c0e2dc64ad0dd343e32c72affebd49cfe36f1db7ac17c85d6", + "de8aae7fcdef1b4edef0c348f3a65d24219194bc56681d71846cf5716b30a9f5", + "35978e45b2a870b85976e4f556db8996d02b203fe4d5770ca9862fda96b168ce", + "ab17ef14546a3d0eadaefdbf51c9368d5673de44b5541638506169ccb966044d", + "4db941d19688e2c539687b7ea45b84dfda212f98e33d44ca0d4298acc637938e", + "461b21ba1ac8a231bc6f0e0d0c5af8fecc9d4c3177a1abb03e7456bbb16a1f88", + "1dc9821a64325a77fa0a561e33a66cd162b302c43290266a329f3825a426d7c5", + "0cedc6ff163ff1f37e6d6090971fa97b7a84764e4cc419f860494bcf3dc64332", + "8a329c4ed566f5599090e359c3eb6d8862232d3fea3407ad81c6bbf50a2bf1a6", + "93fa0c70d4617331e8453fe593add9247cd183901038207a5bf4d20df70c78ca", + "b587f2d5c377f440ddc2be3c3671108d6eb0a0fb446877859007401ac0b2abf6", + "2c5fb421f908ac47ac166d9f1cc953668190a833c8809ee1cd447da1233dd7fd", + "10bc24c667d06f94b2634b41e03e7f1a3d7f5c4934df8c191090378970b6dc3f", + "27c31a3ae3c4246b8d940f107d70a374154906203b37dddd65779e17dde505ad", + "361a4b3043695ec2be73d1120c3614376ccd0aba128bfc9a940638cfee9a9b23", + "f6335610dce1ff2e8ea7769768469f99d31981b92cf9c9af130c267a6856eb75", + "e1b480d98cdf41ea694b792eb94039ebe2ba6343597f2cb691c261c0ec4679d2", + "b20892a7530c6da1e9835f23f9ca51351b412e39badc81189ec99cb8230f8ad2", + "7a0a32f122c470b5f0932abde695a24f5ecbe7b74f9bb2b77bb7dcc1ac408cf6", + "f3c7815a2bee014903640767e1bdbc02d99000b61d5a42f3b8fc589aa05e7888", + "929c05d2684fa8e26e0ac2c3c5ac2e5657f60c7567f887f674e7b41aa2cfab80", + "4cb8b86a4e8c60a227cdc0a3b43271c9e181e79d9f4193117f09aeb65e0d1c29", + "8e958e4288e6f7fa47a36ced20f0fd5d89592321fc4f97b01e89d08086628ccc", + "33f740882d3f5d9e2afd027958dbd8b32032e04adb4ae596e07390125158f3d3", + "63211da6fd4b4e8ff533ce44edf6ada47ffb21d047a4033e4504fa34341798ca", + "e256170cb22cfedad942b8008aedd15dd7a84927137af51aff313ec28b9b1bf8", + "b4ae94a0098b7c32f29d7aaf3411d05cc9411ff9f64dbdd2b75d46dd54b3e1f1", + "c91b4759aad11edd22bf8e46ff9a23149be8d5084c0b2012e88c2aa796a824e2", + "a7f91cd66f653bb01b93139e8b34143164ef7b8c5600a571c1140a12580d3967", + "fd00d352ba385f9e593a1282c6fb62582e55f5f8d3303fd7888ab85fb3716eeb", + "19ed20cf54db296060368bda5ac4ae58e1470b9b90c565e95329ad289cc69fa5", + "ed91a663c19bc1f74f465f26717bdf3671cf02036f6d1f5ef45964483ab746e6", + "b7dfedfcee131def65c51aed3bdf27d1cd075fc53ce57759c8441353250c36f0", + "57c855ab849e7371e968437e94948d2881c38ed8616c336e0d9782c54e955a71", + "bb86c0621b2a056ad909d4ae8d3f8ad4f48791820b76234fed000aa3d19d93f2", + "e2bbeb69cf34ad45c67db09dcf74c7d45c02e51982dddfb661edbde5e796f29f", + "a8cb070f17d22587103416527404ba4a4a7e65e73b4de34fe7419e295e203344", + "f54e138ec0392f42e036a944a8530e6855e710d6449145afe08669803287d3fb", + "a9a0c1df293972d5e9a6542d8e8faa9161255f0b79e0956b02ecb057fd47bf48", + "4a4983ac422bce3ada4d528a8caf3a86b2691d56964489c14236aff7d6203db7", + "c4b684815bf64df9806307699619c6179afcf6124a4edbcd1a1616fe80a45def", + "4d1c5585299c93e27bd8a9daaa70c4f0d73c567fc09611a67d01a795bae67dae", + "75c4e427dc68b13b24e1d944f7192995bf64f31d6d54416c4c7388527e79ffe2", + "3f658e7312e33eae2fbf13aaf40289363397db9fee494dab4c6873db7ff52fdd", + "9d3445a8144c662c45617a2419234ffad8fac12fc16331659bb828e6600d4af0", + "722eef4ac927c70886414c221eb51e737b3dd8280762e0fe8c246f1d0bcc20d1", + "9f08929babed6484acfe78cbb3ca1443ef7ee24b08b76f7eacf13ff87a14a9a3", + "2ac642d59056d6a84ddaf8ebbb057d2a21e39792aec3cde95f57a604c940838f", + "9cced3a84b6ddae3f016e144f3708f4821eaf620c29bf42ca8203ddbf971049b", + "b340faa755f66bc5726c09e7a7f9810db07a307ec6ebd3c01d39582ea306ae20", + "84b536d7ce03eec38ef3d52d5799ca6b84778b3a558d3090d745f62369eaa7a7", + "2b81ec9f2a03d5a40f125a6b7f725370bcb50254185c7563103a5a61030c3927", + "53933f73b4ca96510db7cfceddb3cb98447dca20fb4fd2d3ea8fbd05dcfdddc5", + "c287fe6d2586ddce466e7ff59cb0b8205fe734401cf42aa93cd5257ad51439f7", + "60b1592300b31f11b05b73aeb1b77887ac9a2f24bb94d0ed5c18cab770eb8100", + "faa830e9a8baee6660a8db62d05a34996e48beb748428bd2a004b5e17d896cce", + "c152ce2b46b5e49508dc18938c2b8a575b3e001fa4397f13ea65554ca6f3a3d3", + "cdfa1ad30596b60ab3f8a4fdb931530d1a96b9a176323d969d519ea7636b678d", + "bf23fb3cd240215ca03e8d732ebfd9c4414d9da57aadadb2a60ae49ab4d3b35e", + "22f644f1f763bb17aa11f3f3d23a5f41b501862941d9c2838c54d6f5ada7faf6", + "7a41a5337902fd5fc0eb97fc7e75aca7f8dff38bc10a36c90f859f710d6e4a36", + "957835f7767f2580d340c4039b2d1144993b9bd908be62db7c9cb80291f215c2", + "cf3bf007426b200e1315fb650d6c8fcc544db1efe7723f5cba940c0c3fe4e9a4", + "75d368aa68cb05409c46640938bc18e825b70ea7047481b6f03da5a6a7cbcc1b", + "667ae4748eb46489dcda951c3d6dde00e6cf47cbb5b42f38ee772e480dfc567c", + "3bfdbfe217b0aabeef2915a0915e47f6a09c28022c134bf29a0082935d7c4432", + "8625b04ebe9e444f5a90d83ac8fd27c119756ad9f120984b8f06c92839e57bde", + "79276bbe931838786f0c5eb1c4480e8418e4537e2968f41b1f18a094cc06631a", + "be8083239c54aa5c421ca3da87a51837fd2c9e65b0be084b80c9ac72ea53a57f", + "966f3a7b327614fb89c64204c79ef35a3246bfe8f5e44fb4b8da859d44f03dd3", + "2a217ed1d535b5de810784af9640c66756ff819444eb8fa8a802b6399397dae9", + "ad0c940caff402378d73eeacf7b55c05fc37804185c56ad1bb103aa21d29f85a", + "6a5fe7712d01fd99ea0a50fb66a8610993ab7eeaaae3f9fa190409bd07557a56", + "994205f817be06676c32b84d2fead2f60be8f622b3bd0e9e7869bec972994fd5", + "432fbb3913bb16ce8479cca0e01fa97a3c04eae617735dbbb48c70a9d9faa0be", + "343782f7647b1117f531832d1533e39ea564a7cb3cb86196430b16a863e154b1", + "3140c8d7d29b4b75973d12c4d10b4a6e44c3e533ae8ab08c16a79703bd08ea8f", + "2987cff1bf6b28603610e45cbc52213630e9ca4622945783d3187b961d8ae87f", + "7a2941df71dd3d5215c31444924ed412d3401a1c2053ecdbf75692a789447e8b", + "d5754cc668e6e05548dee85dd9908fb36b48fbe446276f281fa7c37363aa42d8", + "0491bdd1148c092ea1be94806c72217321dd4d7902ea4adf4106814ff32f098a", + "9ce7bd10d5eabe9db99472f1e4a0f1c0a4a3a1411f7e195bf269d4a3b30680ed", + "4f5a896678477391b3ff5ab74980a05aba7ca00430b0d9045024d66fc6aeedad", + "67aa62e5bcd4c205444e141379ac3a2e7ceb1ac36a5ec50d5cc02ab193d3426c", + "0c4296687f5a2f6664579adb4afb106ba47ff915e2b63fe935f44d0dc9a25edd", + "cee5e6eb2909701a0288151739fde30e0a2723b18ccd59aa7db5afd25a60d5a2", + "c0468d09d74a0fb30ce5dfda7c53866e33e3e457ad742fca33807e37a1d27d0d", + "0ef807072182cc5f030c3fab2be14b00bee1edbe9c7e5cb358b1126347fe1aaf", + "d42c3c7c4bc3d7dfa80d1df4aa110368e6592254e6e6753bfa27a590b1374984", + "8380fc35c16081ffbb6a023c989a9ad4d9644de4c8073d39e5d43b479f96e2cb", + "444dd409031ddfa0b3ffcf92bee7e9f08bda1b9c193a755cdfc3954878d715d8", + "a29a64be3e5f6948b1fea4fcf5d7d4ffd418b0dd18419536f453d95e79bd919c", + "a27765c77fd9511f89728c7099c563c7da1ffba7e42c1ae674aae82985804721", + "28d0d8925ad4b4df33a2fc7f6f21e39873a8f9d76a9a636ed2ad327259f7e5fc", + "48b2c6ad69a190a2d95b22a2169f768502f15c936ba06f748e9777b8086a8963", + "6182bb04e8eb98b629378998e01fa8c47629f27f134e14d7397efda6c74f88ac", + "ae40b0bd14003a588df523c2837f0b05a4e0cc8157be010e4109b7526b34dd95", + "34de8bdb2b03958ef3d81a744db7aa3f7f95cd112d0f53d63143f45f6de8bfe4", + "23b55d16e7c48d0502d428e07574ff7ea928e44bf1442bca732b5927db2370a5", + "9008838391ee77748d96ceebce05b02182aba985963a461f985d34ebefc0e9b8", + "40d860046e0ac1163ce27af02fcf5b2280f7dbfb23eec29300d2ba4b9c9c693b", + "a638f5c833734bd1a185c613c1559a5bb87b62dee5a4ada713a7e8c48bb39930", + "e31a5f0e938b587742348ff003fe635e31f6113030d9e8f30d4e22ddc89144cd", + "5cf6572465f3cfe67cb431e588cc4246f79f245001188dda15c4d85b4801321d", + "6dc0bf6130add1e40bfe6311951a1a2fe602c8796d234a86b6aff4985ee27feb", + "8a3b3dbcc386361f76841bbcdead026afa2a6c568e8e97c156fb849b6a465dc4", + "320daeb9ccea9f34ee629136fbd55b07f222b9b3ce1f94987a7e20fed17206e5", + "2f49861cd2e01b26c5a84ce4cee2438327761afee50a48c89d6d7b49018b7fcf", + "e69c8cf076852b36e45e5be83218a3accf29094e4e9895b36aa56f9a10d284b4", + "a8566fa6c2fec3f79f2611c1db9dbb25b856fedc9b3856008397b0f0178778b1", + "b9200a2a81d114b953e3563d9856822753ba4b7703943b0df920352e4ad300d4", + "31e319dcc4c3ec0f089e371d39a790b7e967896917c26926aac256954cbc52f9", + "fbd3031cef8c0c8330f83153e9753313edfb899a170c20531d06ea9a45217856", + "e563c3665885e9254e14440b42e3c2bf0eae51180571c3e2a2f8c99bc8a8fd83", + "07288958348e0cc68880849818d806834e84b6541a622d1e952ed0a85efa2d98", + "1fcd0987e064964e8796c3e297d6b8d6477ccca8dd37175bf3d0935161baf2b6", + "df3f905163ab3d87e9867b18dec20fdc7301e1312761470fe7827f3c7a3db96a", + "9de32735e458f45ebdcbb307321f693781b3f005cc375570ba5eb9bdad3cafb6", + "a7fbca77957e7ae4b135dc04daced4b319bfe100bdb612b0d6c8fe330ca876c8", + "9b2e6addb9131b2aa8d9d01bb4a3684a9980fa59ef8eb6ddbf9c8804b041f4ce", + "a9481433389c5a2acdcab26e600e500c3709249dc14c01b7025de2719fdb68e2", + "09dcb87aaca6537622c5c8125f39df290bd8343cd89b4c497046992634c147da", + "537102a29f389fca9edf41239c62b332fe92a71527588182e893d46b5f2ae7cc", + "c004039ccbe8bfa4625372d3c9754eb16e814a2a370c7e8bdf6021aeb9633963", + "b1186a4e8caea3d1d0c06f4c00ee9fa386ae3f3b8a8dd92d1adae8aaf6462b1f", + "88f4aca157bee6712046cf5efee0dec950c966ac32e68c4e51328411f48ddc42", + "1e2688c6aff721fde920d60a838b5462dd4447e251581e7ca97a4fd7564be63a", + "e716d47275fcec2ca23863880f9c21ff53fe74a87c30c23943e2b1b468352566", + "ea0ee24c027c79c5a9fd9b47ae556e6aaddfe2b97e00fd855e91aee45cd064fd", + "b7adfa74a8d03dc963202c231fa527ea6f9168afa6b6f0c8cc4fe0ec0f7baacd", + "3807d25698eed478f6802982ad5bdbee3083bfa07253305f96e76bea6d9f5d7c", + "9d04e40577c3ac00b0f66f4cbba694f01ddb0e56ca303160a8acce6b649675d3", + "2c47612ef589a6f2b82ce23672f581aecb065640201df8d02a185e2de15635d0", + "adf24254e91a47236003315e0b8c25fa5f86d5bbe5d35bd083a488e2b89a8c7a", + "cca693215a23955ee155ff41fa4027523b05dd2e1afade1878ab171daed11078", + "8692daae3b0608de881e01c86d8c1e45cba1f32996869ce8e6cf3b8f793a41f0", + "398f15b36141ed45f0724b8e1060d3a67f28e4d99ae2c064d4d0fa8e8c720bf7", + "d570289b50e3e8f57e70ed955b7b87992ffdb16f3bc4908a9a9425d0210a14d8", + "5ae446d92abc358e0077b932494baf9983a31a27f548268390a2094e98985222", + "16f423a7835fe2e2cfb869494e5bd43b25660452f62b377b69884a28b5a323c8", + "88331376b5428f50a91b84af5edf56e438e59ebd2a83cd840c20f0ff966fbfff", + "af9d12d94e4c3ae112f5cabeba7f6eba5105e1ba2c4f71f4fd90cb0f3f671ebc", + "a3debcaa4d4b6d950822b0fb612a436278d23b305128972e9737aac0c703097f", + "03753f72efd39aec75a3840a4acef16830ff9d25f41ddbc6d13c1dbf5cdb71ef", + "17f1ae9c3247e556215929dcb383ba18aaac2ae9b6f3784ea7d738beff46cce5", + "a0c43101293a4183f74a575b10384341e9a3e5106c21e3882dd42ba792f6beb6", + "dccf54f2eb6e441304cbc4ceb659b936cd36fa75c70609bf31a4287b40d0df8a", + "e9c9204781d9bf34edcd52eb222ae469f310c37b45e9d6b8e86017a81b54a889", + "9f84dc532aef6865b04161a61bcaaa0371ccb22db5e92366f314e67d46b020ef", + "e282255e252194f1fe94ea32e063020ad0ed7471ba3d959d71841251f545ec50", + "8ee17d97bc69a166939da3a10815d207843861c949a64795a276b3b7e6d76cee", + "51792977284ef54f288a9cb144ed0b0dab129146c5206e7c56c3e5b94058b1ba", + "63c8831e07ce87543117ab11e4fda4ac7d10dcb2dbe0ed9a69e0035c3f010ded", + "bc87d9b6d2dcd9d2ac6e86aacc394853f349214ba910d63588924232088d7a53", + "ad9b8e4446a0326cea32e64346803c15595cdaa7eb48660b981db6ef3eafd168", + "2e724245446b50e8e94adb0c7d6dac108324c7063646a07080c670e0842291f1", + "938628f96d7e1bf5fada66b1681c8cf3731463451a66a9a792e099ca09f59910", + "58484171dbe293667f81b76c6f0d493928a92543bf46076cc62de3d0d1ce02cf", + "0863180da779d530ff5184908bc1ddd85910a5c643d1317fe0f3796f47eba414", + "27273069347a23a4e5fee10346ab67813f99b8e09c3d31d4b1c4384fa6bed588", + "f872f706976de4ebf97429946b83d7c1e0480496f26442d4253440a0f462ba82", + "949c7243483d52b85e6ef058fe8814b5fd6b307a529fd34c07daa8eae5759770", + "7a1001461506e3b5a4de3c3de74a1a838ab6b6d1530042ff9bd802e6bda90e91" + ].into_iter().map(Txid::from_str).map(Result::unwrap).collect() + }; + + static ref TESTNET_SKIPPED_TXS: HashSet = { + [ + "6c8eaa51142b069305e07aea0ee247a467f1fc7d1378428005b8034e069e8cda", + "9dbd8e2f2f331e0d314968baedaf49065e45fbd0316c95e8e1e02548437a76f4", + "4f5f620484e5359eafb9fe799b568a59ca75202bfe6aa1546c54820c99889437", + "b22fca714f70f68e45bef2babc5d7f0a1c81fd892ddfd347edb43cc80fc31db2", + "08e864402d066cb7e0f65f587c2450c03f982f04b06728f455df0930a1f062dc", + "a20faada80dc028a821cf5c3889071442fe7d5f1487e669e907512f060da86e7", + "97cb98df139d608a79e277fe6edd4439867be032aa6463c13cab18de12632db3", + "b90b85e05f58d73d339be4563bcbf6c9fd041a1ddf175538135fae96937453df", + "af264140932d5ec7049639ae1d8d3453a307d6ed3272a7d12ead4d09370cca9c", + "a65a1c2e37461c01e19f99675e448eb23b64d0dd1234547a30b45ebf5e9e7ba2", + "dfd54905c6a323d92fd923a2fcc592e005fa8488e2f3774cb585f7fd33068433", + "f5166734c9fe55d46325c2406454daddc698ff9d76491dff8e6553027d53878f", + "e30ad732c4ec80946a9aef649e3eef521bf408f29539c0ff254b67272cc908ea" + ].into_iter().map(Txid::from_str).map(Result::unwrap).collect() + }; +} + +pub fn is_skipped_tx(tx: &Txid) -> bool { + MAINNET_SKIPPED_TXS.contains(tx) || TESTNET_SKIPPED_TXS.contains(tx) +} diff --git a/lib/ain-ocean/src/bin/cli.rs b/lib/ain-ocean/src/bin/cli.rs index 8604e28608e..8e845c7370a 100644 --- a/lib/ain-ocean/src/bin/cli.rs +++ b/lib/ain-ocean/src/bin/cli.rs @@ -1,4 +1,10 @@ -use std::{net::SocketAddr, path::PathBuf, sync::Arc, time::Instant}; +use std::{ + net::SocketAddr, + path::PathBuf, + sync::Arc, + thread, + time::{Duration, Instant}, +}; use ain_ocean::{ index_block, network::Network, storage::ocean_store::OceanStore, PoolCreationHeight, Result, @@ -29,6 +35,7 @@ struct Cli { /// Sets the RPC password #[arg(long, value_name = "PASSWORD")] pass: String, + /// Sets the bind address for the TCP listener #[arg(long, value_name = "BINDADDRESS", default_value = "0.0.0.0:3002")] bind_address: SocketAddr, @@ -74,7 +81,7 @@ async fn main() -> Result<()> { .get_highest()? .map_or(0, |b| b.height); let new_height = highest_block + 1; - println!("Processed height in {:?}", new_height); + println!("Current indexed height {new_height}"); let hash = if let Some(hash) = next_block_hash { hash } else { @@ -83,7 +90,7 @@ async fn main() -> Result<()> { Err(e) => { println!("e : {:?}", e); // Out of range, sleep for 10s - std::thread::sleep(std::time::Duration::from_millis(10000)); + thread::sleep(Duration::from_millis(10000)); continue; } } @@ -92,7 +99,7 @@ async fn main() -> Result<()> { Err(e) => { println!("e : {:?}", e); // Error getting block, sleep for 30s - std::thread::sleep(std::time::Duration::from_millis(30000)); + thread::sleep(Duration::from_millis(30000)); continue; } Ok(GetBlockResult::Full(block)) => block, diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 44d6dce6235..e607f5d7f4d 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -9,8 +9,7 @@ pub mod tx_result; use std::{sync::Arc, time::Instant}; -use ain_dftx::{deserialize, DfTx, Stack}; -use bitcoin::hashes::Hash; +use ain_dftx::{deserialize, is_skipped_tx, DfTx, Stack}; use defichain_rpc::json::blockchain::{Block, Transaction}; use log::debug; pub use pool::{PoolSwapAggregatedInterval, AGGREGATED_INTERVALS}; @@ -134,7 +133,7 @@ pub fn index_block( index_block_start(services, &block, pools)?; for (tx_idx, tx) in block.tx.into_iter().enumerate() { - if ain_cpp_imports::is_skipped_tx(tx.txid.to_raw_hash().to_byte_array()) { + if is_skipped_tx(&tx.txid) { continue; } From 0d733d0e1cb8ca32150cecb2c793b330d54621d9 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Tue, 11 Jun 2024 17:30:50 +0800 Subject: [PATCH 104/185] Ocean: poolswap fallback handling (#2932) * handle compositeswap empty pools * fmt * fallback * fmt --- lib/ain-ocean/src/api/common.rs | 7 + lib/ain-ocean/src/api/pool_pair/mod.rs | 22 +-- lib/ain-ocean/src/api/pool_pair/service.rs | 170 +++++++++------------ lib/ain-ocean/src/bin/cli.rs | 13 +- lib/ain-ocean/src/indexer/mod.rs | 12 +- lib/ain-ocean/src/indexer/pool.rs | 113 +++++++++++--- lib/ain-ocean/src/model/poolswap.rs | 4 +- lib/ain-rs-exports/src/lib.rs | 2 + lib/ain-rs-exports/src/ocean.rs | 2 + src/dfi/validation.cpp | 7 +- src/init.cpp | 7 +- 11 files changed, 216 insertions(+), 143 deletions(-) diff --git a/lib/ain-ocean/src/api/common.rs b/lib/ain-ocean/src/api/common.rs index 8bb6293655d..c7653de0df0 100644 --- a/lib/ain-ocean/src/api/common.rs +++ b/lib/ain-ocean/src/api/common.rs @@ -1,3 +1,4 @@ +use bitcoin::{Address, Network, ScriptBuf}; use defichain_rpc::json::token::TokenInfo; use rust_decimal::Decimal; use rust_decimal_macros::dec; @@ -39,6 +40,12 @@ pub fn format_number(v: Decimal) -> String { } } +pub fn from_script(script: ScriptBuf, network: Network) -> crate::Result { + let script = script.as_script(); + let address = Address::from_script(script, network)?.to_string(); + Ok(address) +} + /// Finds the balance of a specified token symbol within a list of token strings. /// /// This function iterates through a vector of token strings, where each string diff --git a/lib/ain-ocean/src/api/pool_pair/mod.rs b/lib/ain-ocean/src/api/pool_pair/mod.rs index b2208f69171..864936bdc8e 100644 --- a/lib/ain-ocean/src/api/pool_pair/mod.rs +++ b/lib/ain-ocean/src/api/pool_pair/mod.rs @@ -24,8 +24,8 @@ use serde::{Deserialize, Serialize}; use serde_json::json; use serde_with::skip_serializing_none; use service::{ - check_swap_type, find_swap_from_to, get_aggregated_in_usd, get_apr, get_total_liquidity_usd, - get_usd_volume, PoolPairVolumeResponse, PoolSwapFromTo, PoolSwapFromToData, SwapType, + check_swap_type, find_swap_from, find_swap_to, get_aggregated_in_usd, get_apr, + get_total_liquidity_usd, get_usd_volume, PoolPairVolumeResponse, PoolSwapFromToData, SwapType, }; use super::{ @@ -84,7 +84,12 @@ pub struct PoolSwapVerboseResponse { } impl PoolSwapVerboseResponse { - fn map(v: PoolSwap, from_to: Option, swap_type: Option) -> Self { + fn map( + v: PoolSwap, + from: Option, + to: Option, + swap_type: Option, + ) -> Self { Self { id: v.id, sort: v.sort, @@ -93,8 +98,8 @@ impl PoolSwapVerboseResponse { pool_pair_id: v.pool_id.to_string(), from_amount: Decimal::new(v.from_amount, 8).to_string(), from_token_id: v.from_token_id, - from: from_to.clone().and_then(|item| item.from), - to: from_to.and_then(|item| item.to), + from, + to, block: v.block, r#type: swap_type, } @@ -454,13 +459,12 @@ async fn list_pool_swaps_verbose( }) .map(|item| async { let (_, swap) = item?; - let from_to = - find_swap_from_to(&ctx, swap.block.height, swap.txid, swap.txno.try_into()?) - .await?; + let from = find_swap_from(&ctx, swap.clone()).await?; + let to = find_swap_to(&ctx, swap.clone()).await?; let swap_type = check_swap_type(&ctx, swap.clone()).await?; - let res = PoolSwapVerboseResponse::map(swap, from_to, swap_type); + let res = PoolSwapVerboseResponse::map(swap, from, to, swap_type); Ok::(res) }) .collect::>(); diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index 157e423fe17..4edd18f9c58 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -1,11 +1,8 @@ use std::{collections::HashMap, str::FromStr, sync::Arc}; use anyhow::{format_err, Context}; -use bitcoin::{Address, Txid}; -use defichain_rpc::{ - json::{account::AccountHistory, poolpair::PoolPairInfo}, - AccountRPC, BlockchainRPC, -}; +use bitcoin::Txid; +use defichain_rpc::{json::poolpair::PoolPairInfo, AccountRPC, BlockchainRPC}; use rust_decimal::{prelude::FromPrimitive, Decimal}; use rust_decimal_macros::dec; use serde::{Deserialize, Serialize}; @@ -14,21 +11,17 @@ use super::{AppContext, PoolPairAprResponse}; use crate::{ api::{ cache::{get_gov_cached, get_pool_pair_cached, get_token_cached}, - common::parse_display_symbol, + common::{from_script, parse_display_symbol}, pool_pair::path::{get_best_path, BestSwapPathResponse}, }, error::{Error, NotFoundKind}, indexer::PoolSwapAggregatedInterval, - model::PoolSwapAggregatedAggregated, + model::{BlockContext, PoolSwapAggregatedAggregated}, repository::{RepositoryOps, SecondaryIndex}, storage::SortOrder, Result, }; -use ain_dftx::{ - deserialize, - pool::{CompositeSwap, PoolSwap}, - DfTx, Stack, -}; +use ain_dftx::{deserialize, pool::CompositeSwap, DfTx, Stack}; #[allow(clippy::upper_case_acronyms)] #[derive(Serialize, Deserialize, Debug, Clone)] @@ -607,30 +600,85 @@ fn find_composite_swap_dftx(ctx: &Arc, txid: Txid) -> Result Some(data), _ => None, }; + // let pool_swap_dftx = match dftx { + // DfTx::PoolSwap(data) => Some(data), + // DfTx::CompositeSwap(data) => Some(data.pool_swap), + // _ => None, + // };; Ok(composite_swap_dftx) } -fn find_pool_swap_dftx(ctx: &Arc, txid: Txid) -> Result> { - let dftx = call_dftx(ctx, txid)?; - if dftx.is_none() { +pub async fn find_swap_from( + ctx: &Arc, + swap: crate::model::PoolSwap, +) -> Result> { + let crate::model::PoolSwap { + from, + from_amount, + from_token_id, + .. + } = swap; + let from_address = from_script(from, ctx.network.into())?; + + let from_token = get_token_cached(ctx, &from_token_id.to_string()).await?; + if from_token.is_none() { return Ok(None); } - let dftx = dftx.unwrap(); - let pool_swap_dftx = match dftx { - DfTx::PoolSwap(data) => Some(data), - DfTx::CompositeSwap(data) => Some(data.pool_swap), - _ => None, - }; + let (_, from_token) = from_token.unwrap(); - Ok(pool_swap_dftx) + Ok(Some(PoolSwapFromToData { + address: from_address, + amount: Decimal::new(from_amount, 8).to_string(), + display_symbol: parse_display_symbol(&from_token), + symbol: from_token.symbol, + })) } -fn find_pool_swap_from_to( - history: AccountHistory, - from: bool, - display_symbol: String, +pub async fn find_swap_to( + ctx: &Arc, + swap: crate::model::PoolSwap, ) -> Result> { + let crate::model::PoolSwap { + to, + to_token_id, + to_amount, + block, + txno, + .. + } = swap; + let BlockContext { height, .. } = block; + let txno = txno.try_into()?; + + let to_address = from_script(to, ctx.network.into())?; + + let to_token = get_token_cached(ctx, &to_token_id.to_string()).await?; + if to_token.is_none() { + return Ok(None); + } + let (_, to_token) = to_token.unwrap(); + + let display_symbol = parse_display_symbol(&to_token); + + // NOTE(canonbrother): fallback to API layer to calculate `to_amount` + // context: to_amount has been calculated while indexing with ocean archive + // `to_amount` None indicates the node is not running with ocean archive + // get the `to_amount` via `getaccounthistory` + if to_amount.is_some() { + let amount = to_amount.unwrap().abs(); + return Ok(Some(PoolSwapFromToData { + address: to_address, + amount: Decimal::new(amount, 8).to_string(), + symbol: to_token.symbol, + display_symbol, + })); + } + + let history = ctx + .client + .get_account_history(&to_address.to_string(), height, txno) + .await?; + for account in history.amounts { let parts = account.split('@').collect::>(); let [value, symbol] = parts @@ -640,16 +688,7 @@ fn find_pool_swap_from_to( let value = Decimal::from_str(value)?; - if value.is_sign_negative() && from { - return Ok(Some(PoolSwapFromToData { - address: history.owner, - amount: format!("{:.8}", value.abs()), - symbol: symbol.to_string(), - display_symbol, - })); - } - - if value.is_sign_positive() && !from { + if value.is_sign_positive() { return Ok(Some(PoolSwapFromToData { address: history.owner, amount: format!("{:.8}", value.abs()), @@ -662,65 +701,6 @@ fn find_pool_swap_from_to( Ok(None) } -pub async fn find_swap_from_to( - ctx: &Arc, - height: u32, - txid: Txid, - txno: u32, -) -> Result> { - let dftx = find_pool_swap_dftx(ctx, txid)?; - if dftx.is_none() { - return Ok(None); - } - let dftx = dftx.unwrap(); - - let from_script = dftx.from_script.as_script(); - - let from_address = Address::from_script(from_script, ctx.network.into()); - if from_address.is_err() { - return Ok(None); - } - let from_address = from_address.unwrap().to_string(); - - let to_script = dftx.to_script.as_script(); - let to_address = Address::from_script(to_script, ctx.network.into()); - if to_address.is_err() { - return Ok(None); - } - let to_address = to_address.unwrap().to_string(); - - let from_token = get_token_cached(ctx, &dftx.from_token_id.0.to_string()).await?; - if from_token.is_none() { - return Ok(None); - } - let (_, from_token) = from_token.unwrap(); - - let to_token = get_token_cached(ctx, &dftx.to_token_id.0.to_string()).await?; - if to_token.is_none() { - return Ok(None); - } - let (_, to_token) = to_token.unwrap(); - - let from = PoolSwapFromToData { - address: from_address, - amount: Decimal::new(dftx.from_amount, 8).to_string(), - display_symbol: parse_display_symbol(&from_token), - symbol: from_token.symbol, - }; - - let history = ctx - .client - .get_account_history(&to_address.to_string(), height, txno) - .await?; - - let to = find_pool_swap_from_to(history, false, parse_display_symbol(&to_token))?; - - Ok(Some(PoolSwapFromTo { - from: Some(from), - to, - })) -} - async fn get_pool_swap_type( ctx: &Arc, swap: crate::model::PoolSwap, diff --git a/lib/ain-ocean/src/bin/cli.rs b/lib/ain-ocean/src/bin/cli.rs index 8e845c7370a..2ef4f914213 100644 --- a/lib/ain-ocean/src/bin/cli.rs +++ b/lib/ain-ocean/src/bin/cli.rs @@ -111,11 +111,16 @@ async fn main() -> Result<()> { .await? .0 .into_iter() - .map(|(id, info)| PoolCreationHeight { - id: id.parse::().unwrap(), - creation_height: info.creation_height as u32, + .map(|(id, info)| { + let pool = PoolCreationHeight { + id: id.parse::()?, + id_token_a: info.id_token_a.parse::()?, + id_token_b: info.id_token_b.parse::()?, + creation_height: info.creation_height as u32, + }; + Ok(pool) }) - .collect::>(); + .collect::>>()?; next_block_hash = block.nextblockhash; match index_block(&services, block, pools) { diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index e607f5d7f4d..71cd0764f62 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -12,7 +12,9 @@ use std::{sync::Arc, time::Instant}; use ain_dftx::{deserialize, is_skipped_tx, DfTx, Stack}; use defichain_rpc::json::blockchain::{Block, Transaction}; use log::debug; -pub use pool::{PoolSwapAggregatedInterval, AGGREGATED_INTERVALS}; +pub use pool::{ + update_mapping, PoolCreationHeight, PoolSwapAggregatedInterval, AGGREGATED_INTERVALS, +}; use crate::{ index_transaction, @@ -30,12 +32,6 @@ pub(crate) trait Index { fn invalidate(&self, services: &Arc, ctx: &Context) -> Result<()>; } -#[derive(Debug, Clone)] -pub struct PoolCreationHeight { - pub id: u32, - pub creation_height: u32, -} - #[derive(Debug)] pub struct Context { block: BlockContext, @@ -130,6 +126,8 @@ pub fn index_block( median_time: block.mediantime, }; + update_mapping(&pools); + index_block_start(services, &block, pools)?; for (tx_idx, tx) in block.tx.into_iter().enumerate() { diff --git a/lib/ain-ocean/src/indexer/pool.rs b/lib/ain-ocean/src/indexer/pool.rs index 349bc9859c5..393188fda3f 100644 --- a/lib/ain-ocean/src/indexer/pool.rs +++ b/lib/ain-ocean/src/indexer/pool.rs @@ -1,6 +1,10 @@ -use std::{ops::Div, str::FromStr, sync::Arc}; +use parking_lot::Mutex; +use std::{collections::HashMap, ops::Div, str::FromStr, sync::Arc}; -use ain_dftx::pool::*; +use ain_dftx::{ + common::{CompactVec, VarInt}, + pool::*, +}; use anyhow::format_err; use bitcoin::BlockHash; // use bitcoin::Address; @@ -28,25 +32,86 @@ pub enum PoolSwapAggregatedInterval { OneHour = 60 * 60, } +#[derive(Debug, Clone)] +pub struct PoolCreationHeight { + pub id: u32, + pub id_token_a: u32, + pub id_token_b: u32, + pub creation_height: u32, +} + +lazy_static::lazy_static! { + pub static ref POOL_PAIR_PATH_MAPPING: Mutex> = Mutex::new(HashMap::new()); +} + +fn find_pair(a: u64, b: u64) -> Option { + let mapping = POOL_PAIR_PATH_MAPPING.lock(); + let ab = mapping.get(&format!("{a}-{b}")); + if ab.is_some() { + return ab.cloned(); + } + let ba = mapping.get(&format!("{b}-{a}")); + if ba.is_some() { + return ba.cloned(); + } + None +} + +pub fn update_mapping(pools: &Vec) { + let mut mapping = POOL_PAIR_PATH_MAPPING.lock(); + for pool in pools { + mapping.insert( + format!("{}-{}", pool.id_token_a, pool.id_token_b), + pool.clone(), + ); + mapping.insert( + format!("{}-{}", pool.id_token_b, pool.id_token_a), + pool.clone(), + ); + } +} + +fn process_pool_ids(pool_ids: CompactVec, a: u64, b: u64) -> CompactVec { + if pool_ids.as_ref().is_empty() { + let pool = find_pair(a, b); + if pool.is_none() { + log::error!("Pool not found by {a}-{b} or {b}-{a} from POOL_PAIR_PATH_MAPPING"); + return CompactVec::from(Vec::new()); + } + let pool = pool.unwrap(); + let pool_id = PoolId { + id: VarInt(pool.id as u64), + }; + return CompactVec::from(vec![pool_id]); + } + pool_ids +} + impl Index for PoolSwap { fn index(self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[Poolswap] Indexing..."); let txid = ctx.tx.txid; let idx = ctx.tx_idx; - let Some(TxResult::PoolSwap(PoolSwapResult { to_amount, pool_id })) = - services.result.get(&txid)? - else { - // TODO fallback through getaccounthistory when indexing against non-oceanarchive node - // let address = Address::from_script(&self.to_script, bitcoin::Network::Bitcoin) - // .map_err(|e| format_err!("Error getting address from script: {e}")); - debug!("Missing swap result for {}", ctx.tx.txid.to_string()); - return Err("Missing swap result".into()); - }; - let from = self.from_script; let to = self.to_script; let from_token_id = self.from_token_id.0; let from_amount = self.from_amount; + let to_token_id = self.to_token_id.0; + + let (to_amount, pool_id) = if let Some(TxResult::PoolSwap(PoolSwapResult { + to_amount, + pool_id, + })) = services.result.get(&txid)? + { + (Some(to_amount), pool_id) + } else { + let pair = find_pair(from_token_id, to_token_id); + if pair.is_none() { + return Err(format_err!("Pool not found by {from_token_id}-{to_token_id} or {to_token_id}-{from_token_id} from POOL_PAIR_PATH_MAPPING").into()); + } + let pair = pair.unwrap(); + (None, pair.id) + }; let swap = model::PoolSwap { id: format!("{}-{}", pool_id, txid), @@ -56,7 +121,7 @@ impl Index for PoolSwap { txno: idx, from_amount, from_token_id, - to_token_id: self.to_token_id.0, + to_token_id, to_amount, pool_id, from, @@ -204,20 +269,20 @@ impl Index for CompositeSwap { fn index(self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[CompositeSwap] Indexing..."); let txid = ctx.tx.txid; - let Some(TxResult::PoolSwap(PoolSwapResult { to_amount, .. })) = - services.result.get(&txid)? - else { - // TODO fallback through getaccounthistory when indexing against non-oceanarchive node - // let address = - // Address::from_script(&self.pool_swap.to_script, bitcoin::Network::Bitcoin) - // .map_err(|e| format_err!("Error getting address from script: {e}")); - debug!("Missing swap result for {}", txid.to_string()); - return Err("Missing swap result".into()); - }; + + let to_amount = services.result.get(&txid)?.and_then(|res| match res { + TxResult::PoolSwap(PoolSwapResult { to_amount, .. }) => Some(to_amount), + TxResult::None => None, + }); let from = self.pool_swap.from_script; let to = self.pool_swap.to_script; - for pool in self.pools.as_ref() { + let pool_ids = process_pool_ids( + self.pools, + self.pool_swap.from_token_id.0, + self.pool_swap.to_token_id.0, + ); + for pool in pool_ids.as_ref() { let pool_id = pool.id.0 as u32; let swap = model::PoolSwap { id: format!("{}-{}", pool_id, txid), diff --git a/lib/ain-ocean/src/model/poolswap.rs b/lib/ain-ocean/src/model/poolswap.rs index 1dee98f7b7a..13867d80727 100644 --- a/lib/ain-ocean/src/model/poolswap.rs +++ b/lib/ain-ocean/src/model/poolswap.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use super::BlockContext; -pub type PoolSwapKey = (u32, u32, usize); +pub type PoolSwapKey = (u32, u32, usize); // (pool_id, height, txno) #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] @@ -15,7 +15,7 @@ pub struct PoolSwap { pub sort: String, pub from_amount: i64, pub from_token_id: u64, - pub to_amount: i64, + pub to_amount: Option, pub to_token_id: u64, pub from: ScriptBuf, pub to: ScriptBuf, diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index bcb622f6209..a245634f24c 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -169,6 +169,8 @@ pub mod ffi { pub struct PoolCreationHeight { pub id: u32, + pub id_token_a: u32, + pub id_token_b: u32, pub creation_height: u32, } diff --git a/lib/ain-rs-exports/src/ocean.rs b/lib/ain-rs-exports/src/ocean.rs index fc8926959f4..316ad79341c 100644 --- a/lib/ain-rs-exports/src/ocean.rs +++ b/lib/ain-rs-exports/src/ocean.rs @@ -14,6 +14,8 @@ pub fn ocean_index_block(block_str: String, pools: Vec) .into_iter() .map(|p| PoolCreationHeight { id: p.id, + id_token_a: p.id_token_a, + id_token_b: p.id_token_b, creation_height: p.creation_height, }) .collect::>(); diff --git a/src/dfi/validation.cpp b/src/dfi/validation.cpp index 7412406c5b6..76e86a965ae 100644 --- a/src/dfi/validation.cpp +++ b/src/dfi/validation.cpp @@ -3141,7 +3141,12 @@ Res ProcessDeFiEventFallible(const CBlock &block, [&](DCT_ID const &id, CPoolPair pool) { const auto token = pcustomcsview->GetToken(id); if (token) { - pools.push_back({id.v, pool.creationHeight}); + pools.push_back(PoolCreationHeight{ + id.v, + pool.idTokenA.v, + pool.idTokenB.v, + pool.creationHeight, + }); }; return true; }, diff --git a/src/init.cpp b/src/init.cpp index 70c49ae6cba..dab0bd1d039 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2490,7 +2490,12 @@ bool AppInitMain(InitInterfaces& interfaces) [&](DCT_ID const &id, CPoolPair pool) { const auto token = pcustomcsview->GetToken(id); if (token) { - pools.push_back({id.v, pool.creationHeight}); + pools.push_back(PoolCreationHeight{ + id.v, + pool.idTokenA.v, + pool.idTokenB.v, + pool.creationHeight + }); }; return true; }, {0}); From 5751b16ffc6aba310ec718e89526ba95fd11da41 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Wed, 12 Jun 2024 08:10:49 +0100 Subject: [PATCH 105/185] Ocean: Index createpoolpair result (#2936) * Oceain: Index createpoolpair result * Add missing cf * fmt cpp * Add header guards * Clippy fix * Clippy fix --- lib/ain-dftx/src/types/mod.rs | 8 +- lib/ain-dftx/src/types/pool.rs | 2 +- lib/ain-ocean/src/api/pool_pair/service.rs | 19 ++- lib/ain-ocean/src/bin/cli.rs | 25 +--- lib/ain-ocean/src/indexer/mod.rs | 40 ++++--- lib/ain-ocean/src/indexer/poolpair.rs | 54 +++++++++ .../src/indexer/{pool.rs => poolswap.rs} | 112 ++++++------------ lib/ain-ocean/src/lib.rs | 18 ++- lib/ain-ocean/src/model/poolswap.rs | 2 +- lib/ain-ocean/src/model/tx_result.rs | 4 + lib/ain-ocean/src/repository/mod.rs | 2 + lib/ain-ocean/src/repository/poolpair.rs | 29 +++++ lib/ain-ocean/src/storage/columns/mod.rs | 6 +- lib/ain-ocean/src/storage/columns/poolpair.rs | 31 +++++ lib/ain-rs-exports/src/lib.rs | 6 +- lib/ain-rs-exports/src/ocean.rs | 15 +-- src/Makefile.am | 2 + src/dfi/consensus/poolpairs.cpp | 8 +- src/dfi/mn_checks.cpp | 13 +- src/dfi/validation.cpp | 17 +-- src/ffi/ffiocean.cpp | 19 +++ src/ffi/ffiocean.h | 6 + src/init.cpp | 17 +-- 23 files changed, 256 insertions(+), 199 deletions(-) create mode 100644 lib/ain-ocean/src/indexer/poolpair.rs rename lib/ain-ocean/src/indexer/{pool.rs => poolswap.rs} (75%) create mode 100644 lib/ain-ocean/src/repository/poolpair.rs create mode 100644 lib/ain-ocean/src/storage/columns/poolpair.rs create mode 100644 src/ffi/ffiocean.cpp create mode 100644 src/ffi/ffiocean.h diff --git a/lib/ain-dftx/src/types/mod.rs b/lib/ain-dftx/src/types/mod.rs index fa7a10c4b5f..2174cd36ce6 100644 --- a/lib/ain-dftx/src/types/mod.rs +++ b/lib/ain-dftx/src/types/mod.rs @@ -50,7 +50,7 @@ pub enum DfTx { PaybackLoanV2(PaybackLoanV2), PlaceAuctionBid(PlaceAuctionBid), PoolAddLiquidity(PoolAddLiquidity), - PoolCreatePair(PoolCreatePair), + CreatePoolPair(CreatePoolPair), PoolRemoveLiquidity(PoolRemoveLiquidity), PoolSwap(PoolSwap), PoolUpdatePair(PoolUpdatePair), @@ -130,7 +130,7 @@ impl DfTx { DfTx::UpdateMasternode(_) => b'm', DfTx::UpdateTokenAny(_) => b'n', DfTx::AppointOracle(_) => b'o', - DfTx::PoolCreatePair(_) => b'p', + DfTx::CreatePoolPair(_) => b'p', DfTx::PoolRemoveLiquidity(_) => b'r', DfTx::PoolSwap(_) => b's', DfTx::UpdateOracle(_) => b't', @@ -181,7 +181,7 @@ impl Decodable for DfTx { DfTx::CreateMasternode(CreateMasternode::consensus_decode(r)?) } CustomTxType::CreatePoolPair => { - DfTx::PoolCreatePair(PoolCreatePair::consensus_decode(r)?) + DfTx::CreatePoolPair(CreatePoolPair::consensus_decode(r)?) } CustomTxType::CreateToken => DfTx::CreateToken(CreateToken::consensus_decode(r)?), CustomTxType::CreateVoc => DfTx::CreateVoc(CreateProposal::consensus_decode(r)?), @@ -287,7 +287,7 @@ impl Encodable for DfTx { DfTx::BurnToken(data) => data.consensus_encode(w), DfTx::CloseVault(data) => data.consensus_encode(w), DfTx::CreateMasternode(data) => data.consensus_encode(w), - DfTx::PoolCreatePair(data) => data.consensus_encode(w), + DfTx::CreatePoolPair(data) => data.consensus_encode(w), DfTx::CreateCfp(data) => data.consensus_encode(w), DfTx::CreateToken(data) => data.consensus_encode(w), DfTx::CreateVoc(data) => data.consensus_encode(w), diff --git a/lib/ain-dftx/src/types/pool.rs b/lib/ain-dftx/src/types/pool.rs index 6997f0945e4..3d3c7a97a53 100644 --- a/lib/ain-dftx/src/types/pool.rs +++ b/lib/ain-dftx/src/types/pool.rs @@ -47,7 +47,7 @@ pub struct PoolRemoveLiquidity { } #[derive(ConsensusEncoding, Debug, PartialEq, Eq)] -pub struct PoolCreatePair { +pub struct CreatePoolPair { pub token_a: VarInt, pub token_b: VarInt, pub commission: i64, diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index 4edd18f9c58..b8b93fd6dde 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -642,7 +642,6 @@ pub async fn find_swap_to( let crate::model::PoolSwap { to, to_token_id, - to_amount, block, txno, .. @@ -664,15 +663,15 @@ pub async fn find_swap_to( // context: to_amount has been calculated while indexing with ocean archive // `to_amount` None indicates the node is not running with ocean archive // get the `to_amount` via `getaccounthistory` - if to_amount.is_some() { - let amount = to_amount.unwrap().abs(); - return Ok(Some(PoolSwapFromToData { - address: to_address, - amount: Decimal::new(amount, 8).to_string(), - symbol: to_token.symbol, - display_symbol, - })); - } + // if to_amount.is_some() { + // let amount = to_amount.unwrap().abs(); + // return Ok(Some(PoolSwapFromToData { + // address: to_address, + // amount: Decimal::new(amount, 8).to_string(), + // symbol: to_token.symbol, + // display_symbol, + // })); + // } let history = ctx .client diff --git a/lib/ain-ocean/src/bin/cli.rs b/lib/ain-ocean/src/bin/cli.rs index 2ef4f914213..12984ca30b8 100644 --- a/lib/ain-ocean/src/bin/cli.rs +++ b/lib/ain-ocean/src/bin/cli.rs @@ -7,11 +7,10 @@ use std::{ }; use ain_ocean::{ - index_block, network::Network, storage::ocean_store::OceanStore, PoolCreationHeight, Result, - Services, + index_block, network::Network, storage::ocean_store::OceanStore, Result, Services, }; use clap::Parser; -use defichain_rpc::{json::blockchain::*, Auth, BlockchainRPC, Client, PoolPairRPC}; +use defichain_rpc::{json::blockchain::*, Auth, BlockchainRPC, Client}; #[derive(Parser, Debug)] #[command( @@ -67,7 +66,7 @@ async fn main() -> Result<()> { let listener = tokio::net::TcpListener::bind(cli.bind_address).await?; let ocean_router = - ain_ocean::ocean_router(&services, client.clone(), cli.network.to_string()).await?; + ain_ocean::ocean_router(&services, Arc::clone(&client), cli.network.to_string()).await?; tokio::spawn(async move { axum::serve(listener, ocean_router).await.unwrap() }); let mut indexed_block = 0; @@ -106,24 +105,8 @@ async fn main() -> Result<()> { Ok(_) => return Err("Error deserializing block".into()), }; - let pools = client - .list_pool_pairs(None, Some(true)) - .await? - .0 - .into_iter() - .map(|(id, info)| { - let pool = PoolCreationHeight { - id: id.parse::()?, - id_token_a: info.id_token_a.parse::()?, - id_token_b: info.id_token_b.parse::()?, - creation_height: info.creation_height as u32, - }; - Ok(pool) - }) - .collect::>>()?; - next_block_hash = block.nextblockhash; - match index_block(&services, block, pools) { + match index_block(&services, block) { Ok(_) => (), Err(e) => { return Err(e); diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 71cd0764f62..c7a0cb5a762 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -3,7 +3,8 @@ pub mod loan_token; mod masternode; pub mod oracle; pub mod oracle_test; -pub mod pool; +pub mod poolpair; +pub mod poolswap; pub mod transaction; pub mod tx_result; @@ -12,9 +13,7 @@ use std::{sync::Arc, time::Instant}; use ain_dftx::{deserialize, is_skipped_tx, DfTx, Stack}; use defichain_rpc::json::blockchain::{Block, Transaction}; use log::debug; -pub use pool::{ - update_mapping, PoolCreationHeight, PoolSwapAggregatedInterval, AGGREGATED_INTERVALS, -}; +pub use poolswap::{PoolCreationHeight, PoolSwapAggregatedInterval, AGGREGATED_INTERVALS}; use crate::{ index_transaction, @@ -48,13 +47,21 @@ fn get_bucket(block: &Block, interval: i64) -> i64 { block.mediantime - (block.mediantime % interval) } -fn index_block_start( - services: &Arc, - block: &Block, - pool_pairs: Vec, -) -> Result<()> { - let mut pool_pairs = pool_pairs; - pool_pairs.sort_by(|a, b| b.creation_height.cmp(&a.creation_height)); +fn index_block_start(services: &Arc, block: &Block) -> Result<()> { + let pool_pairs = services + .poolpair + .by_height + .list(None, SortOrder::Ascending)? + .map(|el| { + let ((k, _), (pool_id, id_token_a, id_token_b)) = el?; + Ok(PoolCreationHeight { + id: pool_id, + id_token_a, + id_token_b, + creation_height: k, + }) + }) + .collect::>>()?; for interval in AGGREGATED_INTERVALS { for pool_pair in &pool_pairs { @@ -110,11 +117,7 @@ fn index_block_start( Ok(()) } -pub fn index_block( - services: &Arc, - block: Block, - pools: Vec, -) -> Result<()> { +pub fn index_block(services: &Arc, block: Block) -> Result<()> { debug!("[index_block] Indexing block..."); let start = Instant::now(); let block_hash = block.hash; @@ -126,9 +129,7 @@ pub fn index_block( median_time: block.mediantime, }; - update_mapping(&pools); - - index_block_start(services, &block, pools)?; + index_block_start(services, &block)?; for (tx_idx, tx) in block.tx.into_iter().enumerate() { if is_skipped_tx(&tx.txid) { @@ -169,6 +170,7 @@ pub fn index_block( DfTx::PoolSwap(data) => data.index(services, &ctx)?, DfTx::SetLoanToken(data) => data.index(services, &ctx)?, DfTx::CompositeSwap(data) => data.index(services, &ctx)?, + DfTx::CreatePoolPair(data) => data.index(services, &ctx)?, // DfTx::PlaceAuctionBid(data) => data.index(services, &ctx)?, _ => (), } diff --git a/lib/ain-ocean/src/indexer/poolpair.rs b/lib/ain-ocean/src/indexer/poolpair.rs new file mode 100644 index 00000000000..eea4d65d151 --- /dev/null +++ b/lib/ain-ocean/src/indexer/poolpair.rs @@ -0,0 +1,54 @@ +use std::sync::Arc; + +use ain_dftx::pool::CreatePoolPair; +use log::debug; + +use crate::{ + indexer::{Context, Index, Result}, + model::TxResult, + repository::RepositoryOps, + Services, +}; + +impl Index for CreatePoolPair { + fn index(self, services: &Arc, ctx: &Context) -> Result<()> { + let Some(TxResult::CreatePoolPair(pool_id)) = services.result.get(&ctx.tx.txid)? else { + return Err("[CreatePoolPair] Missing result".into()); + }; + + debug!( + "[CreatePoolPair] Indexing {} {} id {}", + ctx.block.height, ctx.tx_idx, &pool_id + ); + let id_a = self.token_a.0 as u32; + let id_b = self.token_b.0 as u32; + + services + .poolpair + .by_height + .put(&(ctx.block.height, ctx.tx_idx), &(pool_id, id_a, id_b))?; + + services.poolpair.by_id.put(&(id_a, id_b), &pool_id)?; + services.poolpair.by_id.put(&(id_b, id_a), &pool_id)?; + + Ok(()) + } + + fn invalidate(&self, services: &Arc, ctx: &Context) -> Result<()> { + if let Some((_, id_a, id_b)) = services + .poolpair + .by_height + .get(&(ctx.block.height, ctx.tx_idx))? + { + services.poolpair.by_id.delete(&(id_a, id_b))?; + services.poolpair.by_id.delete(&(id_b, id_a))?; + } + + services + .poolpair + .by_height + .delete(&(ctx.block.height, ctx.tx_idx))?; + + Ok(()) + } +} diff --git a/lib/ain-ocean/src/indexer/pool.rs b/lib/ain-ocean/src/indexer/poolswap.rs similarity index 75% rename from lib/ain-ocean/src/indexer/pool.rs rename to lib/ain-ocean/src/indexer/poolswap.rs index 393188fda3f..5243964acb0 100644 --- a/lib/ain-ocean/src/indexer/pool.rs +++ b/lib/ain-ocean/src/indexer/poolswap.rs @@ -1,10 +1,6 @@ -use parking_lot::Mutex; -use std::{collections::HashMap, ops::Div, str::FromStr, sync::Arc}; +use std::{ops::Div, str::FromStr, sync::Arc}; -use ain_dftx::{ - common::{CompactVec, VarInt}, - pool::*, -}; +use ain_dftx::pool::*; use anyhow::format_err; use bitcoin::BlockHash; // use bitcoin::Address; @@ -40,53 +36,6 @@ pub struct PoolCreationHeight { pub creation_height: u32, } -lazy_static::lazy_static! { - pub static ref POOL_PAIR_PATH_MAPPING: Mutex> = Mutex::new(HashMap::new()); -} - -fn find_pair(a: u64, b: u64) -> Option { - let mapping = POOL_PAIR_PATH_MAPPING.lock(); - let ab = mapping.get(&format!("{a}-{b}")); - if ab.is_some() { - return ab.cloned(); - } - let ba = mapping.get(&format!("{b}-{a}")); - if ba.is_some() { - return ba.cloned(); - } - None -} - -pub fn update_mapping(pools: &Vec) { - let mut mapping = POOL_PAIR_PATH_MAPPING.lock(); - for pool in pools { - mapping.insert( - format!("{}-{}", pool.id_token_a, pool.id_token_b), - pool.clone(), - ); - mapping.insert( - format!("{}-{}", pool.id_token_b, pool.id_token_a), - pool.clone(), - ); - } -} - -fn process_pool_ids(pool_ids: CompactVec, a: u64, b: u64) -> CompactVec { - if pool_ids.as_ref().is_empty() { - let pool = find_pair(a, b); - if pool.is_none() { - log::error!("Pool not found by {a}-{b} or {b}-{a} from POOL_PAIR_PATH_MAPPING"); - return CompactVec::from(Vec::new()); - } - let pool = pool.unwrap(); - let pool_id = PoolId { - id: VarInt(pool.id as u64), - }; - return CompactVec::from(vec![pool_id]); - } - pool_ids -} - impl Index for PoolSwap { fn index(self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[Poolswap] Indexing..."); @@ -98,19 +47,17 @@ impl Index for PoolSwap { let from_amount = self.from_amount; let to_token_id = self.to_token_id.0; - let (to_amount, pool_id) = if let Some(TxResult::PoolSwap(PoolSwapResult { - to_amount, - pool_id, - })) = services.result.get(&txid)? - { - (Some(to_amount), pool_id) - } else { - let pair = find_pair(from_token_id, to_token_id); - if pair.is_none() { - return Err(format_err!("Pool not found by {from_token_id}-{to_token_id} or {to_token_id}-{from_token_id} from POOL_PAIR_PATH_MAPPING").into()); - } - let pair = pair.unwrap(); - (None, pair.id) + let Some(TxResult::PoolSwap(PoolSwapResult { to_amount, pool_id })) = + services.result.get(&txid)? + else { + // TODO: Commenting out for now, fallback should only be introduced for supporting back CLI indexing + return Err("Missing swap result".into()); + // let pair = find_pair(from_token_id, to_token_id); + // if pair.is_none() { + // return Err(format_err!("Pool not found by {from_token_id}-{to_token_id} or {to_token_id}-{from_token_id}").into()); + // } + // let pair = pair.unwrap(); + // (None, pair.id) }; let swap = model::PoolSwap { @@ -270,20 +217,31 @@ impl Index for CompositeSwap { debug!("[CompositeSwap] Indexing..."); let txid = ctx.tx.txid; - let to_amount = services.result.get(&txid)?.and_then(|res| match res { - TxResult::PoolSwap(PoolSwapResult { to_amount, .. }) => Some(to_amount), - TxResult::None => None, - }); + let Some(TxResult::PoolSwap(PoolSwapResult { to_amount, .. })) = + services.result.get(&txid)? + else { + debug!("Missing swap result for {}", txid.to_string()); + return Err("Missing swap result".into()); + }; let from = self.pool_swap.from_script; let to = self.pool_swap.to_script; - let pool_ids = process_pool_ids( - self.pools, - self.pool_swap.from_token_id.0, - self.pool_swap.to_token_id.0, - ); - for pool in pool_ids.as_ref() { - let pool_id = pool.id.0 as u32; + let pools = self.pools.as_ref(); + + let pool_ids = if pools.is_empty() { + let Some(pool_id) = services.poolpair.by_id.get(&( + self.pool_swap.from_token_id.0 as u32, + self.pool_swap.to_token_id.0 as u32, + ))? + else { + return Err("Missing pool_id".into()); + }; + Vec::from([pool_id]) + } else { + pools.iter().map(|pool| pool.id.0 as u32).collect() + }; + + for pool_id in pool_ids { let swap = model::PoolSwap { id: format!("{}-{}", pool_id, txid), sort: format!("{}-{}", ctx.block.height, ctx.tx_idx), diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 9c75b2712e5..21e76713e18 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -20,10 +20,10 @@ use repository::{ OraclePriceAggregatedIntervalRepository, OraclePriceAggregatedRepository, OraclePriceAggregatedRepositorykey, OraclePriceFeedKeyRepository, OraclePriceFeedRepository, OracleRepository, OracleTokenCurrencyKeyRepository, OracleTokenCurrencyRepository, - PoolSwapAggregatedKeyRepository, PoolSwapAggregatedRepository, PoolSwapRepository, - PriceTickerKeyRepository, PriceTickerRepository, RawBlockRepository, - TransactionByBlockHashRepository, TransactionRepository, TransactionVinRepository, - TransactionVoutRepository, TxResultRepository, + PoolPairByHeightRepository, PoolPairRepository, PoolSwapAggregatedKeyRepository, + PoolSwapAggregatedRepository, PoolSwapRepository, PriceTickerKeyRepository, + PriceTickerRepository, RawBlockRepository, TransactionByBlockHashRepository, + TransactionRepository, TransactionVinRepository, TransactionVoutRepository, TxResultRepository, }; use serde::Serialize; pub mod api; @@ -66,6 +66,11 @@ pub struct PoolService { by_id: PoolSwapRepository, } +pub struct PoolPairService { + by_height: PoolPairByHeightRepository, + by_id: PoolPairRepository, +} + pub struct PoolSwapAggregatedService { by_id: PoolSwapAggregatedRepository, by_key: PoolSwapAggregatedKeyRepository, @@ -128,6 +133,7 @@ pub struct Services { pub auction: AuctionService, pub result: TxResultRepository, pub pool: PoolService, + pub poolpair: PoolPairService, pub pool_swap_aggregated: PoolSwapAggregatedService, pub transaction: TransactionService, pub oracle: OracleService, @@ -159,6 +165,10 @@ impl Services { by_height: AuctionHistoryByHeightRepository::new(Arc::clone(&store)), }, result: TxResultRepository::new(Arc::clone(&store)), + poolpair: PoolPairService { + by_height: PoolPairByHeightRepository::new(Arc::clone(&store)), + by_id: PoolPairRepository::new(Arc::clone(&store)), + }, pool: PoolService { by_id: PoolSwapRepository::new(Arc::clone(&store)), }, diff --git a/lib/ain-ocean/src/model/poolswap.rs b/lib/ain-ocean/src/model/poolswap.rs index 13867d80727..fc66bddab8c 100644 --- a/lib/ain-ocean/src/model/poolswap.rs +++ b/lib/ain-ocean/src/model/poolswap.rs @@ -15,7 +15,7 @@ pub struct PoolSwap { pub sort: String, pub from_amount: i64, pub from_token_id: u64, - pub to_amount: Option, + pub to_amount: i64, pub to_token_id: u64, pub from: ScriptBuf, pub to: ScriptBuf, diff --git a/lib/ain-ocean/src/model/tx_result.rs b/lib/ain-ocean/src/model/tx_result.rs index 77d5c529db1..37ab8dc4241 100644 --- a/lib/ain-ocean/src/model/tx_result.rs +++ b/lib/ain-ocean/src/model/tx_result.rs @@ -11,6 +11,7 @@ pub struct PoolSwapResult { #[derive(Serialize, Deserialize, Debug)] pub enum TxResult { PoolSwap(PoolSwapResult), + CreatePoolPair(u32), None, } @@ -22,6 +23,9 @@ impl From<(u8, usize)> for TxResult { CustomTxType::PoolSwap | CustomTxType::PoolSwapV2 => { TxResult::PoolSwap(unsafe { *(result_ptr as *const PoolSwapResult) }) } + CustomTxType::CreatePoolPair => { + TxResult::CreatePoolPair(unsafe { *(result_ptr as *const u32) }) + } _ => TxResult::None, } } diff --git a/lib/ain-ocean/src/repository/mod.rs b/lib/ain-ocean/src/repository/mod.rs index 8a71164bb49..68d29cf4afe 100644 --- a/lib/ain-ocean/src/repository/mod.rs +++ b/lib/ain-ocean/src/repository/mod.rs @@ -12,6 +12,7 @@ mod oracle_price_feed; mod oracle_token_currency; mod pool_swap; mod pool_swap_aggregated; +mod poolpair; mod price_ticker; mod raw_block; mod script_activity; @@ -35,6 +36,7 @@ pub use oracle_price_feed::*; pub use oracle_token_currency::*; pub use pool_swap::*; pub use pool_swap_aggregated::*; +pub use poolpair::*; pub use price_ticker::*; pub use raw_block::*; // pub use script_activity::*; diff --git a/lib/ain-ocean/src/repository/poolpair.rs b/lib/ain-ocean/src/repository/poolpair.rs new file mode 100644 index 00000000000..871f7535a91 --- /dev/null +++ b/lib/ain-ocean/src/repository/poolpair.rs @@ -0,0 +1,29 @@ +use std::sync::Arc; + +use ain_db::LedgerColumn; +use ain_macros::Repository; + +use super::RepositoryOps; +use crate::{ + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +type PoolPairByHeightKey = (u32, usize); +type PoolPairValue = (u32, u32, u32); // pool_id, id_token_a, id_token_b + +#[derive(Repository)] +#[repository(K = "PoolPairByHeightKey", V = "PoolPairValue")] +pub struct PoolPairByHeightRepository { + pub store: Arc, + col: LedgerColumn, +} + +type PoolPairId = (u32, u32); + +#[derive(Repository)] +#[repository(K = "PoolPairId", V = "u32")] +pub struct PoolPairRepository { + pub store: Arc, + col: LedgerColumn, +} diff --git a/lib/ain-ocean/src/storage/columns/mod.rs b/lib/ain-ocean/src/storage/columns/mod.rs index b405505abde..875c6d4cc87 100644 --- a/lib/ain-ocean/src/storage/columns/mod.rs +++ b/lib/ain-ocean/src/storage/columns/mod.rs @@ -10,6 +10,7 @@ mod oracle_price_feed; mod oracle_token_currency; mod pool_swap; mod pool_swap_aggregated; +mod poolpair; mod price_ticker; mod raw_block; mod script_activity; @@ -34,6 +35,7 @@ pub use oracle_price_feed::*; pub use oracle_token_currency::*; pub use pool_swap::*; pub use pool_swap_aggregated::*; +pub use poolpair::*; pub use price_ticker::*; pub use raw_block::*; pub use script_activity::*; @@ -45,7 +47,7 @@ pub use transaction_vout::*; pub use tx_result::*; pub use vault_auction_history::*; -pub const COLUMN_NAMES: [&str; 34] = [ +pub const COLUMN_NAMES: [&str; 36] = [ block::Block::NAME, block::BlockByHeight::NAME, masternode_stats::MasternodeStats::NAME, @@ -67,6 +69,8 @@ pub const COLUMN_NAMES: [&str; 34] = [ pool_swap_aggregated::PoolSwapAggregated::NAME, pool_swap_aggregated::PoolSwapAggregatedKey::NAME, pool_swap::PoolSwap::NAME, + poolpair::PoolPair::NAME, + poolpair::PoolPairByHeight::NAME, price_ticker::PriceTicker::NAME, price_ticker::PriceTickerKey::NAME, raw_block::RawBlock::NAME, diff --git a/lib/ain-ocean/src/storage/columns/poolpair.rs b/lib/ain-ocean/src/storage/columns/poolpair.rs new file mode 100644 index 00000000000..184bb5e7e67 --- /dev/null +++ b/lib/ain-ocean/src/storage/columns/poolpair.rs @@ -0,0 +1,31 @@ +use ain_db::{Column, ColumnName, TypedColumn}; + +#[derive(Debug)] +pub struct PoolPairByHeight; + +impl ColumnName for PoolPairByHeight { + const NAME: &'static str = "poolpair_by_height"; +} + +impl Column for PoolPairByHeight { + type Index = (u32, usize); +} + +impl TypedColumn for PoolPairByHeight { + type Type = (u32, u32, u32); +} + +#[derive(Debug)] +pub struct PoolPair; + +impl ColumnName for PoolPair { + const NAME: &'static str = "poolpair"; +} + +impl Column for PoolPair { + type Index = (u32, u32); +} + +impl TypedColumn for PoolPair { + type Type = u32; +} diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index a245634f24c..0adbc6383ad 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -353,11 +353,7 @@ pub mod ffi { fn evm_try_flush_db(result: &mut CrossBoundaryResult); - fn ocean_index_block( - result: &mut CrossBoundaryResult, - block_str: String, - pools: Vec, - ); + fn ocean_index_block(result: &mut CrossBoundaryResult, block_str: String); fn ocean_invalidate_block(result: &mut CrossBoundaryResult, block: String); fn ocean_try_set_tx_result( diff --git a/lib/ain-rs-exports/src/ocean.rs b/lib/ain-rs-exports/src/ocean.rs index 316ad79341c..a1748ae8076 100644 --- a/lib/ain-rs-exports/src/ocean.rs +++ b/lib/ain-rs-exports/src/ocean.rs @@ -1,5 +1,5 @@ use ain_macros::ffi_fallible; -use ain_ocean::{PoolCreationHeight, Result}; +use ain_ocean::Result; use defichain_rpc::json::blockchain::{Block, Transaction}; use crate::{ @@ -8,18 +8,9 @@ use crate::{ }; #[ffi_fallible] -pub fn ocean_index_block(block_str: String, pools: Vec) -> Result<()> { +pub fn ocean_index_block(block_str: String) -> Result<()> { let block: Block = serde_json::from_str(&block_str)?; - let pools = pools - .into_iter() - .map(|p| PoolCreationHeight { - id: p.id, - id_token_a: p.id_token_a, - id_token_b: p.id_token_b, - creation_height: p.creation_height, - }) - .collect::>(); - ain_ocean::index_block(&ain_ocean::SERVICES, block, pools) + ain_ocean::index_block(&ain_ocean::SERVICES, block) } #[ffi_fallible] diff --git a/src/Makefile.am b/src/Makefile.am index 1d823f97df6..d843ae9db05 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -159,6 +159,7 @@ DEFI_CORE_H = \ logging.h \ ffi/ffiexports.h \ ffi/ffihelpers.h \ + ffi/ffiocean.h \ dfi/accounts.h \ dfi/accountshistory.h \ dfi/anchors.h \ @@ -410,6 +411,7 @@ libdefi_server_a_SOURCES = \ init.cpp \ dbwrapper.cpp \ ffi/ffiexports.cpp \ + ffi/ffiocean.cpp \ dfi/accounts.cpp \ dfi/accountshistory.cpp \ dfi/anchors.cpp \ diff --git a/src/dfi/consensus/poolpairs.cpp b/src/dfi/consensus/poolpairs.cpp index 2472f8ae1f3..8fe1ef95da7 100644 --- a/src/dfi/consensus/poolpairs.cpp +++ b/src/dfi/consensus/poolpairs.cpp @@ -7,6 +7,7 @@ #include #include #include +#include Res CPoolPairsConsensus::EraseEmptyBalances(TAmounts &balances) const { auto &mnview = blockCtx.GetView(); @@ -95,7 +96,12 @@ Res CPoolPairsConsensus::operator()(const CCreatePoolPairMessage &obj) const { } } - return mnview.SetPoolPair(tokenId, height, poolPair); + if (auto res = mnview.SetPoolPair(tokenId, height, poolPair); !res) { + return res; + } + + return OceanSetTxResult(std::make_pair(CustomTxType::CreatePoolPair, tx.GetHash()), + static_cast(reinterpret_cast(&tokenId->v))); } Res CPoolPairsConsensus::operator()(const CUpdatePoolPairMessage &obj) const { diff --git a/src/dfi/mn_checks.cpp b/src/dfi/mn_checks.cpp index 42763ecaa6c..64e28a12d87 100644 --- a/src/dfi/mn_checks.cpp +++ b/src/dfi/mn_checks.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -1155,17 +1156,7 @@ Res CPoolSwap::ExecuteSwap(CCustomCSView &view, result = swapAmountResult.nValue; // Send final swap amount Rust side for indexer - bool isOceanEnabled = gArgs.GetBoolArg("-oceanarchive", false); - if (txInfo && isOceanEnabled) { - const auto &[txType, txHash] = *txInfo; - CrossBoundaryResult ffiResult; - ocean_try_set_tx_result(ffiResult, - static_cast(txType), - txHash.GetByteArrayBE(), - static_cast(reinterpret_cast(&finalSwapAmount))); - } - - return Res::Ok(); + return OceanSetTxResult(txInfo, static_cast(reinterpret_cast(&finalSwapAmount))); } Res SwapToDFIorDUSD(CCustomCSView &mnview, diff --git a/src/dfi/validation.cpp b/src/dfi/validation.cpp index 76e86a965ae..db415c0302a 100644 --- a/src/dfi/validation.cpp +++ b/src/dfi/validation.cpp @@ -3136,22 +3136,7 @@ Res ProcessDeFiEventFallible(const CBlock &block, const UniValue b = blockToJSON(block, ::ChainActive().Tip(), pindex, true, 2); CrossBoundaryResult result; - rust::cxxbridge1::Vec pools; - pcustomcsview->ForEachPoolPair( - [&](DCT_ID const &id, CPoolPair pool) { - const auto token = pcustomcsview->GetToken(id); - if (token) { - pools.push_back(PoolCreationHeight{ - id.v, - pool.idTokenA.v, - pool.idTokenB.v, - pool.creationHeight, - }); - }; - return true; - }, - {0}); - ocean_index_block(result, b.write(), pools); + ocean_index_block(result, b.write()); if (!result.ok) { return Res::Err(result.reason.c_str()); } diff --git a/src/ffi/ffiocean.cpp b/src/ffi/ffiocean.cpp new file mode 100644 index 00000000000..22c7da4c6a4 --- /dev/null +++ b/src/ffi/ffiocean.cpp @@ -0,0 +1,19 @@ +// Copyright (c) DeFi Blockchain Developers +// Distributed under the MIT software license, see the accompanying +// file LICENSE or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include + +Res OceanSetTxResult(const std::optional> &txInfo, const std::size_t result_ptr) { + bool isOceanEnabled = gArgs.GetBoolArg("-oceanarchive", false); + if (txInfo && isOceanEnabled) { + const auto &[txType, txHash] = *txInfo; + CrossBoundaryResult ffiResult; + ocean_try_set_tx_result(ffiResult, static_cast(txType), txHash.GetByteArrayBE(), result_ptr); + } + + return Res::Ok(); +} diff --git a/src/ffi/ffiocean.h b/src/ffi/ffiocean.h new file mode 100644 index 00000000000..b801484268d --- /dev/null +++ b/src/ffi/ffiocean.h @@ -0,0 +1,6 @@ +#ifndef DEFI_FFI_FFIOCEAN_H +#define DEFI_FFI_FFIOCEAN_H + +Res OceanSetTxResult(const std::optional> &txInfo, const std::size_t result_ptr); + +#endif // DEFI_FFI_FFIOCEAN_H diff --git a/src/init.cpp b/src/init.cpp index dab0bd1d039..9607af2f422 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2485,23 +2485,8 @@ bool AppInitMain(InitInterfaces& interfaces) const UniValue b = blockToJSON(block, tip, pblockindex, true, 2); - rust::cxxbridge1::Vec pools; - pcustomcsview->ForEachPoolPair( - [&](DCT_ID const &id, CPoolPair pool) { - const auto token = pcustomcsview->GetToken(id); - if (token) { - pools.push_back(PoolCreationHeight{ - id.v, - pool.idTokenA.v, - pool.idTokenB.v, - pool.creationHeight - }); - }; - return true; - }, {0}); - CrossBoundaryResult result; - ocean_index_block(result, b.write(), pools); + ocean_index_block(result, b.write()); if (!result.ok) { LogPrintf("Error indexing genesis block: %s\n", result.reason); return false; From ebcc7fdad5743e40dfe46943417b5b48395d5df7 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Wed, 12 Jun 2024 19:57:37 +0800 Subject: [PATCH 106/185] Ocean: add error field in ApiError (#2938) * add error field to adopt whale api client error handling * throw poolpair not found err --- lib/ain-ocean/src/api/pool_pair/mod.rs | 4 ++-- lib/ain-ocean/src/error.rs | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/ain-ocean/src/api/pool_pair/mod.rs b/lib/ain-ocean/src/api/pool_pair/mod.rs index 864936bdc8e..949b03fb202 100644 --- a/lib/ain-ocean/src/api/pool_pair/mod.rs +++ b/lib/ain-ocean/src/api/pool_pair/mod.rs @@ -37,7 +37,7 @@ use super::{ AppContext, }; use crate::{ - error::{ApiError, Error}, + error::{ApiError, Error, NotFoundKind}, model::{BlockContext, PoolSwap, PoolSwapAggregated}, repository::{InitialKeyProvider, PoolSwapRepository, RepositoryOps, SecondaryIndex}, storage::SortOrder, @@ -373,7 +373,7 @@ async fn get_pool_pair( return Ok(Response::new(Some(res))); }; - Ok(Response::new(None)) + Err(Error::NotFound(NotFoundKind::PoolPair)) } #[ocean_endpoint] diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index fb8e2478f2d..01f157c768a 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -9,6 +9,7 @@ use axum::{ }; use bitcoin::hex::HexToArrayError; use serde::Serialize; +use serde_json::json; use thiserror::Error; #[derive(Error, Debug)] @@ -23,6 +24,8 @@ pub enum NotFoundKind { Oracle, #[error("token")] Token, + #[error("poolpair")] + PoolPair, } #[derive(Error, Debug)] @@ -121,8 +124,10 @@ impl ApiError { impl IntoResponse for ApiError { fn into_response(self) -> Response { let status = self.status; - let reason = Json(self); - (status, reason).into_response() + let body = Json(json!({ + "error": self.error + })); + (status, body).into_response() } } From 488f9ad76a39cf0e6c78a8cc116dc14bfbd67b11 Mon Sep 17 00:00:00 2001 From: jouzo Date: Wed, 12 Jun 2024 17:37:55 +0100 Subject: [PATCH 107/185] Remove cli indexer --- lib/ain-ocean/src/bin/cli.rs | 123 ----------------------------------- lib/ain-ocean/src/network.rs | 1 + 2 files changed, 1 insertion(+), 123 deletions(-) delete mode 100644 lib/ain-ocean/src/bin/cli.rs diff --git a/lib/ain-ocean/src/bin/cli.rs b/lib/ain-ocean/src/bin/cli.rs deleted file mode 100644 index 12984ca30b8..00000000000 --- a/lib/ain-ocean/src/bin/cli.rs +++ /dev/null @@ -1,123 +0,0 @@ -use std::{ - net::SocketAddr, - path::PathBuf, - sync::Arc, - thread, - time::{Duration, Instant}, -}; - -use ain_ocean::{ - index_block, network::Network, storage::ocean_store::OceanStore, Result, Services, -}; -use clap::Parser; -use defichain_rpc::{json::blockchain::*, Auth, BlockchainRPC, Client}; - -#[derive(Parser, Debug)] -#[command( - author = "Defichain Labs ", - version = "0.1", - about = "Runs the Ocean Node Service" -)] -struct Cli { - /// Sets a custom data directory - #[arg(long, value_name = "DATADIR")] - datadir: PathBuf, - - /// Sets the RPC server address - #[arg(long, value_name = "RPCADDRESS")] - rpcaddress: String, - - /// Sets the RPC username - #[arg(long, value_name = "USERNAME")] - user: String, - - /// Sets the RPC password - #[arg(long, value_name = "PASSWORD")] - pass: String, - - /// Sets the bind address for the TCP listener - #[arg(long, value_name = "BINDADDRESS", default_value = "0.0.0.0:3002")] - bind_address: SocketAddr, - /// Sets the benchmark frequency - #[arg(long, value_name = "BENCHFREQUENCY", default_value = "10000")] - bench_frequency: u32, - - /// Sets Ocean network - #[arg(long, value_name = "NETWORK", default_value = "mainnet")] - network: Network, -} - -#[tokio::main] -async fn main() -> Result<()> { - env_logger::init(); - let cli = Cli::parse(); - - let store = Arc::new(OceanStore::new(&cli.datadir)?); - - let client = Arc::new( - Client::new( - &cli.rpcaddress, - Auth::UserPass(cli.user.clone(), cli.pass.clone()), - ) - .await?, - ); - - let services = Arc::new(Services::new(store)); - - let listener = tokio::net::TcpListener::bind(cli.bind_address).await?; - let ocean_router = - ain_ocean::ocean_router(&services, Arc::clone(&client), cli.network.to_string()).await?; - tokio::spawn(async move { axum::serve(listener, ocean_router).await.unwrap() }); - - let mut indexed_block = 0; - let mut next_block_hash = None; - let mut start_time = Instant::now(); - - loop { - let highest_block = services - .block - .by_height - .get_highest()? - .map_or(0, |b| b.height); - let new_height = highest_block + 1; - println!("Current indexed height {new_height}"); - let hash = if let Some(hash) = next_block_hash { - hash - } else { - match client.get_block_hash(new_height).await { - Ok(hash) => hash, - Err(e) => { - println!("e : {:?}", e); - // Out of range, sleep for 10s - thread::sleep(Duration::from_millis(10000)); - continue; - } - } - }; - let block = match client.get_block(hash, 2).await { - Err(e) => { - println!("e : {:?}", e); - // Error getting block, sleep for 30s - thread::sleep(Duration::from_millis(30000)); - continue; - } - Ok(GetBlockResult::Full(block)) => block, - Ok(_) => return Err("Error deserializing block".into()), - }; - - next_block_hash = block.nextblockhash; - match index_block(&services, block) { - Ok(_) => (), - Err(e) => { - return Err(e); - } - } - - indexed_block += 1; - if indexed_block % cli.bench_frequency == 0 { - let elapsed = start_time.elapsed(); - println!("Processed {} blocks in {:?}", cli.bench_frequency, elapsed); - start_time = Instant::now(); - } - } -} diff --git a/lib/ain-ocean/src/network.rs b/lib/ain-ocean/src/network.rs index 911ab641624..8c69fba68cf 100644 --- a/lib/ain-ocean/src/network.rs +++ b/lib/ain-ocean/src/network.rs @@ -1,4 +1,5 @@ use std::fmt; + #[derive(Debug, Clone, Copy, PartialEq)] pub enum Network { Mainnet, From 38e27f2e5c338afcedf9f086a5d0de48cd5a2ecb Mon Sep 17 00:00:00 2001 From: jouzo Date: Fri, 14 Jun 2024 08:44:23 +0100 Subject: [PATCH 108/185] Flatten dftx check --- lib/ain-ocean/src/indexer/mod.rs | 62 ++++++++++++++++---------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index c7a0cb5a762..66ff0c671ac 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -144,38 +144,40 @@ pub fn index_block(services: &Arc, block: Block) -> Resul }; let bytes = &ctx.tx.vout[0].script_pub_key.hex; - if bytes.len() > 6 && bytes[0] == 0x6a && bytes[1] <= 0x4e { - let offset = 1 + match bytes[1] { - 0x4c => 2, - 0x4d => 3, - 0x4e => 4, - _ => 1, - }; + if bytes.len() <= 6 || bytes[0] != 0x6a || bytes[1] > 0x4e { + continue; + } - let raw_tx = &bytes[offset..]; - match deserialize::(raw_tx) { - Err(bitcoin::consensus::encode::Error::ParseFailed("Invalid marker")) => { - println!("Discarding invalid marker"); - } - Err(e) => return Err(e.into()), - Ok(Stack { dftx, .. }) => { - match dftx { - DfTx::CreateMasternode(data) => data.index(services, &ctx)?, - DfTx::UpdateMasternode(data) => data.index(services, &ctx)?, - DfTx::ResignMasternode(data) => data.index(services, &ctx)?, - DfTx::AppointOracle(data) => data.index(services, &ctx)?, - DfTx::RemoveOracle(data) => data.index(services, &ctx)?, - DfTx::UpdateOracle(data) => data.index(services, &ctx)?, - DfTx::SetOracleData(data) => data.index(services, &ctx)?, - DfTx::PoolSwap(data) => data.index(services, &ctx)?, - DfTx::SetLoanToken(data) => data.index(services, &ctx)?, - DfTx::CompositeSwap(data) => data.index(services, &ctx)?, - DfTx::CreatePoolPair(data) => data.index(services, &ctx)?, - // DfTx::PlaceAuctionBid(data) => data.index(services, &ctx)?, - _ => (), - } - log_elapsed(start, "Indexed dftx"); + let offset = 1 + match bytes[1] { + 0x4c => 2, + 0x4d => 3, + 0x4e => 4, + _ => 1, + }; + + let raw_tx = &bytes[offset..]; + match deserialize::(raw_tx) { + Err(bitcoin::consensus::encode::Error::ParseFailed("Invalid marker")) => { + println!("Discarding invalid marker"); + } + Err(e) => return Err(e.into()), + Ok(Stack { dftx, .. }) => { + match dftx { + DfTx::CreateMasternode(data) => data.index(services, &ctx)?, + DfTx::UpdateMasternode(data) => data.index(services, &ctx)?, + DfTx::ResignMasternode(data) => data.index(services, &ctx)?, + DfTx::AppointOracle(data) => data.index(services, &ctx)?, + DfTx::RemoveOracle(data) => data.index(services, &ctx)?, + DfTx::UpdateOracle(data) => data.index(services, &ctx)?, + DfTx::SetOracleData(data) => data.index(services, &ctx)?, + DfTx::PoolSwap(data) => data.index(services, &ctx)?, + DfTx::SetLoanToken(data) => data.index(services, &ctx)?, + DfTx::CompositeSwap(data) => data.index(services, &ctx)?, + DfTx::CreatePoolPair(data) => data.index(services, &ctx)?, + // DfTx::PlaceAuctionBid(data) => data.index(services, &ctx)?, + _ => (), } + log_elapsed(start, "Indexed dftx"); } } From ae6d0a3afb2ca06003d81949b8bbd4549fea681f Mon Sep 17 00:00:00 2001 From: canonbrother Date: Fri, 14 Jun 2024 17:42:18 +0800 Subject: [PATCH 109/185] Ocean: fix `PoolCreationHeight` sorting & add `CompositeSwap` Aggregated (#2940) * add desc on PoolPairByHeightKey * pool_pairs sorted by creationheight * index composite swap aggregated --- lib/ain-ocean/src/indexer/mod.rs | 2 +- lib/ain-ocean/src/indexer/poolswap.rs | 262 +++++++++++++---------- lib/ain-ocean/src/repository/poolpair.rs | 2 +- 3 files changed, 150 insertions(+), 116 deletions(-) diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 66ff0c671ac..9f7ebf30a05 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -51,7 +51,7 @@ fn index_block_start(services: &Arc, block: &Block) -> Re let pool_pairs = services .poolpair .by_height - .list(None, SortOrder::Ascending)? + .list(None, SortOrder::Descending)? .map(|el| { let ((k, _), (pool_id, id_token_a, id_token_b)) = el?; Ok(PoolCreationHeight { diff --git a/lib/ain-ocean/src/indexer/poolswap.rs b/lib/ain-ocean/src/indexer/poolswap.rs index 5243964acb0..6d380981fcd 100644 --- a/lib/ain-ocean/src/indexer/poolswap.rs +++ b/lib/ain-ocean/src/indexer/poolswap.rs @@ -2,7 +2,7 @@ use std::{ops::Div, str::FromStr, sync::Arc}; use ain_dftx::pool::*; use anyhow::format_err; -use bitcoin::BlockHash; +use bitcoin::{BlockHash, Txid}; // use bitcoin::Address; use log::debug; use rust_decimal::Decimal; @@ -36,6 +36,132 @@ pub struct PoolCreationHeight { pub creation_height: u32, } +fn index_swap_aggregated( + services: &Arc, + pool_id: u32, + from_token_id: u64, + from_amount: i64, + txid: Txid, +) -> Result<()> { + for interval in AGGREGATED_INTERVALS { + let repository = &services.pool_swap_aggregated; + let mut prevs = repository + .by_key + .list(Some((pool_id, interval, i64::MAX)), SortOrder::Descending)? + .take(1) + .take_while(|item| match item { + Ok((k, _)) => k.0 == pool_id && k.1 == interval, + _ => true, + }) + .map(|e| repository.by_key.retrieve_primary_value(e)) + .collect::>>()?; + + if prevs.is_empty() { + log::error!( + "index swap {txid}: Unable to find {pool_id}-{interval} for Aggregate Indexing" + ); + continue; + } + + let aggregated = prevs.first_mut(); + if let Some(aggregated) = aggregated { + let amount = aggregated + .aggregated + .amounts + .get(&from_token_id.to_string()) + .map(|amt| Decimal::from_str(amt)) + .transpose()? + .unwrap_or(dec!(0)); + + let aggregated_amount = amount + .checked_add(Decimal::from(from_amount).div(dec!(100_000_000))) + .ok_or(Error::OverflowError)?; + + aggregated.aggregated.amounts.insert( + from_token_id.to_string(), + format!("{:.8}", aggregated_amount), + ); + + let parts = aggregated.id.split('-').collect::>(); + if parts.len() != 3 { + return Err(format_err!("Invalid poolswap aggregated id format").into()); + }; + let pool_id = parts[0].parse::()?; + let interval = parts[1].parse::()?; + let hash = parts[2].parse::()?; + + repository + .by_id + .put(&(pool_id, interval, hash), aggregated)?; + } + } + + Ok(()) +} + +fn invalidate_swap_aggregated( + services: &Arc, + pool_id: u32, + from_token_id: u64, + from_amount: i64, + txid: Txid, +) -> Result<()> { + for interval in AGGREGATED_INTERVALS { + let repository = &services.pool_swap_aggregated; + let mut prevs = repository + .by_key + .list(Some((pool_id, interval, i64::MAX)), SortOrder::Descending)? + .take(1) + .take_while(|item| match item { + Ok((k, _)) => k.0 == pool_id && k.1 == interval, + _ => true, + }) + .map(|e| repository.by_key.retrieve_primary_value(e)) + .collect::>>()?; + + if prevs.is_empty() { + log::error!( + "invalidate swap {txid}: Unable to find {pool_id}-{interval} for Aggregate Indexing" + ); + continue; + } + + let aggregated = prevs.first_mut(); + if let Some(aggregated) = aggregated { + let amount = aggregated + .aggregated + .amounts + .get(&from_token_id.to_string()) + .map(|amt| Decimal::from_str(amt)) + .transpose()? + .unwrap_or(dec!(0)); + + let aggregated_amount = amount + .checked_sub(Decimal::from(from_amount).div(dec!(100_000_000))) + .ok_or(Error::UnderflowError)?; + + aggregated.aggregated.amounts.insert( + from_token_id.to_string(), + format!("{:.8}", aggregated_amount), + ); + + let parts = aggregated.id.split('-').collect::>(); + if parts.len() != 3 { + return Err(format_err!("Invalid poolswap aggregated id format").into()); + }; + let pool_id = parts[0].parse::()?; + let interval = parts[1].parse::()?; + let hash = parts[2].parse::()?; + + repository + .by_id + .put(&(pool_id, interval, hash), aggregated)?; + } + } + + Ok(()) +} + impl Index for PoolSwap { fn index(self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[Poolswap] Indexing..."); @@ -82,64 +208,16 @@ impl Index for PoolSwap { .by_id .put(&(pool_id, ctx.block.height, idx), &swap)?; - for interval in AGGREGATED_INTERVALS { - let repository = &services.pool_swap_aggregated; - let mut prevs = repository - .by_key - .list(Some((pool_id, interval, i64::MAX)), SortOrder::Descending)? - .take(1) - .take_while(|item| match item { - Ok((k, _)) => k.0 == pool_id && k.1 == interval, - _ => true, - }) - .map(|e| repository.by_key.retrieve_primary_value(e)) - .collect::>>()?; - - if prevs.is_empty() { - log::error!( - "index swap {txid}: Unable to find {pool_id}-{interval} for Aggregate Indexing" - ); - continue; - } - - let aggregated = prevs.first_mut(); - if let Some(aggregated) = aggregated { - let amount = aggregated - .aggregated - .amounts - .get(&from_token_id.to_string()) - .map(|amt| Decimal::from_str(amt)) - .transpose()? - .unwrap_or(dec!(0)); - - let aggregated_amount = amount - .checked_add(Decimal::from(from_amount).div(dec!(100_000_000))) - .ok_or(Error::OverflowError)?; - - aggregated.aggregated.amounts.insert( - from_token_id.to_string(), - format!("{:.8}", aggregated_amount), - ); - - let parts = aggregated.id.split('-').collect::>(); - if parts.len() != 3 { - return Err(format_err!("Invalid poolswap aggregated id format").into()); - }; - let pool_id = parts[0].parse::()?; - let interval = parts[1].parse::()?; - let hash = parts[2].parse::()?; - - repository - .by_id - .put(&(pool_id, interval, hash), aggregated)?; - } - } + index_swap_aggregated(services, pool_id, from_token_id, from_amount, txid)?; Ok(()) } fn invalidate(&self, services: &Arc, ctx: &Context) -> Result<()> { let txid = ctx.tx.txid; + let from_token_id = self.from_token_id.0; + let from_amount = self.from_amount; + let Some(TxResult::PoolSwap(PoolSwapResult { pool_id, .. })) = services.result.get(&txid)? else { @@ -152,61 +230,7 @@ impl Index for PoolSwap { .delete(&(pool_id, ctx.block.height, ctx.tx_idx))?; tx_result::invalidate(services, &txid)?; - for interval in AGGREGATED_INTERVALS { - let repository = &services.pool_swap_aggregated; - let mut prevs = repository - .by_key - .list(Some((pool_id, interval, i64::MAX)), SortOrder::Descending)? - .take(1) - .take_while(|item| match item { - Ok((k, _)) => k.0 == pool_id && k.1 == interval, - _ => true, - }) - .map(|e| repository.by_key.retrieve_primary_value(e)) - .collect::>>()?; - - if prevs.is_empty() { - log::error!( - "invalidate swap {txid}: Unable to find {pool_id}-{interval} for Aggregate Indexing" - ); - continue; - } - - let from_token_id = self.from_token_id.0; - let from_amount = self.from_amount; - - let aggregated = prevs.first_mut(); - if let Some(aggregated) = aggregated { - let amount = aggregated - .aggregated - .amounts - .get(&from_token_id.to_string()) - .map(|amt| Decimal::from_str(amt)) - .transpose()? - .unwrap_or(dec!(0)); - - let aggregated_amount = amount - .checked_sub(Decimal::from(from_amount).div(dec!(100_000_000))) - .ok_or(Error::UnderflowError)?; - - aggregated.aggregated.amounts.insert( - from_token_id.to_string(), - format!("{:.8}", aggregated_amount), - ); - - let parts = aggregated.id.split('-').collect::>(); - if parts.len() != 3 { - return Err(format_err!("Invalid poolswap aggregated id format").into()); - }; - let pool_id = parts[0].parse::()?; - let interval = parts[1].parse::()?; - let hash = parts[2].parse::()?; - - repository - .by_id - .put(&(pool_id, interval, hash), aggregated)?; - } - } + invalidate_swap_aggregated(services, pool_id, from_token_id, from_amount, txid)?; Ok(()) } @@ -216,6 +240,9 @@ impl Index for CompositeSwap { fn index(self, services: &Arc, ctx: &Context) -> Result<()> { debug!("[CompositeSwap] Indexing..."); let txid = ctx.tx.txid; + let from_token_id = self.pool_swap.from_token_id.0; + let from_amount = self.pool_swap.from_amount; + let to_token_id = self.pool_swap.to_token_id.0; let Some(TxResult::PoolSwap(PoolSwapResult { to_amount, .. })) = services.result.get(&txid)? @@ -229,10 +256,10 @@ impl Index for CompositeSwap { let pools = self.pools.as_ref(); let pool_ids = if pools.is_empty() { - let Some(pool_id) = services.poolpair.by_id.get(&( - self.pool_swap.from_token_id.0 as u32, - self.pool_swap.to_token_id.0 as u32, - ))? + let Some(pool_id) = services + .poolpair + .by_id + .get(&(from_token_id as u32, to_token_id as u32))? else { return Err("Missing pool_id".into()); }; @@ -248,8 +275,8 @@ impl Index for CompositeSwap { txid, txno: ctx.tx_idx, from_amount: self.pool_swap.from_amount, - from_token_id: self.pool_swap.from_token_id.0, - to_token_id: self.pool_swap.to_token_id.0, + from_token_id, + to_token_id, to_amount, pool_id, from: from.clone(), @@ -260,18 +287,25 @@ impl Index for CompositeSwap { .pool .by_id .put(&(pool_id, ctx.block.height, ctx.tx_idx), &swap)?; + + index_swap_aggregated(services, pool_id, from_token_id, from_amount, txid)?; } Ok(()) } fn invalidate(&self, services: &Arc, ctx: &Context) -> Result<()> { + let from_token_id = self.pool_swap.from_token_id.0; + let from_amount = self.pool_swap.from_amount; + let txid = ctx.tx.txid; for pool in self.pools.as_ref() { let pool_id = pool.id.0 as u32; services .pool .by_id .delete(&(pool_id, ctx.block.height, ctx.tx_idx))?; + + invalidate_swap_aggregated(services, pool_id, from_token_id, from_amount, txid)?; } tx_result::invalidate(services, &ctx.tx.txid) } diff --git a/lib/ain-ocean/src/repository/poolpair.rs b/lib/ain-ocean/src/repository/poolpair.rs index 871f7535a91..31bc421dc2e 100644 --- a/lib/ain-ocean/src/repository/poolpair.rs +++ b/lib/ain-ocean/src/repository/poolpair.rs @@ -9,7 +9,7 @@ use crate::{ Result, }; -type PoolPairByHeightKey = (u32, usize); +type PoolPairByHeightKey = (u32, usize); // block_height, tx_idx type PoolPairValue = (u32, u32, u32); // pool_id, id_token_a, id_token_b #[derive(Repository)] From 4e3902bf3553b0800133f43285f0cc583be8825c Mon Sep 17 00:00:00 2001 From: Nagaraj <144004792+nagarajm22@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:16:12 +0800 Subject: [PATCH 110/185] RawTx API (#2921) * ocean rawtx api * updated validate * updated api for raw_trasaction * fixed get_raw_tx * updated request to json rawtx * updated raw tx api * added validate to rawtx * update send_rawtx * fixed clippy * resolved issue * fixed get method * fixed validate in raw_tx * fixed pool format * fixed rawtx bad request test cases * fixed validate return type * updated send error message * fixed lint issue --------- Co-authored-by: jouzo --- lib/Cargo.lock | 4 +- lib/ain-dftx/src/types/pool.rs | 7 + lib/ain-ocean/src/api/mod.rs | 10 +- lib/ain-ocean/src/api/pool_pair/mod.rs | 3 +- lib/ain-ocean/src/api/pool_pair/price.rs | 3 +- lib/ain-ocean/src/api/pool_pair/service.rs | 2 +- lib/ain-ocean/src/api/rawtx.rs | 222 +++++++++++++++++++-- lib/ain-ocean/src/error.rs | 7 + lib/ain-ocean/src/model/mod.rs | 2 + lib/ain-ocean/src/model/raw_tx.rs | 42 ++++ 10 files changed, 277 insertions(+), 25 deletions(-) create mode 100644 lib/ain-ocean/src/model/raw_tx.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 2fbc384a6ee..56aadea45a6 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -1530,7 +1530,7 @@ dependencies = [ [[package]] name = "defichain-rpc" version = "0.18.0" -source = "git+https://github.com/defich/rust-defichain-rpc.git#9d0a769b11c24b855843ecb6dbe556a3b30dfcdf" +source = "git+https://github.com/defich/rust-defichain-rpc.git#90b50580fb913a58e474c66a26dc21c7a9b97d95" dependencies = [ "async-trait", "defichain-rpc-json", @@ -1543,7 +1543,7 @@ dependencies = [ [[package]] name = "defichain-rpc-json" version = "0.18.0" -source = "git+https://github.com/defich/rust-defichain-rpc.git#9d0a769b11c24b855843ecb6dbe556a3b30dfcdf" +source = "git+https://github.com/defich/rust-defichain-rpc.git#90b50580fb913a58e474c66a26dc21c7a9b97d95" dependencies = [ "bitcoin", "serde", diff --git a/lib/ain-dftx/src/types/pool.rs b/lib/ain-dftx/src/types/pool.rs index 3d3c7a97a53..d9550fef9be 100644 --- a/lib/ain-dftx/src/types/pool.rs +++ b/lib/ain-dftx/src/types/pool.rs @@ -1,3 +1,5 @@ +use std::fmt; + use ain_macros::ConsensusEncoding; use bitcoin::{io, ScriptBuf}; @@ -65,3 +67,8 @@ pub struct PoolUpdatePair { pub owner_address: ScriptBuf, pub custom_rewards: Maybe>, } +impl fmt::Display for PoolId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "PoolId: {:?}", self.id) + } +} diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index d3ccc3f51b3..f1707120df7 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -4,18 +4,18 @@ use axum::{extract::Request, http::StatusCode, response::IntoResponse, Json, Rou // mod address; mod block; +mod cache; +pub mod common; mod fee; mod governance; mod loan; mod masternode; mod oracle; +mod path; mod pool_pair; pub mod prices; -// mod rawtx; -mod cache; -pub mod common; -mod path; mod query; +mod rawtx; mod response; mod stats; mod tokens; @@ -81,7 +81,7 @@ pub async fn ocean_router( .nest("/oracles", oracle::router(Arc::clone(&context))) .nest("/poolpairs", pool_pair::router(Arc::clone(&context))) .nest("/prices", prices::router(Arc::clone(&context))) - // .nest("/rawtx", rawtx::router(Arc::clone(&context))) + .nest("/rawtx", rawtx::router(Arc::clone(&context))) .nest("/stats", stats::router(Arc::clone(&context))) .nest("/tokens", tokens::router(Arc::clone(&context))) .nest("/transactions", transactions::router(Arc::clone(&context))) diff --git a/lib/ain-ocean/src/api/pool_pair/mod.rs b/lib/ain-ocean/src/api/pool_pair/mod.rs index 949b03fb202..529507fb6ce 100644 --- a/lib/ain-ocean/src/api/pool_pair/mod.rs +++ b/lib/ain-ocean/src/api/pool_pair/mod.rs @@ -19,6 +19,7 @@ use path::{ SwapPathsResponse, }; use petgraph::graphmap::UnGraphMap; +use price::DexPriceResponse; use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; use serde_json::json; @@ -44,8 +45,6 @@ use crate::{ Result, TokenIdentifier, }; -use price::DexPriceResponse; - pub mod path; pub mod price; pub mod service; diff --git a/lib/ain-ocean/src/api/pool_pair/price.rs b/lib/ain-ocean/src/api/pool_pair/price.rs index e4d1bf6f320..1bdb408d163 100644 --- a/lib/ain-ocean/src/api/pool_pair/price.rs +++ b/lib/ain-ocean/src/api/pool_pair/price.rs @@ -1,10 +1,9 @@ -use serde::Serialize; use std::{collections::HashMap, sync::Arc}; use defichain_rpc::json::token::TokenInfo; +use serde::Serialize; use super::{path::get_best_path, AppContext}; - use crate::{ api::{ cache::{get_token_cached, list_token_cached}, diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index b8b93fd6dde..d6d317c879a 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -1,5 +1,6 @@ use std::{collections::HashMap, str::FromStr, sync::Arc}; +use ain_dftx::{deserialize, pool::CompositeSwap, DfTx, Stack}; use anyhow::{format_err, Context}; use bitcoin::Txid; use defichain_rpc::{json::poolpair::PoolPairInfo, AccountRPC, BlockchainRPC}; @@ -21,7 +22,6 @@ use crate::{ storage::SortOrder, Result, }; -use ain_dftx::{deserialize, pool::CompositeSwap, DfTx, Stack}; #[allow(clippy::upper_case_acronyms)] #[derive(Serialize, Deserialize, Debug, Clone)] diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index d412441a689..f178b16c740 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -1,27 +1,223 @@ -use std::sync::Arc; +use std::{result::Result as StdResult, str::FromStr, sync::Arc}; +use ain_dftx::{deserialize, DfTx}; +use ain_macros::ocean_endpoint; use axum::{ + extract::{Json, Path}, routing::{get, post}, - Router, + Extension, Router, }; -use defichain_rpc::{Client, RpcApi}; -use super::path::Path; +use bitcoin::{Transaction, Txid}; +use defichain_rpc::{PoolPairRPC, RpcApi}; +use rust_decimal::prelude::ToPrimitive; +use rust_decimal_macros::dec; +use serde::{Deserialize, Serialize, Serializer}; -async fn send_rawtx() -> String { - "Sending raw transaction".to_string() +use super::{query::Query, response::Response, AppContext}; +use crate::{ + error::{ApiError, NotFoundKind}, + model::{default_max_fee_rate, MempoolAcceptResult, RawTransactionResult, RawTxDto}, + Error, Result, +}; + +enum TransactionResponse { + HexString(String), + TransactionDetails(Box), +} + +#[derive(Deserialize, Default)] +struct QueryParams { + verbose: bool, } -async fn test_rawtx() -> String { - "Testing raw transaction".to_string() +#[ocean_endpoint] +async fn send_raw_tx( + Extension(ctx): Extension>, + Json(raw_tx_dto): Json, +) -> Result { + validate(ctx.clone(), raw_tx_dto.hex.clone()).await?; + let max_fee = match raw_tx_dto.max_fee_rate { + Some(fee_rate) => { + let sat_per_bitcoin = dec!(100_000_000); + let fee_in_satoshis = fee_rate.checked_mul(sat_per_bitcoin); + match fee_in_satoshis { + Some(value) => Some(value.to_u64().unwrap_or_default()), + None => Some(default_max_fee_rate().to_sat()), + } + } + None => Some(default_max_fee_rate().to_sat()), + }; + match ctx + .client + .send_raw_transaction(raw_tx_dto.hex, max_fee) + .await + { + Ok(tx_hash) => Ok(tx_hash.to_string()), + Err(e) => { + eprintln!("Failed to send raw transaction: {:?}", e); + if e.to_string().contains("TX decode failed") { + Err(Error::BadRequest("Transaction decode failed".to_string())) + } else { + Err(Error::RpcError(e)) + } + } + } +} +#[ocean_endpoint] +async fn test_raw_tx( + Extension(ctx): Extension>, + Json(raw_tx_dto): Json, +) -> Result>> { + let trx = defichain_rpc::RawTx::raw_hex(raw_tx_dto.hex); + let max_fee = match raw_tx_dto.max_fee_rate { + Some(fee_rate) => { + let sat_per_bitcoin = dec!(100_000_000); + let fee_in_satoshis = fee_rate.checked_mul(sat_per_bitcoin); + match fee_in_satoshis { + Some(value) => Some(value.to_u64().unwrap_or_default()), + None => Some(default_max_fee_rate().to_sat()), + } + } + None => Some(default_max_fee_rate().to_sat()), + }; + match ctx.client.test_mempool_accept(&[trx], max_fee).await { + Ok(mempool_tx) => { + let results = mempool_tx + .into_iter() + .map(|tx_result| MempoolAcceptResult { + txid: tx_result.txid, + allowed: tx_result.allowed, + reject_reason: tx_result.reject_reason, + vsize: tx_result.vsize, + fees: tx_result.fees.map(|f| f.base), + }) + .collect::>(); + Ok(Response::new(results)) + } + Err(e) => { + eprintln!("Failed to send raw transaction: {:?}", e); + if e.to_string().contains("TX decode failed") { + Err(Error::BadRequest("Transaction decode failed".to_string())) + } else { + Err(Error::RpcError(e)) + } + } + } } -async fn get_rawtx(Path(txid): Path) -> String { - format!("Details of raw transaction with txid {}", txid) +impl Serialize for TransactionResponse { + fn serialize(&self, serializer: S) -> StdResult + where + S: Serializer, + { + match *self { + TransactionResponse::HexString(ref s) => serializer.serialize_str(s), + TransactionResponse::TransactionDetails(ref details) => details.serialize(serializer), + } + } +} + +#[ocean_endpoint] +async fn get_raw_tx( + Extension(ctx): Extension>, + Path(txid): Path, + Query(QueryParams { verbose }): Query, +) -> Result { + let tx_hash = Txid::from_str(&txid)?; + if !verbose { + let tx_hex = ctx.client.get_raw_transaction_hex(&tx_hash, None).await.map_err(|e| { + if e.to_string().contains("No such mempool or blockchain transaction. Use gettransaction for wallet transactions.") { + Error::NotFound(NotFoundKind::RawTx) + } else { + Error::RpcError(e) + } + })?; + Ok(TransactionResponse::HexString(tx_hex)) + } else { + let tx_info = ctx + .client + .get_raw_transaction_info(&tx_hash, None) + .await + .map_err(|e| { + eprintln!("Failed to get raw transaction hex: {:?}", e); + Error::RpcError(e) + })?; + let result = RawTransactionResult { + in_active_chain: tx_info.in_active_chain, + hex: tx_info.hex, + txid: tx_info.txid, + hash: tx_info.hash, + size: tx_info.size, + vsize: tx_info.vsize, + version: tx_info.version, + locktime: tx_info.locktime, + vin: tx_info.vin, + vout: tx_info.vout, + blockhash: tx_info.blockhash, + confirmations: tx_info.confirmations, + time: tx_info.time, + blocktime: tx_info.blocktime, + }; + Ok(TransactionResponse::TransactionDetails(Box::new(result))) + } +} + +async fn validate(ctx: Arc, hex: String) -> Result<()> { + if !hex.starts_with("040000000001") { + return Ok(()); + } + let data = hex::decode(hex)?; + println!("decode_hex {:?}", data); + let trx = deserialize::(&data)?; + let bytes = trx.output[0].clone().script_pubkey.into_bytes(); + let tx: Option = if bytes.len() > 2 && bytes[0] == 0x6a && bytes[1] <= 0x4e { + let offset = 1 + match bytes[1] { + 0x4c => 2, + 0x4d => 3, + 0x4e => 4, + _ => 1, + }; + + let raw_tx = &bytes[offset..]; + Some(deserialize::(raw_tx)?) + } else { + return Ok(()); + }; + + if let Some(tx) = tx { + if let DfTx::CompositeSwap(composite_swap) = tx { + if composite_swap.pools.as_ref().is_empty() { + return Ok(()); + } + let pool_id = composite_swap.pools.iter().last().unwrap(); + let tokio_id = composite_swap.pool_swap.to_token_id.0.to_string(); + let pool_pair = ctx + .client + .get_pool_pair(pool_id.to_string(), Some(true)) + .await?; + for (_, pool_pair_info) in pool_pair.0 { + if pool_pair_info.id_token_a.eq(&tokio_id) + || pool_pair_info.id_token_b.eq(&tokio_id) + { + println!("Found a match: {:?}", pool_pair_info); + } + } + Ok(()) + } else { + Err(Error::BadRequest( + "Transaction is not a composite swap".to_string(), + )) + } + } else { + Ok(()) + } } pub fn router(ctx: Arc) -> Router { + println!("{:?}", ctx.network); Router::new() - .route("/send", post(send_rawtx)) - .route("/test", get(test_rawtx)) - .route("/:txid", get(get_rawtx)) + .route("/send", post(send_raw_tx)) + .route("/test", post(test_raw_tx)) + .route("/:txid", get(get_raw_tx)) + .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 01f157c768a..4ad4ccf3c71 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -26,6 +26,8 @@ pub enum NotFoundKind { Token, #[error("poolpair")] PoolPair, + #[error("rawtx")] + RawTx, } #[derive(Error, Debug)] @@ -70,6 +72,10 @@ pub enum Error { TryFromIntError(#[from] std::num::TryFromIntError), #[error(transparent)] Other(#[from] anyhow::Error), + #[error("Validation error: {0}")] + ValidationError(String), + #[error("{0}")] + BadRequest(String), } #[derive(Serialize)] @@ -146,6 +152,7 @@ impl Error { ) } Error::NotFound(_) => (StatusCode::NOT_FOUND, format!("{self}")), + Error::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg.clone()), _ => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()), }; (code, reason) diff --git a/lib/ain-ocean/src/model/mod.rs b/lib/ain-ocean/src/model/mod.rs index 44afffc91cb..9ad04ef098d 100644 --- a/lib/ain-ocean/src/model/mod.rs +++ b/lib/ain-ocean/src/model/mod.rs @@ -12,6 +12,7 @@ mod poolswap; mod poolswap_aggregated; mod price_ticker; mod raw_block; +mod raw_tx; mod script_activity; mod script_aggregation; mod script_unspent; @@ -33,6 +34,7 @@ pub use oracle_token_currency::*; pub use poolswap::*; pub use poolswap_aggregated::*; pub use price_ticker::*; +pub use raw_tx::*; // pub use raw_block::*; // pub use script_activity::*; // pub use script_aggregation::*; diff --git a/lib/ain-ocean/src/model/raw_tx.rs b/lib/ain-ocean/src/model/raw_tx.rs new file mode 100644 index 00000000000..5d4f2e9e7f4 --- /dev/null +++ b/lib/ain-ocean/src/model/raw_tx.rs @@ -0,0 +1,42 @@ +use bitcoin::{Amount, Txid}; +use defichain_rpc::json::{GetRawTransactionResultVin, GetRawTransactionResultVout}; +use rust_decimal::Decimal; +use serde::{Deserialize, Serialize}; +#[derive(Serialize, Deserialize, Default, Clone)] +#[serde(rename_all = "camelCase")] +pub struct RawTxDto { + pub hex: String, + pub max_fee_rate: Option, +} + +pub fn default_max_fee_rate() -> Amount { + Amount::from_btc(0.1).unwrap_or_default() +} + +#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RawTransactionResult { + pub in_active_chain: Option, + pub hex: Vec, + pub txid: bitcoin::Txid, + pub hash: bitcoin::Wtxid, + pub size: usize, + pub vsize: usize, + pub version: u32, + pub locktime: u32, + pub vin: Vec, + pub vout: Vec, + pub blockhash: Option, + pub confirmations: Option, + pub time: Option, + pub blocktime: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct MempoolAcceptResult { + pub txid: Txid, + pub allowed: bool, + pub reject_reason: Option, + pub vsize: Option, + pub fees: Option, +} From a284782148909d38ece4c6dc3634c49782eceb18 Mon Sep 17 00:00:00 2001 From: Nagaraj <144004792+nagarajm22@users.noreply.github.com> Date: Mon, 15 Jul 2024 16:07:50 +0800 Subject: [PATCH 111/185] Ocean: fix governance APIs (listProposals, getProposal, listProposalVotes) (#2947) * updated sorting to list_gov_proposals api * update governance proposal list api * fixed amount param serializing * resolved the issue * fix get_burned_total AccountAmount * updated governance model * fixed clippy * fix ser model --------- Co-authored-by: canonbrother --- lib/Cargo.lock | 4 +- lib/ain-ocean/src/api/governance.rs | 24 +++--- lib/ain-ocean/src/api/stats/cache.rs | 26 +++++-- lib/ain-ocean/src/model/governance.rs | 91 ++++++++++++++++++++++ lib/ain-ocean/src/model/mod.rs | 2 + lib/ain-ocean/src/model/transaction_vin.rs | 2 +- 6 files changed, 130 insertions(+), 19 deletions(-) create mode 100644 lib/ain-ocean/src/model/governance.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 56aadea45a6..a54ac9b69bd 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -1530,7 +1530,7 @@ dependencies = [ [[package]] name = "defichain-rpc" version = "0.18.0" -source = "git+https://github.com/defich/rust-defichain-rpc.git#90b50580fb913a58e474c66a26dc21c7a9b97d95" +source = "git+https://github.com/defich/rust-defichain-rpc.git#4c13276a20fc94de45f0b27f0cb2a00e78e389a5" dependencies = [ "async-trait", "defichain-rpc-json", @@ -1543,7 +1543,7 @@ dependencies = [ [[package]] name = "defichain-rpc-json" version = "0.18.0" -source = "git+https://github.com/defich/rust-defichain-rpc.git#90b50580fb913a58e474c66a26dc21c7a9b97d95" +source = "git+https://github.com/defich/rust-defichain-rpc.git#4c13276a20fc94de45f0b27f0cb2a00e78e389a5" dependencies = [ "bitcoin", "serde", diff --git a/lib/ain-ocean/src/api/governance.rs b/lib/ain-ocean/src/api/governance.rs index cbb78aba701..069c108339b 100644 --- a/lib/ain-ocean/src/api/governance.rs +++ b/lib/ain-ocean/src/api/governance.rs @@ -14,6 +14,7 @@ use super::{ }; use crate::{ error::{ApiError, Error, NotFoundKind}, + model::ApiProposalInfo, Result, }; @@ -23,7 +24,7 @@ pub struct GovernanceQuery { pub pagination: PaginationQuery, pub status: Option, pub r#type: Option, - pub cycle: Option, + pub cycle: Option, pub all: Option, pub masternode: Option, } @@ -32,7 +33,7 @@ pub struct GovernanceQuery { async fn list_gov_proposals( Query(query): Query, Extension(ctx): Extension>, -) -> Result> { +) -> Result> { let size = match query.all { Some(true) => 0, _ => query.pagination.size, @@ -41,6 +42,7 @@ async fn list_gov_proposals( let opts = ListProposalsOptions { pagination: Some(ListProposalsPagination { limit: Some(size), + start: query.pagination.next.clone(), ..ListProposalsPagination::default() }), status: query.status, @@ -48,23 +50,27 @@ async fn list_gov_proposals( cycle: query.cycle, }; let proposals = ctx.client.list_gov_proposals(Some(opts)).await?; - - Ok(ApiPagedResponse::of(proposals, size, |proposal| { - proposal.proposal_id.to_string() - })) + let mut proposals_with_string_amount: Vec = + proposals.into_iter().map(ApiProposalInfo::from).collect(); + proposals_with_string_amount.sort_by(|a, b| a.creation_height.cmp(&b.creation_height)); + Ok(ApiPagedResponse::of( + proposals_with_string_amount, + size, + |proposal| proposal.proposal_id.to_string(), + )) } #[ocean_endpoint] async fn get_gov_proposal( - Path(proposal_id): Path, Extension(ctx): Extension>, -) -> Result> { + Path(proposal_id): Path, +) -> Result> { let txid: Txid = proposal_id .parse() .map_err(|_| Error::NotFound(NotFoundKind::Proposal))?; let proposal = ctx.client.get_gov_proposal(txid).await?; - Ok(Response::new(proposal)) + Ok(Response::new(proposal.into())) } #[ocean_endpoint] diff --git a/lib/ain-ocean/src/api/stats/cache.rs b/lib/ain-ocean/src/api/stats/cache.rs index 672a694a59c..4bd3df8edab 100644 --- a/lib/ain-ocean/src/api/stats/cache.rs +++ b/lib/ain-ocean/src/api/stats/cache.rs @@ -1,8 +1,10 @@ -use std::{collections::HashMap, sync::Arc}; +use std::{collections::HashMap, str::FromStr, sync::Arc}; +use anyhow::format_err; use cached::proc_macro::cached; use defichain_rpc::{ - defichain_rpc_json::token::TokenPagination, AccountRPC, Client, LoanRPC, TokenRPC, + defichain_rpc_json::token::TokenPagination, json::account::AccountAmount, AccountRPC, Client, + LoanRPC, TokenRPC, }; use rust_decimal::{ prelude::{FromPrimitive, Zero}, @@ -119,7 +121,7 @@ lazy_static::lazy_static! { )] pub async fn get_burned_total(ctx: &AppContext) -> Result { let burn_address = BURN_ADDRESS.get(ctx.network.as_str()).unwrap(); - let mut tokens = ctx + let accounts = ctx .client .get_account(burn_address, None, Some(true)) .await?; @@ -129,10 +131,20 @@ pub async fn get_burned_total(ctx: &AppContext) -> Result { let emission = Decimal::from_f64(burn_info.emissionburn).ok_or(Error::DecimalConversionError)?; let fee = Decimal::from_f64(burn_info.feeburn).ok_or(Error::DecimalConversionError)?; - let account_balance = tokens - .0 - .remove("0") - .map_or(dec!(0), |v| Decimal::from_f64(v).unwrap_or_default()); + let account_balance = if let AccountAmount::List(accounts) = accounts { + for account in accounts { + let parts = account.split('@').collect::>(); + let [amount, token_id] = <[&str; 2]>::try_from(parts) + .map_err(|_| format_err!("Invalid account structure"))?; + + if token_id == "DFI" { + return Ok(Decimal::from_str(amount).unwrap_or_default()); + } + } + dec!(0) + } else { + dec!(0) + }; Ok(utxo + account_balance + emission + fee) } diff --git a/lib/ain-ocean/src/model/governance.rs b/lib/ain-ocean/src/model/governance.rs new file mode 100644 index 00000000000..8cc86ead9aa --- /dev/null +++ b/lib/ain-ocean/src/model/governance.rs @@ -0,0 +1,91 @@ +use defichain_rpc::json::governance::{ProposalInfo, ProposalStatus, ProposalType}; +use serde::Serialize; +use serde_with::skip_serializing_none; + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ApiProposalInfo { + pub proposal_id: String, + pub title: String, + pub context: String, + pub context_hash: String, + pub r#type: ProposalType, + pub status: ProposalStatus, + pub current_cycle: u64, + pub total_cycles: u64, + pub creation_height: u64, + pub cycle_end_height: u64, + pub proposal_end_height: u64, + pub voting_period: u64, + pub approval_threshold: String, + pub quorum: String, + #[serde(flatten)] + pub confidence_vote: ApiProposalConfidenceVote, + #[serde(flatten)] + pub vote_info: ApiProposalVoteInfo, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ApiProposalConfidenceVote { + pub amount: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub payout_address: Option, +} + +#[skip_serializing_none] +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ApiProposalVoteInfo { + pub votes_possible: Option, + pub votes_present: Option, + pub votes_present_pct: Option, + pub votes_yes: Option, + pub votes_invalid: Option, + pub votes_neutral: Option, + pub votes_no: Option, + pub votes_yes_pct: Option, + pub fee: f64, + pub options: Option>, + pub fee_redistribution_per_vote: Option, + pub fee_redistribution_total: Option, +} + +impl From for ApiProposalInfo { + fn from(proposal: ProposalInfo) -> Self { + ApiProposalInfo { + proposal_id: proposal.proposal_id, + title: proposal.title, + context: proposal.context, + context_hash: proposal.context_hash, + r#type: proposal.r#type, + status: proposal.status, + current_cycle: proposal.current_cycle, + total_cycles: proposal.total_cycles, + creation_height: proposal.creation_height, + cycle_end_height: proposal.cycle_end_height, + proposal_end_height: proposal.proposal_end_height, + voting_period: proposal.voting_period, + approval_threshold: proposal.approval_threshold, + quorum: proposal.quorum, + confidence_vote: ApiProposalConfidenceVote { + amount: proposal.amount.map(|a| format!("{:.8}", a)), + payout_address: proposal.payout_address, + }, + vote_info: ApiProposalVoteInfo { + votes_possible: proposal.votes_possible, + votes_present: proposal.votes_present, + votes_present_pct: proposal.votes_present_pct, + votes_yes: proposal.votes_yes, + votes_invalid: proposal.votes_invalid, + votes_neutral: proposal.votes_neutral, + votes_no: proposal.votes_no, + votes_yes_pct: proposal.votes_yes_pct, + fee: proposal.fee, + options: proposal.options, + fee_redistribution_per_vote: proposal.fee_redistribution_per_vote, + fee_redistribution_total: proposal.fee_redistribution_total, + }, + } + } +} diff --git a/lib/ain-ocean/src/model/mod.rs b/lib/ain-ocean/src/model/mod.rs index 9ad04ef098d..bd11c3ce941 100644 --- a/lib/ain-ocean/src/model/mod.rs +++ b/lib/ain-ocean/src/model/mod.rs @@ -1,4 +1,5 @@ mod block; +mod governance; mod masternode; mod masternode_stats; pub mod oracle; @@ -22,6 +23,7 @@ mod transaction_vout; mod tx_result; mod vault_auction_batch_history; pub use block::*; +pub use governance::*; pub use masternode::*; pub use masternode_stats::*; pub use oracle::*; diff --git a/lib/ain-ocean/src/model/transaction_vin.rs b/lib/ain-ocean/src/model/transaction_vin.rs index 08acc9234e2..08413762e88 100644 --- a/lib/ain-ocean/src/model/transaction_vin.rs +++ b/lib/ain-ocean/src/model/transaction_vin.rs @@ -28,7 +28,7 @@ impl TransactionVin { tx_in_witness: None, }, Vin::Standard(v) => { - let vout = vouts.get(v.vout as usize).map(|vout| TransactionVinVout { + let vout = vouts.get(v.vout).map(|vout| TransactionVinVout { txid: vout.txid, value: vout.value, n: vout.n, From 5700a1d6569c4cecd37e607ab0ec168ccb2ffb3b Mon Sep 17 00:00:00 2001 From: canonbrother Date: Mon, 15 Jul 2024 17:48:13 +0800 Subject: [PATCH 112/185] Ocean: address indexers + apis (#2946) * script activity indexer * refine + helper::check_if_evm_tx + error::NotFoundIndex * fmt * api * fmt * fix * fmt * Ocean: indexer script unspent + api.address.list_transactions_unspent (#2948) * script unspent indexer * list_tx_unspent api * fmt * Ocean: indexer script aggregation + api.address.get_balance & get_aggregation (#2949) * script aggregation indexer * fmt * address api: get_balance + get_aggregation * get_balance return string * decimal to string as deserialize not support in decimal * fix NotFoundIndex params * fix script agg indexer * ScriptAggregationResponse * 8 decimal * decimal -> f64 * map api resp & fix sorting * fix paginate * fmt * script activity uses find_tx_vout * fix tx getvouts sort asc * fix indexer_script_activity, index_tx order correction, refine find_tx_vout, rm unuse * resp mapping * fmt * rust-defichain-rpc main --- lib/Cargo.lock | 5 +- lib/Cargo.toml | 1 + lib/ain-ocean/Cargo.toml | 1 + lib/ain-ocean/src/api/address.rs | 418 ++++++++++++++++-- lib/ain-ocean/src/api/common.rs | 15 + lib/ain-ocean/src/api/mod.rs | 4 +- lib/ain-ocean/src/api/transactions.rs | 2 +- lib/ain-ocean/src/error.rs | 28 +- lib/ain-ocean/src/hex_encoder.rs | 7 + lib/ain-ocean/src/indexer/helper.rs | 16 + lib/ain-ocean/src/indexer/mod.rs | 369 +++++++++++++++- lib/ain-ocean/src/indexer/transaction.rs | 35 +- lib/ain-ocean/src/lib.rs | 33 +- lib/ain-ocean/src/model/mod.rs | 6 +- lib/ain-ocean/src/model/script_activity.rs | 47 +- lib/ain-ocean/src/model/script_aggregation.rs | 21 +- lib/ain-ocean/src/model/script_unspent.rs | 16 +- lib/ain-ocean/src/model/transaction_vin.rs | 6 +- lib/ain-ocean/src/model/transaction_vout.rs | 5 +- lib/ain-ocean/src/repository/mod.rs | 6 +- .../src/repository/script_activity.rs | 17 + .../src/repository/script_aggregation.rs | 17 + .../src/repository/script_unspent.rs | 37 ++ lib/ain-ocean/src/storage/columns/mod.rs | 3 +- .../src/storage/columns/script_activity.rs | 7 +- .../src/storage/columns/script_aggregation.rs | 5 +- .../src/storage/columns/script_unspent.rs | 20 +- 27 files changed, 1013 insertions(+), 134 deletions(-) create mode 100644 lib/ain-ocean/src/hex_encoder.rs create mode 100644 lib/ain-ocean/src/indexer/helper.rs diff --git a/lib/Cargo.lock b/lib/Cargo.lock index a54ac9b69bd..03314745039 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -274,6 +274,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "serde_with", + "sha2 0.10.8", "tempdir", "tempfile", "thiserror", @@ -1530,7 +1531,7 @@ dependencies = [ [[package]] name = "defichain-rpc" version = "0.18.0" -source = "git+https://github.com/defich/rust-defichain-rpc.git#4c13276a20fc94de45f0b27f0cb2a00e78e389a5" +source = "git+https://github.com/defich/rust-defichain-rpc.git#550743d7b18bbd9bc0ddc6a9ecbb16d7d72151f7" dependencies = [ "async-trait", "defichain-rpc-json", @@ -1543,7 +1544,7 @@ dependencies = [ [[package]] name = "defichain-rpc-json" version = "0.18.0" -source = "git+https://github.com/defich/rust-defichain-rpc.git#4c13276a20fc94de45f0b27f0cb2a00e78e389a5" +source = "git+https://github.com/defich/rust-defichain-rpc.git#550743d7b18bbd9bc0ddc6a9ecbb16d7d72151f7" dependencies = [ "bitcoin", "serde", diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 353dc5ba9d7..df3ddb4b24d 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -61,6 +61,7 @@ prettyplease = "0.2.4" libsecp256k1 = "0.7" ripemd = { version = "0.1", default-features = false } sha3 = "0.10" +sha2 = { version = "0.10", default-features = false } ## common diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index 6130290514d..2743abd2a91 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -47,6 +47,7 @@ num_cpus.workspace = true petgraph = { version = "0.6.4", features = ["serde-1"] } parking_lot.workspace = true indexmap.workspace = true +sha2.workspace = true [dev-dependencies] tempdir.workspace = true diff --git a/lib/ain-ocean/src/api/address.rs b/lib/ain-ocean/src/api/address.rs index 7a9df60ef80..8d2dbd6b400 100644 --- a/lib/ain-ocean/src/api/address.rs +++ b/lib/ain-ocean/src/api/address.rs @@ -1,74 +1,398 @@ -use std::sync::Arc; +use std::{str::FromStr, sync::Arc}; -use axum::{routing::get, Router}; -use defichain_rpc::{Client, RpcApi}; -use serde::Deserialize; -use super::path::Path; +use super::{ + common::address_to_hid, + path::Path, + query::{PaginationQuery, Query}, + response::{ApiPagedResponse, Response}, + AppContext, +}; +use crate::{ + error::ApiError, + model::{ + BlockContext, ScriptActivity, ScriptActivityTypeHex, ScriptAggregation, ScriptUnspent, + }, + repository::RepositoryOps, + storage::SortOrder, + Error, Result, +}; +use ain_macros::ocean_endpoint; +use axum::{routing::get, Extension, Router}; +use bitcoin::{hashes::Hash, hex::DisplayHex, Txid}; +use serde::{Deserialize, Serialize}; +use serde_with::skip_serializing_none; #[derive(Deserialize)] struct Address { address: String, } -#[derive(Deserialize)] -struct History { - address: String, - height: i64, - txno: i64, +// #[derive(Deserialize)] +// struct History { +// address: String, +// height: i64, +// txno: i64, +// } + +// async fn get_account_history( +// Path(History { +// address, +// height, +// txno, +// }): Path, +// ) -> String { +// format!( +// "Account history for address {}, height {}, txno {}", +// address, height, txno +// ) +// } + +// async fn list_account_history(Path(Address { address }): Path
) -> String { +// format!("List account history for address {}", address) +// } + +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ScriptAggregationResponse { + pub id: String, + pub hid: String, + pub block: BlockContext, + pub script: ScriptAggregationScriptResponse, + pub statistic: ScriptAggregationStatisticResponse, + pub amount: ScriptAggregationAmountResponse, } -async fn get_account_history( - Path(History { - address, - height, - txno, - }): Path, -) -> String { - format!( - "Account history for address {}, height {}, txno {}", - address, height, txno - ) +impl From for ScriptAggregationResponse { + fn from(v: ScriptAggregation) -> Self { + Self { + id: format!("{}{}", hex::encode(v.id.1.to_be_bytes()), v.id.0), + hid: v.hid, + block: v.block, + script: ScriptAggregationScriptResponse { + r#type: v.script.r#type, + hex: v.script.hex.as_hex().to_string(), + }, + statistic: ScriptAggregationStatisticResponse { + tx_count: v.statistic.tx_count, + tx_in_count: v.statistic.tx_in_count, + tx_out_count: v.statistic.tx_out_count, + }, + amount: ScriptAggregationAmountResponse { + tx_in: format!("{:.8}", v.amount.tx_in), + tx_out: format!("{:.8}", v.amount.tx_out), + unspent: format!("{:.8}", v.amount.unspent), + }, + } + } } -async fn list_account_history(Path(Address { address }): Path
) -> String { - format!("List account history for address {}", address) +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ScriptAggregationScriptResponse { + pub r#type: String, + pub hex: String, } -async fn get_balance(Path(Address { address }): Path
) -> String { - format!("balance for address {address}") +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ScriptAggregationStatisticResponse { + pub tx_count: i32, + pub tx_in_count: i32, + pub tx_out_count: i32, } -async fn get_aggregation(Path(Address { address }): Path
) -> String { - format!("Aggregation for address {}", address) +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ScriptAggregationAmountResponse { + pub tx_in: String, + pub tx_out: String, + pub unspent: String, } -async fn list_token(Path(Address { address }): Path
) -> String { - format!("List tokens for address {}", address) +fn get_latest_aggregation( + ctx: &Arc, + hid: String, +) -> Result> { + let latest = ctx + .services + .script_aggregation + .by_id + .list(Some((hid.clone(), u32::MAX)), SortOrder::Descending)? + .take(1) + .take_while(|item| match item { + Ok(((v, _), _)) => v == &hid, + _ => true, + }) + .map(|item| { + let (_, v) = item?; + let res = v.into(); + Ok(res) + }) + .collect::>>()?; + + Ok(latest.first().cloned()) } -async fn list_vault(Path(Address { address }): Path
) -> String { - format!("List vaults for address {}", address) +#[ocean_endpoint] +async fn get_balance( + Path(Address { address }): Path
, + Extension(ctx): Extension>, +) -> Result> { + let hid = address_to_hid(&address, ctx.network.into())?; + let aggregation = get_latest_aggregation(&ctx, hid)?; + if aggregation.is_none() { + return Ok(Response::new("0.00000000".to_string())); + } + let aggregation = aggregation.unwrap(); + Ok(Response::new(aggregation.amount.unspent)) } -async fn list_transaction(Path(Address { address }): Path
) -> String { - format!("List transactions for address {}", address) +#[ocean_endpoint] +async fn get_aggregation( + Path(Address { address }): Path
, + Extension(ctx): Extension>, +) -> Result>> { + let hid = address_to_hid(&address, ctx.network.into())?; + let aggregation = get_latest_aggregation(&ctx, hid)?; + Ok(Response::new(aggregation)) } -async fn list_transaction_unspent(Path(Address { address }): Path
) -> String { - format!("List unspent transactions for address {}", address) +// async fn list_token(Path(Address { address }): Path
) -> String { +// format!("List tokens for address {}", address) +// } + +// async fn list_vault(Path(Address { address }): Path
) -> String { +// format!("List vaults for address {}", address) +// } + +#[skip_serializing_none] +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ScriptActivityResponse { + pub id: String, + pub hid: String, + pub r#type: String, + pub type_hex: String, + pub txid: Txid, + pub block: BlockContext, + pub script: ScriptActivityScriptResponse, + pub vin: Option, + pub vout: Option, + pub value: String, + pub token_id: Option, +} + +impl From for ScriptActivityResponse { + fn from(v: ScriptActivity) -> Self { + Self { + id: v.id, + hid: v.hid, + r#type: v.r#type.to_string(), + type_hex: v.type_hex.to_string(), + txid: v.txid, + block: v.block, + script: ScriptActivityScriptResponse { + r#type: v.script.r#type, + hex: v.script.hex.to_lower_hex_string(), + }, + vin: v.vin.map(|vin| ScriptActivityVinVoutResponse { + txid: vin.txid, + n: vin.n, + }), + vout: v.vout.map(|vout| ScriptActivityVinVoutResponse { + txid: vout.txid, + n: vout.n, + }), + value: v.value, + token_id: v.token_id, + } + } +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ScriptActivityScriptResponse { + pub r#type: String, + pub hex: String, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ScriptActivityVinVoutResponse { + pub txid: Txid, + pub n: usize, +} + +#[ocean_endpoint] +async fn list_transactions( + Path(Address { address }): Path
, + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let hid = address_to_hid(&address, ctx.network.into())?; + let next = query + .next + .as_ref() + .map(|next| { + let height = &next[0..8]; + let vin_vout_type = &next[8..8 + 2]; + let txid = &next[8 + 2..64 + 8 + 2]; + let n = &next[64 + 8 + 2..]; + + let height = height.parse::()?; + let vin_vout_type = match vin_vout_type { + "00" => ScriptActivityTypeHex::Vin, + _ => ScriptActivityTypeHex::Vout, + }; + let txid = Txid::from_str(txid)?; + let n = n.parse::()?; + Ok::<(u32, ScriptActivityTypeHex, Txid, usize), Error>((height, vin_vout_type, txid, n)) + }) + .transpose()? + .unwrap_or(( + u32::MAX, + ScriptActivityTypeHex::Vout, + Txid::from_byte_array([0xffu8; 32]), + usize::MAX, + )); + + let res = ctx + .services + .script_activity + .by_id + .list( + Some((hid.clone(), next.0, next.1, next.2, next.3)), + SortOrder::Descending, + )? + .skip(query.next.is_some() as usize) + .take(query.size) + .take_while(|item| match item { + Ok((k, _)) => k.0 == hid, + _ => true, + }) + .map(|item| { + let (_, v) = item?; + Ok(v.into()) + }) + .collect::>>()?; + + Ok(ApiPagedResponse::of(res, query.size, |item| { + item.id.clone() + })) +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ScriptUnspentResponse { + pub id: String, + pub hid: String, + pub sort: String, + pub block: BlockContext, + pub script: ScriptUnspentScriptResponse, + pub vout: ScriptUnspentVoutResponse, +} + +impl From for ScriptUnspentResponse { + fn from(v: ScriptUnspent) -> Self { + Self { + id: v.id, + hid: v.hid, + sort: v.sort, + block: v.block, + script: ScriptUnspentScriptResponse { + r#type: v.script.r#type, + hex: v.script.hex.to_lower_hex_string(), + }, + vout: ScriptUnspentVoutResponse { + txid: v.vout.txid, + n: v.vout.n, + value: format!("{:.8}", v.vout.value), + token_id: v.vout.token_id, + }, + } + } +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ScriptUnspentScriptResponse { + pub r#type: String, + pub hex: String, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ScriptUnspentVoutResponse { + pub txid: Txid, + pub n: usize, + pub value: String, + pub token_id: Option, +} + +#[ocean_endpoint] +async fn list_transaction_unspent( + Path(Address { address }): Path
, + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let hid = address_to_hid(&address, ctx.network.into())?; + + let next = query + .next + .as_ref() + .map(|next| { + let height = &next[0..8]; + let txid = &next[8..64 + 8]; + let n = &next[64 + 8..]; + + let txid = Txid::from_str(txid)?; + Ok::<(String, Txid, String), Error>((height.to_string(), txid, n.to_string())) + }) + .transpose()? + .unwrap_or(( + "0".to_string(), + Txid::from_byte_array([0x00u8; 32]), + "0".to_string(), + )); + + let res = ctx + .services + .script_unspent + .by_id + .list( + Some((hid.clone(), next.0, next.1, next.2)), + SortOrder::Ascending, + )? + .skip(query.next.is_some() as usize) + .take(query.size) + .take_while(|item| match item { + Ok((k, _)) => k.0 == hid.clone(), + _ => true, + }) + .map(|item| { + let (_, v) = item?; + let res = v.into(); + Ok(res) + }) + .collect::>>()?; + + Ok(ApiPagedResponse::of(res, query.size, |item| { + item.sort.clone() + })) } pub fn router(ctx: Arc) -> Router { - Router::new().nest( - "/:address", - Router::new() - .route("/history/:height/:txno", get(get_account_history)) - .route("/history", get(list_account_history)) - .route("/balance", get(get_balance)) - .route("/aggregation", get(get_aggregation)) - .route("/tokens", get(list_token)) - .route("/vaults", get(list_vault)) - .route("/transactions", get(list_transaction)) - .route("/transactions/unspent", get(list_transaction_unspent)), - ) + Router::new() + // .route("/history/:height/:txno", get(get_account_history)) + // .route("/history", get(list_account_history)) + .route("/:address/balance", get(get_balance)) + .route("/:address/aggregation", get(get_aggregation)) + // .route("/tokens", get(list_token)) + // .route("/vaults", get(list_vault)) + .route("/:address/transactions", get(list_transactions)) + .route( + "/:address/transactions/unspent", + get(list_transaction_unspent), + ) + .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/api/common.rs b/lib/ain-ocean/src/api/common.rs index c7653de0df0..80c604c60e7 100644 --- a/lib/ain-ocean/src/api/common.rs +++ b/lib/ain-ocean/src/api/common.rs @@ -1,7 +1,11 @@ +use anyhow::format_err; use bitcoin::{Address, Network, ScriptBuf}; use defichain_rpc::json::token::TokenInfo; use rust_decimal::Decimal; use rust_decimal_macros::dec; +use std::str::FromStr; + +use crate::hex_encoder::as_sha256; use super::query::PaginationQuery; @@ -46,6 +50,17 @@ pub fn from_script(script: ScriptBuf, network: Network) -> crate::Result Ok(address) } +pub fn to_script(address: &str, network: Network) -> crate::Result { + let addr = Address::from_str(address)?.require_network(network)?; + Ok(ScriptBuf::from(addr)) +} + +pub fn address_to_hid(address: &str, network: Network) -> crate::Result { + let script = to_script(address, network).map_err(|_| format_err!("InvalidDefiAddress"))?; + let bytes = script.to_bytes(); + Ok(as_sha256(bytes)) +} + /// Finds the balance of a specified token symbol within a list of token strings. /// /// This function iterates through a vector of token strings, where each string diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index f1707120df7..0b90f58e894 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -2,7 +2,7 @@ use std::{str::FromStr, sync::Arc}; use axum::{extract::Request, http::StatusCode, response::IntoResponse, Json, Router}; -// mod address; +mod address; mod block; mod cache; pub mod common; @@ -73,7 +73,7 @@ pub async fn ocean_router( Ok(Router::new().nest( format!("/v0/{}", context.network).as_str(), Router::new() - // .nest("/address/", address::router(Arc::clone(&context))) + .nest("/address/", address::router(Arc::clone(&context))) .nest("/governance", governance::router(Arc::clone(&context))) .nest("/loans", loan::router(Arc::clone(&context))) .nest("/fee", fee::router(Arc::clone(&context))) diff --git a/lib/ain-ocean/src/api/transactions.rs b/lib/ain-ocean/src/api/transactions.rs index 87c3f5d97c1..262c75c8240 100644 --- a/lib/ain-ocean/src/api/transactions.rs +++ b/lib/ain-ocean/src/api/transactions.rs @@ -75,7 +75,7 @@ async fn get_vouts( .services .transaction .vout_by_id - .list(Some((id, next)), SortOrder::Descending)? + .list(Some((id, next)), SortOrder::Ascending)? .paginate(&query) .take_while(|item| match item { Ok((_, vout)) => vout.txid == id, diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 4ad4ccf3c71..f93114e2df5 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -1,4 +1,7 @@ -use std::num::ParseIntError; +use std::{ + fmt, + num::{ParseFloatError, ParseIntError}, +}; use ain_db::DBError; use anyhow::format_err; @@ -12,6 +15,21 @@ use serde::Serialize; use serde_json::json; use thiserror::Error; +#[derive(Debug)] +pub enum IndexAction { + Index, + Invalidate, +} + +impl fmt::Display for IndexAction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + IndexAction::Index => write!(f, "index"), + IndexAction::Invalidate => write!(f, "invalidate"), + } + } +} + #[derive(Error, Debug)] pub enum NotFoundKind { #[error("proposal")] @@ -38,6 +56,8 @@ pub enum Error { HexToArrayError(#[from] HexToArrayError), #[error("Ocean: ParseIntError error: {0:?}")] ParseIntError(#[from] ParseIntError), + #[error("Ocean: ParseFloatError error: {0:?}")] + ParseFloatError(#[from] ParseFloatError), #[error("Ocean: DBError error: {0:?}")] DBError(#[from] DBError), #[error("Ocean: IO error: {0:?}")] @@ -54,6 +74,10 @@ pub enum Error { RpcError(#[from] defichain_rpc::Error), #[error("Unable to find {0:}")] NotFound(NotFoundKind), + #[error( + "attempting to sync: {0:?} but type: {1:?} with id: {2:?} cannot be found in the index" + )] + NotFoundIndex(IndexAction, String, String), #[error("Ocean: Decimal error: {0:?}")] DecimalError(#[from] rust_decimal::Error), #[error("Decimal conversion error")] @@ -70,6 +94,8 @@ pub enum Error { BitcoinAddressError(#[from] bitcoin::address::Error), #[error("Ocean: TryFromIntError: {0:?}")] TryFromIntError(#[from] std::num::TryFromIntError), + #[error("{0:}")] + AddressParseError(#[from] bitcoin::address::error::ParseError), #[error(transparent)] Other(#[from] anyhow::Error), #[error("Validation error: {0}")] diff --git a/lib/ain-ocean/src/hex_encoder.rs b/lib/ain-ocean/src/hex_encoder.rs new file mode 100644 index 00000000000..a7ec4b92718 --- /dev/null +++ b/lib/ain-ocean/src/hex_encoder.rs @@ -0,0 +1,7 @@ +use sha2::{Digest, Sha256}; + +pub fn as_sha256(bytes: Vec) -> String { + let mut hasher = Sha256::new(); + hasher.update(bytes); + format!("{:x}", hasher.finalize()) +} diff --git a/lib/ain-ocean/src/indexer/helper.rs b/lib/ain-ocean/src/indexer/helper.rs new file mode 100644 index 00000000000..40378314ae5 --- /dev/null +++ b/lib/ain-ocean/src/indexer/helper.rs @@ -0,0 +1,16 @@ +use bitcoin::{hashes::Hash, Txid}; +use defichain_rpc::json::blockchain::{Transaction, Vin}; + +pub fn check_if_evm_tx(txn: &Transaction) -> bool { + txn.vin.len() == 2 + && txn.vin.iter().all(|vin| match vin { + Vin::Coinbase(_) => true, + Vin::Standard(tx) => tx.txid == Txid::all_zeros(), + }) + && txn.vout.len() == 1 + && txn.vout[0] + .script_pub_key + .asm + .starts_with("OP_RETURN 4466547839") + && txn.vout[0].value == 0f64 +} diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 9f7ebf30a05..983e10cc633 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -8,19 +8,31 @@ pub mod poolswap; pub mod transaction; pub mod tx_result; -use std::{sync::Arc, time::Instant}; +pub mod helper; + +use std::{collections::HashMap, sync::Arc, time::Instant}; use ain_dftx::{deserialize, is_skipped_tx, DfTx, Stack}; -use defichain_rpc::json::blockchain::{Block, Transaction}; +use defichain_rpc::json::blockchain::{Block, Transaction, Vin, VinStandard}; +use helper::check_if_evm_tx; use log::debug; pub use poolswap::{PoolCreationHeight, PoolSwapAggregatedInterval, AGGREGATED_INTERVALS}; +use rust_decimal::{prelude::FromPrimitive, Decimal}; use crate::{ + error::IndexAction, + hex_encoder::as_sha256, index_transaction, - model::{Block as BlockMapper, BlockContext, PoolSwapAggregated, PoolSwapAggregatedAggregated}, + model::{ + Block as BlockMapper, BlockContext, PoolSwapAggregated, PoolSwapAggregatedAggregated, + ScriptActivity, ScriptActivityScript, ScriptActivityType, ScriptActivityTypeHex, + ScriptActivityVin, ScriptActivityVout, ScriptAggregation, ScriptAggregationAmount, + ScriptAggregationScript, ScriptAggregationStatistic, ScriptUnspent, ScriptUnspentScript, + ScriptUnspentVout, TransactionVout, TransactionVoutScript, + }, repository::{RepositoryOps, SecondaryIndex}, storage::SortOrder, - Result, Services, + Error, Result, Services, }; pub(crate) trait Index { @@ -117,6 +129,342 @@ fn index_block_start(services: &Arc, block: &Block) -> Re Ok(()) } +fn get_vin_standard(vin: &Vin) -> Option { + match vin { + Vin::Coinbase(_vin) => None, + Vin::Standard(vin) => Some(vin.clone()), + } +} + +fn find_tx_vout( + services: &Arc, + block: &Block, + vin: &VinStandard, +) -> Result> { + let tx = block.tx.clone().into_iter().find(|tx| tx.txid == vin.txid); + + if let Some(tx) = tx { + let vout = tx.vout.into_iter().find(|vout| vout.n == vin.vout); + + if let Some(vout) = vout { + let value = Decimal::from_f64(vout.value).ok_or(Error::DecimalConversionError)?; + let tx_vout = TransactionVout { + id: format!("{}{:x}", tx.txid, vin.vout), + txid: tx.txid, + n: vout.n, + value: format!("{:.8}", value), + token_id: vout.token_id, + script: TransactionVoutScript { + r#type: vout.script_pub_key.r#type.clone(), + hex: vout.script_pub_key.hex.clone(), + }, + }; + return Ok(Some(tx_vout)); + } + } + services.transaction.vout_by_id.get(&(vin.txid, vin.vout)) +} + +fn index_script_activity(services: &Arc, block: &Block) -> Result<()> { + for tx in block.tx.iter() { + if check_if_evm_tx(tx) { + continue; + } + + for vin in tx.vin.iter() { + let vin_standard = get_vin_standard(vin); + if vin_standard.is_none() { + continue; + } + let vin = vin_standard.unwrap(); + let vout = find_tx_vout(services, block, &vin)?; + if vout.is_none() { + log::error!("attempting to sync: {:?} but type: TransactionVout with id:{}-{} cannot be found in the index", IndexAction::Index, vin.txid, vin.vout); + continue; + } + let vout = vout.unwrap(); + + let hid = as_sha256(vout.script.hex.clone()); // as key + let script_activity = ScriptActivity { + id: format!( + "{}{}{}{}", + hex::encode(block.height.to_be_bytes()), + ScriptActivityTypeHex::Vin, + vin.txid, + hex::encode(vin.vout.to_be_bytes()) + ), + hid: hid.clone(), + r#type: ScriptActivityType::Vin, + type_hex: ScriptActivityTypeHex::Vin, + txid: tx.txid, + block: BlockContext { + hash: block.hash, + height: block.height, + time: block.time, + median_time: block.mediantime, + }, + script: ScriptActivityScript { + r#type: vout.script.r#type, + hex: vout.script.hex, + }, + vin: Some(ScriptActivityVin { + txid: vin.txid, + n: vin.vout, + }), + vout: None, + value: format!("{:.8}", vout.value.parse::()?), + token_id: vout.token_id, + }; + let id = ( + hid, + block.height, + ScriptActivityTypeHex::Vin, + vin.txid, + vin.vout, + ); + services.script_activity.by_id.put(&id, &script_activity)? + } + + for vout in tx.vout.iter() { + if vout.script_pub_key.hex.starts_with(&[0x6a]) { + continue; + } + let hid = as_sha256(vout.script_pub_key.hex.clone()); + let script_activity = ScriptActivity { + id: format!( + "{}{}{}{}", + hex::encode(block.height.to_be_bytes()), + ScriptActivityTypeHex::Vout, + tx.txid, + hex::encode(vout.n.to_be_bytes()) + ), + hid: hid.clone(), + r#type: ScriptActivityType::Vout, + type_hex: ScriptActivityTypeHex::Vout, + txid: tx.txid, + block: BlockContext { + hash: block.hash, + height: block.height, + time: block.time, + median_time: block.mediantime, + }, + script: ScriptActivityScript { + r#type: vout.script_pub_key.r#type.clone(), + hex: vout.script_pub_key.hex.clone(), + }, + vin: None, + vout: Some(ScriptActivityVout { + txid: tx.txid, + n: vout.n, + }), + value: format!("{:.8}", vout.value), + token_id: vout.token_id, + }; + let id = ( + hid, + block.height, + ScriptActivityTypeHex::Vout, + tx.txid, + vout.n, + ); + services.script_activity.by_id.put(&id, &script_activity)? + } + } + + Ok(()) +} + +fn index_script_aggregation(services: &Arc, block: &Block) -> Result<()> { + let mut record: HashMap = HashMap::new(); + + fn find_script_aggregation( + record: &mut HashMap, + block: &Block, + hex: Vec, + script_type: String, + ) -> ScriptAggregation { + let hid = as_sha256(hex.clone()); + let aggregation = record.get(&hid).cloned(); + + if let Some(aggregation) = aggregation { + aggregation + } else { + let aggregation = ScriptAggregation { + id: (hid.clone(), block.height), + hid: hid.clone(), + block: BlockContext { + hash: block.hash, + height: block.height, + median_time: block.mediantime, + time: block.time, + }, + script: ScriptAggregationScript { + r#type: script_type, + hex, + }, + statistic: ScriptAggregationStatistic { + tx_count: 0, + tx_in_count: 0, + tx_out_count: 0, + }, + amount: ScriptAggregationAmount { + tx_in: 0.0, + tx_out: 0.0, + unspent: 0.0, + }, + }; + record.insert(hid, aggregation.clone()); + aggregation + } + } + + for tx in block.tx.iter() { + if check_if_evm_tx(tx) { + continue; + } + + for vin in tx.vin.iter() { + let vin_standard = get_vin_standard(vin); + if vin_standard.is_none() { + continue; + } + let vin = vin_standard.unwrap(); + + let vout = find_tx_vout(services, block, &vin)?; + if vout.is_none() { + log::error!("attempting to sync: {:?} but type: TransactionVout with id:{}-{} cannot be found in the index", IndexAction::Index, vin.txid, vin.vout); + continue; + } + let vout = vout.unwrap(); + + // SPENT (REMOVE) + let mut aggregation = + find_script_aggregation(&mut record, block, vout.script.hex, vout.script.r#type); + aggregation.statistic.tx_out_count += 1; + aggregation.amount.tx_out += vout.value.parse::()?; + record.insert(aggregation.hid.clone(), aggregation); + } + + for vout in tx.vout.iter() { + if vout.script_pub_key.hex.starts_with(&[0x6a]) { + continue; + } + + // Unspent (ADD) + let mut aggregation = find_script_aggregation( + &mut record, + block, + vout.script_pub_key.hex.clone(), + vout.script_pub_key.r#type.clone(), + ); + aggregation.statistic.tx_in_count += 1; + aggregation.amount.tx_in += vout.value; + record.insert(aggregation.hid.clone(), aggregation); + } + } + + for (_, mut aggregation) in record.clone().into_iter() { + let repo = &services.script_aggregation; + let latest = repo + .by_id + .list( + Some((aggregation.hid.clone(), u32::MAX)), + SortOrder::Descending, + )? + .take(1) + .take_while(|item| match item { + Ok(((hid, _), _)) => &aggregation.hid == hid, + _ => true, + }) + .map(|item| { + let (_, v) = item?; + Ok(v) + }) + .collect::>>()?; + + if let Some(latest) = latest.first().cloned() { + aggregation.statistic.tx_in_count += latest.statistic.tx_in_count; + aggregation.statistic.tx_out_count += latest.statistic.tx_out_count; + + aggregation.amount.tx_in += latest.amount.tx_in; + aggregation.amount.tx_out += latest.amount.tx_out; + } + + aggregation.statistic.tx_count = + aggregation.statistic.tx_in_count + aggregation.statistic.tx_out_count; + aggregation.amount.unspent = aggregation.amount.tx_in - aggregation.amount.tx_out; + record.insert(aggregation.hid.clone(), aggregation.clone()); + + repo.by_id + .put(&(aggregation.hid.clone(), block.height), &aggregation)?; + } + Ok(()) +} + +fn index_script_unspent(services: &Arc, block: &Block) -> Result<()> { + for tx in block.tx.iter() { + if check_if_evm_tx(tx) { + continue; + } + + for vin in tx.vin.iter() { + let vin_standard = get_vin_standard(vin); + if vin_standard.is_none() { + continue; + } + let vin = vin_standard.unwrap(); + let key = (block.height, vin.txid, vin.vout); + let id = services.script_unspent.by_key.get(&key)?; + if let Some(id) = id { + services.script_unspent.by_id.delete(&id)?; + services.script_unspent.by_key.delete(&key)? + } + } + + for vout in tx.vout.iter() { + let hid = as_sha256(vout.script_pub_key.hex.clone()); + let script_unspent = ScriptUnspent { + id: format!("{}{}", tx.txid, hex::encode(vout.n.to_be_bytes())), + hid: hid.clone(), + sort: format!( + "{}{}{}", + hex::encode(block.height.to_be_bytes()), + tx.txid, + hex::encode(vout.n.to_be_bytes()) + ), + block: BlockContext { + hash: block.hash, + height: block.height, + median_time: block.mediantime, + time: block.time, + }, + script: ScriptUnspentScript { + r#type: vout.script_pub_key.r#type.clone(), + hex: vout.script_pub_key.hex.clone(), + }, + vout: ScriptUnspentVout { + txid: tx.txid, + n: vout.n, + value: vout.value, + token_id: vout.token_id, + }, + }; + + let id = ( + hid.clone(), + hex::encode(block.height.to_be_bytes()), + tx.txid, + hex::encode(vout.n.to_be_bytes()), + ); + let key = (block.height, tx.txid, vout.n); + services.script_unspent.by_key.put(&key, &id)?; + services.script_unspent.by_id.put(&id, &script_unspent)? + } + } + + Ok(()) +} + pub fn index_block(services: &Arc, block: Block) -> Result<()> { debug!("[index_block] Indexing block..."); let start = Instant::now(); @@ -129,9 +477,16 @@ pub fn index_block(services: &Arc, block: Block) -> Resul median_time: block.mediantime, }; + // dftx index_block_start(services, &block)?; - for (tx_idx, tx) in block.tx.into_iter().enumerate() { + index_script_activity(services, &block)?; + + index_script_aggregation(services, &block)?; + + index_script_unspent(services, &block)?; + + for (tx_idx, tx) in block.tx.clone().into_iter().enumerate() { if is_skipped_tx(&tx.txid) { continue; } @@ -143,6 +498,8 @@ pub fn index_block(services: &Arc, block: Block) -> Resul tx_idx, }; + index_transaction(services, &ctx)?; + let bytes = &ctx.tx.vout[0].script_pub_key.hex; if bytes.len() <= 6 || bytes[0] != 0x6a || bytes[1] > 0x4e { continue; @@ -180,8 +537,6 @@ pub fn index_block(services: &Arc, block: Block) -> Resul log_elapsed(start, "Indexed dftx"); } } - - index_transaction(services, ctx)?; } log_elapsed(start, "Indexed block"); diff --git a/lib/ain-ocean/src/indexer/transaction.rs b/lib/ain-ocean/src/indexer/transaction.rs index 961603ea9df..42cb4f19c86 100644 --- a/lib/ain-ocean/src/indexer/transaction.rs +++ b/lib/ain-ocean/src/indexer/transaction.rs @@ -1,14 +1,12 @@ use std::sync::Arc; -use bitcoin::{hashes::Hash, Txid}; -use defichain_rpc::json::blockchain::{Transaction, Vin}; use log::debug; use rust_decimal::{ prelude::{FromPrimitive, Zero}, Decimal, }; -use super::Context; +use super::{helper::check_if_evm_tx, Context}; use crate::{ error::Error, indexer::Result, @@ -19,7 +17,7 @@ use crate::{ Services, }; -pub fn index_transaction(services: &Arc, ctx: Context) -> Result<()> { +pub fn index_transaction(services: &Arc, ctx: &Context) -> Result<()> { debug!("[index_transaction] Indexing..."); let idx = ctx.tx_idx; let is_evm = check_if_evm_tx(&ctx.tx); @@ -31,12 +29,13 @@ pub fn index_transaction(services: &Arc, ctx: Context) -> Result<()> { let mut total_vout_value = Decimal::zero(); let mut vouts = Vec::with_capacity(vout_count); // Index transaction vout - for (vout_idx, vout) in ctx.tx.vout.into_iter().enumerate() { + for vout in ctx.tx.vout.clone().into_iter() { let tx_vout = TransactionVout { + id: format!("{}{:x}", txid, vout.n), txid, - n: vout_idx, - value: vout.value, - token_id: 0, + n: vout.n, + value: vout.value.to_string(), + token_id: Some(0), script: TransactionVoutScript { hex: vout.script_pub_key.hex, r#type: vout.script_pub_key.r#type, @@ -45,14 +44,14 @@ pub fn index_transaction(services: &Arc, ctx: Context) -> Result<()> { services .transaction .vout_by_id - .put(&(txid, vout_idx), &tx_vout)?; + .put(&(txid, vout.n), &tx_vout)?; total_vout_value += Decimal::from_f64(vout.value).ok_or(Error::DecimalConversionError)?; vouts.push(tx_vout); } // Indexing transaction vin - for vin in ctx.tx.vin.into_iter() { + for vin in ctx.tx.vin.clone().into_iter() { if is_evm { continue; } @@ -67,7 +66,7 @@ pub fn index_transaction(services: &Arc, ctx: Context) -> Result<()> { id: txid, txid, order, - hash: ctx.tx.hash, + hash: ctx.tx.hash.clone(), block: ctx.block.clone(), version: ctx.tx.version, size: ctx.tx.size, @@ -87,17 +86,3 @@ pub fn index_transaction(services: &Arc, ctx: Context) -> Result<()> { Ok(()) } - -fn check_if_evm_tx(txn: &Transaction) -> bool { - txn.vin.len() == 2 - && txn.vin.iter().all(|vin| match vin { - Vin::Coinbase(_) => true, - Vin::Standard(tx) => tx.txid == Txid::all_zeros(), - }) - && txn.vout.len() == 1 - && txn.vout[0] - .script_pub_key - .asm - .starts_with("OP_RETURN 4466547839") - && txn.vout[0].value == 0f64 -} diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 21e76713e18..4667b4b633f 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -1,4 +1,5 @@ pub mod error; +pub mod hex_encoder; mod indexer; pub mod network; @@ -22,8 +23,10 @@ use repository::{ OracleRepository, OracleTokenCurrencyKeyRepository, OracleTokenCurrencyRepository, PoolPairByHeightRepository, PoolPairRepository, PoolSwapAggregatedKeyRepository, PoolSwapAggregatedRepository, PoolSwapRepository, PriceTickerKeyRepository, - PriceTickerRepository, RawBlockRepository, TransactionByBlockHashRepository, - TransactionRepository, TransactionVinRepository, TransactionVoutRepository, TxResultRepository, + PriceTickerRepository, RawBlockRepository, ScriptActivityRepository, + ScriptAggregationRepository, ScriptUnspentKeyRepository, ScriptUnspentRepository, + TransactionByBlockHashRepository, TransactionRepository, TransactionVinRepository, + TransactionVoutRepository, TxResultRepository, }; use serde::Serialize; pub mod api; @@ -118,6 +121,19 @@ pub struct PriceTickerService { by_key: PriceTickerKeyRepository, } +pub struct ScriptActivityService { + by_id: ScriptActivityRepository, +} + +pub struct ScriptAggregationService { + by_id: ScriptAggregationRepository, +} + +pub struct ScriptUnspentService { + by_id: ScriptUnspentRepository, + by_key: ScriptUnspentKeyRepository, +} + #[derive(Clone, Debug, Serialize, Eq, PartialEq, Hash)] #[serde(rename_all = "camelCase")] pub struct TokenIdentifier { @@ -144,6 +160,9 @@ pub struct Services { pub oracle_token_currency: OracleTokenCurrencyService, pub oracle_history: OracleHistoryService, pub price_ticker: PriceTickerService, + pub script_activity: ScriptActivityService, + pub script_aggregation: ScriptAggregationService, + pub script_unspent: ScriptUnspentService, pub token_graph: Arc>>, } @@ -213,6 +232,16 @@ impl Services { by_id: PriceTickerRepository::new_id(Arc::clone(&store)), by_key: PriceTickerKeyRepository::new_key(Arc::clone(&store)), }, + script_activity: ScriptActivityService { + by_id: ScriptActivityRepository::new(Arc::clone(&store)), + }, + script_aggregation: ScriptAggregationService { + by_id: ScriptAggregationRepository::new(Arc::clone(&store)), + }, + script_unspent: ScriptUnspentService { + by_id: ScriptUnspentRepository::new(Arc::clone(&store)), + by_key: ScriptUnspentKeyRepository::new(Arc::clone(&store)), + }, token_graph: Arc::new(Mutex::new(UnGraphMap::new())), } } diff --git a/lib/ain-ocean/src/model/mod.rs b/lib/ain-ocean/src/model/mod.rs index bd11c3ce941..234c4b1a1b2 100644 --- a/lib/ain-ocean/src/model/mod.rs +++ b/lib/ain-ocean/src/model/mod.rs @@ -38,9 +38,9 @@ pub use poolswap_aggregated::*; pub use price_ticker::*; pub use raw_tx::*; // pub use raw_block::*; -// pub use script_activity::*; -// pub use script_aggregation::*; -// pub use script_unspent::*; +pub use script_activity::*; +pub use script_aggregation::*; +pub use script_unspent::*; pub use transaction::*; pub use transaction_vin::*; pub use transaction_vout::*; diff --git a/lib/ain-ocean/src/model/script_activity.rs b/lib/ain-ocean/src/model/script_activity.rs index 03aa22afb82..e8dbb75ebdb 100644 --- a/lib/ain-ocean/src/model/script_activity.rs +++ b/lib/ain-ocean/src/model/script_activity.rs @@ -1,48 +1,69 @@ +use bitcoin::Txid; use serde::{Deserialize, Serialize}; +use std::fmt; use super::BlockContext; -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)] pub enum ScriptActivityType { Vin, Vout, } +impl fmt::Display for ScriptActivityType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ScriptActivityType::Vin => write!(f, "vin"), + ScriptActivityType::Vout => write!(f, "vout"), + } + } +} + #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum ScriptActivityTypeHex { Vin, Vout, } -#[derive(Debug, Serialize, Deserialize)] +impl fmt::Display for ScriptActivityTypeHex { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ScriptActivityTypeHex::Vin => write!(f, "00"), + ScriptActivityTypeHex::Vout => write!(f, "01"), + } + } +} + +pub type ScriptActivityId = (String, u32, ScriptActivityTypeHex, Txid, usize); // (hid, block.height, type_hex, txid, index) +#[derive(Debug, Serialize, Deserialize)] pub struct ScriptActivity { - pub id: String, - pub hid: String, + pub id: String, // unique id of this output: block height, type, txid(vin/vout), n(vin/vout) + pub hid: String, // hashed id, for length compatibility reasons this is the hashed id of script pub r#type: ScriptActivityType, pub type_hex: ScriptActivityTypeHex, - pub txid: String, + pub txid: Txid, pub block: BlockContext, pub script: ScriptActivityScript, - pub vin: ScriptActivityVin, - pub vout: ScriptActivityVout, + pub vin: Option, + pub vout: Option, pub value: String, - pub token_id: i32, + pub token_id: Option, } #[derive(Debug, Serialize, Deserialize)] pub struct ScriptActivityScript { pub r#type: String, - pub hex: String, + pub hex: Vec, } #[derive(Debug, Serialize, Deserialize)] pub struct ScriptActivityVin { - pub txid: String, - pub n: i32, + pub txid: Txid, + pub n: usize, } #[derive(Debug, Serialize, Deserialize)] pub struct ScriptActivityVout { - pub txid: String, - pub n: i32, + pub txid: Txid, + pub n: usize, } diff --git a/lib/ain-ocean/src/model/script_aggregation.rs b/lib/ain-ocean/src/model/script_aggregation.rs index 3d8bd49deed..73cf26cfc7d 100644 --- a/lib/ain-ocean/src/model/script_aggregation.rs +++ b/lib/ain-ocean/src/model/script_aggregation.rs @@ -1,9 +1,12 @@ use serde::{Deserialize, Serialize}; use super::BlockContext; -#[derive(Debug, Serialize, Deserialize)] + +pub type ScriptAggregationId = (String, u32); // (hid, block.height) + +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct ScriptAggregation { - pub id: String, + pub id: ScriptAggregationId, pub hid: String, pub block: BlockContext, pub script: ScriptAggregationScript, @@ -11,22 +14,22 @@ pub struct ScriptAggregation { pub amount: ScriptAggregationAmount, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct ScriptAggregationScript { pub r#type: String, - pub hex: String, + pub hex: Vec, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct ScriptAggregationStatistic { pub tx_count: i32, pub tx_in_count: i32, pub tx_out_count: i32, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct ScriptAggregationAmount { - pub tx_in: String, - pub tx_out: String, - pub unspent: String, + pub tx_in: f64, + pub tx_out: f64, + pub unspent: f64, } diff --git a/lib/ain-ocean/src/model/script_unspent.rs b/lib/ain-ocean/src/model/script_unspent.rs index d411f00c3c2..a5d7c934f2d 100644 --- a/lib/ain-ocean/src/model/script_unspent.rs +++ b/lib/ain-ocean/src/model/script_unspent.rs @@ -1,6 +1,10 @@ +use super::BlockContext; +use bitcoin::Txid; use serde::{Deserialize, Serialize}; -use super::BlockContext; +pub type ScriptUnspentId = (String, String, Txid, String); // hid + hex::encode(block.height) + txid + hex::encode(vout_index) +pub type ScriptUnspentKey = (u32, Txid, usize); // block.height + txid + vout_index + #[derive(Debug, Serialize, Deserialize)] pub struct ScriptUnspent { pub id: String, @@ -14,13 +18,13 @@ pub struct ScriptUnspent { #[derive(Debug, Serialize, Deserialize)] pub struct ScriptUnspentScript { pub r#type: String, - pub hex: String, + pub hex: Vec, } #[derive(Debug, Serialize, Deserialize)] pub struct ScriptUnspentVout { - pub txid: String, - pub n: i32, - pub value: String, - pub token_id: i32, + pub txid: Txid, + pub n: usize, + pub value: f64, + pub token_id: Option, } diff --git a/lib/ain-ocean/src/model/transaction_vin.rs b/lib/ain-ocean/src/model/transaction_vin.rs index 08413762e88..5a413019815 100644 --- a/lib/ain-ocean/src/model/transaction_vin.rs +++ b/lib/ain-ocean/src/model/transaction_vin.rs @@ -30,7 +30,7 @@ impl TransactionVin { Vin::Standard(v) => { let vout = vouts.get(v.vout).map(|vout| TransactionVinVout { txid: vout.txid, - value: vout.value, + value: vout.value.clone(), n: vout.n, token_id: vout.token_id, script: vout.script.hex.to_owned(), @@ -53,7 +53,7 @@ impl TransactionVin { pub struct TransactionVinVout { pub txid: Txid, pub n: usize, - pub value: f64, - pub token_id: u8, + pub value: String, + pub token_id: Option, pub script: Vec, } diff --git a/lib/ain-ocean/src/model/transaction_vout.rs b/lib/ain-ocean/src/model/transaction_vout.rs index 8116abfc466..c58453abc42 100644 --- a/lib/ain-ocean/src/model/transaction_vout.rs +++ b/lib/ain-ocean/src/model/transaction_vout.rs @@ -5,10 +5,11 @@ pub type TransactionVoutKey = (Txid, usize); #[derive(Debug, Serialize, Deserialize)] pub struct TransactionVout { + pub id: String, pub txid: Txid, pub n: usize, - pub value: f64, - pub token_id: u8, + pub value: String, + pub token_id: Option, pub script: TransactionVoutScript, } diff --git a/lib/ain-ocean/src/repository/mod.rs b/lib/ain-ocean/src/repository/mod.rs index 68d29cf4afe..e4a80035ad9 100644 --- a/lib/ain-ocean/src/repository/mod.rs +++ b/lib/ain-ocean/src/repository/mod.rs @@ -39,9 +39,9 @@ pub use pool_swap_aggregated::*; pub use poolpair::*; pub use price_ticker::*; pub use raw_block::*; -// pub use script_activity::*; -// pub use script_aggregation::*; -// pub use script_unspent::*; +pub use script_activity::*; +pub use script_aggregation::*; +pub use script_unspent::*; pub use transaction::*; pub use transaction_vin::*; pub use transaction_vout::*; diff --git a/lib/ain-ocean/src/repository/script_activity.rs b/lib/ain-ocean/src/repository/script_activity.rs index 8b137891791..f0448499726 100644 --- a/lib/ain-ocean/src/repository/script_activity.rs +++ b/lib/ain-ocean/src/repository/script_activity.rs @@ -1 +1,18 @@ +use std::sync::Arc; +use ain_db::LedgerColumn; +use ain_macros::Repository; + +use super::RepositoryOps; +use crate::{ + model::{ScriptActivity, ScriptActivityId}, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "ScriptActivityId", V = "ScriptActivity")] +pub struct ScriptActivityRepository { + pub store: Arc, + col: LedgerColumn, +} diff --git a/lib/ain-ocean/src/repository/script_aggregation.rs b/lib/ain-ocean/src/repository/script_aggregation.rs index 8b137891791..feeaec54e3c 100644 --- a/lib/ain-ocean/src/repository/script_aggregation.rs +++ b/lib/ain-ocean/src/repository/script_aggregation.rs @@ -1 +1,18 @@ +use std::sync::Arc; +use ain_db::LedgerColumn; +use ain_macros::Repository; + +use super::RepositoryOps; +use crate::{ + model::{ScriptAggregation, ScriptAggregationId}, + storage::{columns, ocean_store::OceanStore}, + Result, +}; + +#[derive(Repository)] +#[repository(K = "ScriptAggregationId", V = "ScriptAggregation")] +pub struct ScriptAggregationRepository { + pub store: Arc, + col: LedgerColumn, +} diff --git a/lib/ain-ocean/src/repository/script_unspent.rs b/lib/ain-ocean/src/repository/script_unspent.rs index 8b137891791..29c9668f2ca 100644 --- a/lib/ain-ocean/src/repository/script_unspent.rs +++ b/lib/ain-ocean/src/repository/script_unspent.rs @@ -1 +1,38 @@ +use std::sync::Arc; +use ain_db::LedgerColumn; +use ain_macros::Repository; + +use super::{RepositoryOps, SecondaryIndex}; +use crate::{ + model::{ScriptUnspent, ScriptUnspentId, ScriptUnspentKey}, + storage::{columns, ocean_store::OceanStore}, + Error, Result, +}; + +#[derive(Repository)] +#[repository(K = "ScriptUnspentId", V = "ScriptUnspent")] +pub struct ScriptUnspentRepository { + pub store: Arc, + col: LedgerColumn, +} + +#[derive(Repository)] +#[repository(K = "ScriptUnspentKey", V = "ScriptUnspentId")] +pub struct ScriptUnspentKeyRepository { + pub store: Arc, + col: LedgerColumn, +} + +impl SecondaryIndex for ScriptUnspentKeyRepository { + type Value = ScriptUnspent; + + fn retrieve_primary_value(&self, el: Self::ListItem) -> Result { + let (_, id) = el?; + + let col = self.store.column::(); + let res = col.get(&id)?.ok_or(Error::SecondaryIndex)?; + + Ok(res) + } +} diff --git a/lib/ain-ocean/src/storage/columns/mod.rs b/lib/ain-ocean/src/storage/columns/mod.rs index 875c6d4cc87..82cfe929896 100644 --- a/lib/ain-ocean/src/storage/columns/mod.rs +++ b/lib/ain-ocean/src/storage/columns/mod.rs @@ -47,7 +47,7 @@ pub use transaction_vout::*; pub use tx_result::*; pub use vault_auction_history::*; -pub const COLUMN_NAMES: [&str; 36] = [ +pub const COLUMN_NAMES: [&str; 37] = [ block::Block::NAME, block::BlockByHeight::NAME, masternode_stats::MasternodeStats::NAME, @@ -77,6 +77,7 @@ pub const COLUMN_NAMES: [&str; 36] = [ script_activity::ScriptActivity::NAME, script_aggregation::ScriptAggregation::NAME, script_unspent::ScriptUnspent::NAME, + script_unspent::ScriptUnspentKey::NAME, transaction::Transaction::NAME, transaction::TransactionByBlockHash::NAME, transaction_vin::TransactionVin::NAME, diff --git a/lib/ain-ocean/src/storage/columns/script_activity.rs b/lib/ain-ocean/src/storage/columns/script_activity.rs index c47c692b5bd..f9b8b9f17a7 100644 --- a/lib/ain-ocean/src/storage/columns/script_activity.rs +++ b/lib/ain-ocean/src/storage/columns/script_activity.rs @@ -1,16 +1,17 @@ +use crate::model; use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] pub struct ScriptActivity; impl ColumnName for ScriptActivity { - const NAME: &'static str = "raw_block"; + const NAME: &'static str = "script_activity"; } impl Column for ScriptActivity { - type Index = String; + type Index = model::ScriptActivityId; } impl TypedColumn for ScriptActivity { - type Type = String; + type Type = model::ScriptActivity; } diff --git a/lib/ain-ocean/src/storage/columns/script_aggregation.rs b/lib/ain-ocean/src/storage/columns/script_aggregation.rs index 494911aa3fb..eecbba4135d 100644 --- a/lib/ain-ocean/src/storage/columns/script_aggregation.rs +++ b/lib/ain-ocean/src/storage/columns/script_aggregation.rs @@ -1,3 +1,4 @@ +use crate::model; use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] @@ -8,9 +9,9 @@ impl ColumnName for ScriptAggregation { } impl Column for ScriptAggregation { - type Index = String; + type Index = model::ScriptAggregationId; } impl TypedColumn for ScriptAggregation { - type Type = String; + type Type = model::ScriptAggregation; } diff --git a/lib/ain-ocean/src/storage/columns/script_unspent.rs b/lib/ain-ocean/src/storage/columns/script_unspent.rs index 2862184bfe0..52c77205126 100644 --- a/lib/ain-ocean/src/storage/columns/script_unspent.rs +++ b/lib/ain-ocean/src/storage/columns/script_unspent.rs @@ -1,3 +1,4 @@ +use crate::model; use ain_db::{Column, ColumnName, TypedColumn}; #[derive(Debug)] @@ -8,9 +9,24 @@ impl ColumnName for ScriptUnspent { } impl Column for ScriptUnspent { - type Index = String; + type Index = model::ScriptUnspentId; } impl TypedColumn for ScriptUnspent { - type Type = String; + type Type = model::ScriptUnspent; +} + +#[derive(Debug)] +pub struct ScriptUnspentKey; + +impl ColumnName for ScriptUnspentKey { + const NAME: &'static str = "script_unspent_key"; +} + +impl Column for ScriptUnspentKey { + type Index = model::ScriptUnspentKey; +} + +impl TypedColumn for ScriptUnspentKey { + type Type = model::ScriptUnspentId; } From 1fc3b4e0859153f596959e4171d2ba0701f86a4e Mon Sep 17 00:00:00 2001 From: canonbrother Date: Mon, 15 Jul 2024 18:59:22 +0800 Subject: [PATCH 113/185] Ocean: api address list tokens (#2960) * script activity indexer * refine + helper::check_if_evm_tx + error::NotFoundIndex * fmt * api * fmt * fix * fmt * Ocean: indexer script unspent + api.address.list_transactions_unspent (#2948) * script unspent indexer * list_tx_unspent api * fmt * Ocean: indexer script aggregation + api.address.get_balance & get_aggregation (#2949) * script aggregation indexer * fmt * address api: get_balance + get_aggregation * get_balance return string * decimal to string as deserialize not support in decimal * fix NotFoundIndex params * fix script agg indexer * ScriptAggregationResponse * 8 decimal * decimal -> f64 * map api resp & fix sorting * fix paginate * fmt * script activity uses find_tx_vout * fix tx getvouts sort asc * fix indexer_script_activity, index_tx order correction, refine find_tx_vout, rm unuse * resp mapping * fmt * rust-defichain-rpc main * script activity indexer * address list tokens * rm dup import * fmt --- lib/ain-ocean/src/api/address.rs | 71 ++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/lib/ain-ocean/src/api/address.rs b/lib/ain-ocean/src/api/address.rs index 8d2dbd6b400..d6a161d32eb 100644 --- a/lib/ain-ocean/src/api/address.rs +++ b/lib/ain-ocean/src/api/address.rs @@ -1,7 +1,8 @@ -use std::{str::FromStr, sync::Arc}; +use std::{collections::BTreeMap, str::FromStr, sync::Arc}; use super::{ - common::address_to_hid, + cache::get_token_cached, + common::{address_to_hid, parse_display_symbol}, path::Path, query::{PaginationQuery, Query}, response::{ApiPagedResponse, Response}, @@ -19,7 +20,9 @@ use crate::{ use ain_macros::ocean_endpoint; use axum::{routing::get, Extension, Router}; use bitcoin::{hashes::Hash, hex::DisplayHex, Txid}; +use defichain_rpc::RpcApi; use serde::{Deserialize, Serialize}; +use serde_json::json; use serde_with::skip_serializing_none; #[derive(Deserialize)] @@ -381,13 +384,75 @@ async fn list_transaction_unspent( })) } +// Tokens owned by an address +#[derive(Serialize, Debug)] +#[serde(rename_all = "camelCase")] +struct AddressToken { + id: String, + amount: String, + symbol: String, + display_symbol: String, + symbol_key: String, + name: String, + #[serde(rename = "isDAT")] + is_dat: bool, + #[serde(rename = "isLPS")] + is_lps: bool, + is_loan_token: bool, +} + +#[ocean_endpoint] +async fn list_tokens( + Path(Address { address }): Path
, + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let account: BTreeMap = ctx.client.call( + "getaccount", + &[ + address.into(), + json!({ + "limit": query.size, + "start": query.next.as_ref().and_then(|n| n.parse::().ok()).unwrap_or_default(), + "including_start": query.next.is_none() + }), + true.into(), + ], + ).await?; + + let mut vec = Vec::new(); + for (k, v) in account { + let token = get_token_cached(&ctx, &k).await?; + if token.is_none() { + continue; + } + let (id, info) = token.unwrap(); + let address_token = AddressToken { + id, + amount: format!("{:.8}", v), + display_symbol: parse_display_symbol(&info), + symbol: info.symbol, + symbol_key: info.symbol_key, + name: info.name, + is_dat: info.is_dat, + is_lps: info.is_lps, + is_loan_token: info.is_loan_token, + }; + vec.push(address_token) + } + + Ok(ApiPagedResponse::of(vec, query.size, |item| { + item.id.clone() + })) +} + pub fn router(ctx: Arc) -> Router { Router::new() // .route("/history/:height/:txno", get(get_account_history)) // .route("/history", get(list_account_history)) .route("/:address/balance", get(get_balance)) .route("/:address/aggregation", get(get_aggregation)) - // .route("/tokens", get(list_token)) + .route("/:address/tokens", get(list_tokens)) // .route("/vaults", get(list_vault)) .route("/:address/transactions", get(list_transactions)) .route( From 051b569fdbfa95af3284e9e2ceb5f11caa2bda60 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Mon, 15 Jul 2024 23:45:12 +0800 Subject: [PATCH 114/185] Ocean: api address get account history (#2967) * script activity indexer * refine + helper::check_if_evm_tx + error::NotFoundIndex * fmt * api * fmt * fix * fmt * Ocean: indexer script unspent + api.address.list_transactions_unspent (#2948) * script unspent indexer * list_tx_unspent api * fmt * Ocean: indexer script aggregation + api.address.get_balance & get_aggregation (#2949) * script aggregation indexer * fmt * address api: get_balance + get_aggregation * get_balance return string * decimal to string as deserialize not support in decimal * fix NotFoundIndex params * fix script agg indexer * ScriptAggregationResponse * 8 decimal * decimal -> f64 * map api resp & fix sorting * fix paginate * fmt * script activity uses find_tx_vout * fix tx getvouts sort asc * fix indexer_script_activity, index_tx order correction, refine find_tx_vout, rm unuse * resp mapping * fmt * rust-defichain-rpc main * script activity indexer * address list tokens * rm dup import * fmt * get_acc_history * rm log * use anyhow::Context --------- Co-authored-by: Jouzo <15011228+Jouzo@users.noreply.github.com> --- lib/ain-ocean/src/api/address.rs | 83 ++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 21 deletions(-) diff --git a/lib/ain-ocean/src/api/address.rs b/lib/ain-ocean/src/api/address.rs index d6a161d32eb..991ee0181c9 100644 --- a/lib/ain-ocean/src/api/address.rs +++ b/lib/ain-ocean/src/api/address.rs @@ -18,9 +18,10 @@ use crate::{ Error, Result, }; use ain_macros::ocean_endpoint; +use anyhow::Context; use axum::{routing::get, Extension, Router}; -use bitcoin::{hashes::Hash, hex::DisplayHex, Txid}; -use defichain_rpc::RpcApi; +use bitcoin::{hashes::Hash, hex::DisplayHex, BlockHash, Txid}; +use defichain_rpc::{json::account::AccountHistory, AccountRPC, RpcApi}; use serde::{Deserialize, Serialize}; use serde_json::json; use serde_with::skip_serializing_none; @@ -30,25 +31,65 @@ struct Address { address: String, } -// #[derive(Deserialize)] -// struct History { -// address: String, -// height: i64, -// txno: i64, -// } +#[derive(Deserialize)] +struct History { + address: String, + height: u32, + txno: u32, +} -// async fn get_account_history( -// Path(History { -// address, -// height, -// txno, -// }): Path, -// ) -> String { -// format!( -// "Account history for address {}, height {}, txno {}", -// address, height, txno -// ) -// } +#[derive(Debug, Serialize)] +struct AddressHistory { + owner: String, + txid: Option, + txn: Option, + r#type: String, + amounts: Vec, + block: AddressHistoryBlock, +} + +impl From for AddressHistory { + fn from(history: AccountHistory) -> Self { + Self { + owner: history.owner, + txid: history.txid, + txn: history.txn, + r#type: history.r#type, + amounts: history.amounts, + block: AddressHistoryBlock { + height: history.block_height, + hash: history.block_hash, + time: history.block_time, + }, + } + } +} + +#[skip_serializing_none] +#[derive(Debug, Serialize)] +struct AddressHistoryBlock { + height: u64, + hash: Option, + time: Option, +} + +#[ocean_endpoint] +async fn get_account_history( + Path(History { + address, + height, + txno, + }): Path, + Extension(ctx): Extension>, +) -> Result> { + let res = ctx + .client + .get_account_history(&address, height, txno) + .await + .context("Record not found")?; + + Ok(Response::new(res.into())) +} // async fn list_account_history(Path(Address { address }): Path
) -> String { // format!("List account history for address {}", address) @@ -448,7 +489,7 @@ async fn list_tokens( pub fn router(ctx: Arc) -> Router { Router::new() - // .route("/history/:height/:txno", get(get_account_history)) + .route("/:address/history/:height/:txno", get(get_account_history)) // .route("/history", get(list_account_history)) .route("/:address/balance", get(get_balance)) .route("/:address/aggregation", get(get_aggregation)) From 4186f2b448b4bdce1fe94c71ad094fb638fe6b5a Mon Sep 17 00:00:00 2001 From: canonbrother Date: Tue, 16 Jul 2024 16:15:22 +0800 Subject: [PATCH 115/185] Ocean: list auctions api (#2942) * wip * fix froms * refine SetLoanToken indexer * br * desc * fmt * vault state * update cargo.lock 9a338f8d0ed5e837a67eb8c1aa04a9efc0c5d2ba --- lib/Cargo.lock | 4 +- lib/ain-ocean/src/api/cache.rs | 13 +- lib/ain-ocean/src/api/loan.rs | 221 +++++++++++++++- lib/ain-ocean/src/api/pool_pair/service.rs | 2 +- lib/ain-ocean/src/indexer/loan_token.rs | 248 ++++++++++-------- lib/ain-ocean/src/indexer/mod.rs | 2 +- .../src/model/oracle_price_active.rs | 6 +- .../src/model/vault_auction_batch_history.rs | 4 +- .../src/repository/oracle_price_active.rs | 17 +- 9 files changed, 381 insertions(+), 136 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 03314745039..7f1c521147d 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -1531,7 +1531,7 @@ dependencies = [ [[package]] name = "defichain-rpc" version = "0.18.0" -source = "git+https://github.com/defich/rust-defichain-rpc.git#550743d7b18bbd9bc0ddc6a9ecbb16d7d72151f7" +source = "git+https://github.com/defich/rust-defichain-rpc.git#9a338f8d0ed5e837a67eb8c1aa04a9efc0c5d2ba" dependencies = [ "async-trait", "defichain-rpc-json", @@ -1544,7 +1544,7 @@ dependencies = [ [[package]] name = "defichain-rpc-json" version = "0.18.0" -source = "git+https://github.com/defich/rust-defichain-rpc.git#550743d7b18bbd9bc0ddc6a9ecbb16d7d72151f7" +source = "git+https://github.com/defich/rust-defichain-rpc.git#9a338f8d0ed5e837a67eb8c1aa04a9efc0c5d2ba" dependencies = [ "bitcoin", "serde", diff --git a/lib/ain-ocean/src/api/cache.rs b/lib/ain-ocean/src/api/cache.rs index eb17e1115d0..428033b9630 100644 --- a/lib/ain-ocean/src/api/cache.rs +++ b/lib/ain-ocean/src/api/cache.rs @@ -3,11 +3,12 @@ use std::{collections::HashMap, sync::Arc}; use cached::proc_macro::cached; use defichain_rpc::{ json::{ + loan::LoanSchemeResult, poolpair::{PoolPairInfo, PoolPairPagination, PoolPairsResult}, token::{TokenInfo, TokenPagination, TokenResult}, }, jsonrpc_async::error::{Error as JsonRpcError, RpcError}, - Error, MasternodeRPC, PoolPairRPC, TokenRPC, + Error, LoanRPC, MasternodeRPC, PoolPairRPC, TokenRPC, }; use super::AppContext; @@ -129,3 +130,13 @@ pub async fn get_gov_cached( let gov = ctx.client.get_gov(id).await?; Ok(gov) } + +#[cached( + result = true, + key = "String", + convert = r#"{ format!("getloanscheme{id}") }"# +)] +pub async fn get_loan_scheme_cached(ctx: &Arc, id: String) -> Result { + let loan_scheme = ctx.client.get_loan_scheme(id).await?; + Ok(loan_scheme) +} diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index 5980f8315b1..6725f08118b 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -1,23 +1,25 @@ -use std::sync::Arc; +use std::{str::FromStr, sync::Arc}; use ain_macros::ocean_endpoint; use anyhow::format_err; use axum::{routing::get, Extension, Router}; -use bitcoin::Txid; +use bitcoin::{hashes::Hash, Txid}; use defichain_rpc::{ defichain_rpc_json::{ loan::{CollateralTokenDetail, LoanSchemeResult}, token::TokenInfo, + vault::VaultLiquidationBatch, }, - LoanRPC, + json::vault::{AuctionPagination, AuctionPaginationStart, VaultState}, + LoanRPC, VaultRPC, }; use futures::future::try_join_all; use log::debug; use serde::Serialize; use super::{ - cache::get_token_cached, - common::Paginate, + cache::{get_loan_scheme_cached, get_token_cached}, + common::{from_script, parse_display_symbol, Paginate}, path::Path, query::{PaginationQuery, Query}, response::{ApiPagedResponse, Response}, @@ -26,8 +28,8 @@ use super::{ }; use crate::{ error::{ApiError, Error}, - model::VaultAuctionBatchHistory, - repository::RepositoryOps, + model::{OraclePriceActive, VaultAuctionBatchHistory}, + repository::{RepositoryOps, SecondaryIndex}, storage::SortOrder, Result, }; @@ -292,9 +294,206 @@ async fn list_vault_auction_history( })) } -// async fn list_auction() -> String { -// "List of auctions".to_string() -// } +#[derive(Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct VaultLiquidationResponse { + pub vault_id: String, + pub loan_scheme: LoanSchemeResult, + pub owner_address: String, + #[serde(default = "VaultState::in_liquidation")] + pub state: VaultState, + pub liquidation_height: u64, + pub liquidation_penalty: f64, + pub batch_count: usize, + pub batches: Vec, +} + +#[derive(Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct HighestBidResponse { + pub owner: String, + pub amount: Option, +} + +#[derive(Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct VaultLiquidationBatchResponse { + index: u32, + collaterals: Vec, + loan: Option, + highest_bid: Option, + froms: Vec, +} + +#[derive(Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct VaultTokenAmountResponse { + pub id: String, + pub amount: String, + pub symbol: String, + pub display_symbol: String, + pub symbol_key: String, + pub name: String, + pub active_price: Option, +} + +#[ocean_endpoint] +async fn list_auction( + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let start = query.next.as_ref().map(|next| { + let vault_id = &next[0..64]; + let height = &next[64..]; + AuctionPaginationStart { + vault_id: vault_id.to_string(), + height: height.parse::().unwrap_or_default(), + } + }); + + let pagination = AuctionPagination { + start, + including_start: None, + limit: if query.size > 30 { + Some(30) + } else { + Some(query.size) + }, + }; + + async fn map_liquidation_batches( + ctx: &Arc, + vault_id: &str, + batches: Vec, + ) -> Result> { + let repo = &ctx.services.auction; + let mut vec = Vec::new(); + for batch in batches { + let highest_bid = if let Some(bid) = batch.highest_bid { + let amount = map_token_amounts(ctx, vec![bid.amount]).await?; + let res = HighestBidResponse { + owner: bid.owner, + amount: amount.first().cloned(), + }; + Some(res) + } else { + None + }; + let id = ( + Txid::from_str(vault_id)?, + batch.index, + Txid::from_byte_array([0xffu8; 32]), + ); + let bids = repo + .by_id + .list(Some(id), SortOrder::Descending)? + .take_while(|item| match item { + Ok(((vid, bindex, _), _)) => { + vid.to_string() == vault_id && bindex == &batch.index + } + _ => true, + }) + .collect::>(); + let froms = bids + .into_iter() + .map(|bid| { + let (_, v) = bid?; + let from_addr = from_script(v.from, ctx.network.into())?; + Ok::(from_addr) + }) + .collect::>>()?; + vec.push(VaultLiquidationBatchResponse { + index: batch.index, + collaterals: map_token_amounts(ctx, batch.collaterals).await?, + loan: map_token_amounts(ctx, vec![batch.loan]) + .await? + .first() + .cloned(), + froms, + highest_bid, + }) + } + Ok(vec) + } + + async fn map_token_amounts( + ctx: &Arc, + amounts: Vec, + ) -> Result> { + if amounts.is_empty() { + return Ok(Vec::new()); + } + let amount_token_symbols = amounts + .into_iter() + .map(|amount| { + let amount = amount.to_owned(); + let parts = amount.split('@').collect::>(); + let [amount, token_symbol] = <[&str; 2]>::try_from(parts) + .map_err(|_| format_err!("Invalid amount structure"))?; + Ok([amount.to_string(), token_symbol.to_string()]) + }) + .collect::>>()?; + + let mut vault_token_amounts = Vec::new(); + for [amount, token_symbol] in amount_token_symbols { + let token = get_token_cached(ctx, &token_symbol).await?; + if token.is_none() { + log::error!("Token {token_symbol} not found"); + continue; + } + let repo = &ctx.services.oracle_price_active; + let (id, token_info) = token.unwrap(); + let keys = repo + .by_key + .list(None, SortOrder::Descending)? + .collect::>(); + log::debug!("list_auctions keys: {:?}, token_id: {:?}", keys, id); + let active_price = repo + .by_key + .list(None, SortOrder::Descending)? + .take(1) + .take_while(|item| match item { + Ok((k, _)) => k.0 == id, + _ => true, + }) + .map(|el| repo.by_key.retrieve_primary_value(el)) + .collect::>>()?; + + vault_token_amounts.push(VaultTokenAmountResponse { + id, + display_symbol: parse_display_symbol(&token_info), + amount: amount.to_string(), + symbol: token_info.symbol, + symbol_key: token_info.symbol_key, + name: token_info.name, + active_price: active_price.first().cloned(), + }) + } + + Ok(vault_token_amounts) + } + + let mut vaults = Vec::new(); + let liquidation_vaults = ctx.client.list_auctions(Some(pagination)).await?; + for vault in liquidation_vaults { + let loan_scheme = get_loan_scheme_cached(&ctx, vault.loan_scheme_id).await?; + let res = VaultLiquidationResponse { + batches: map_liquidation_batches(&ctx, &vault.vault_id, vault.batches).await?, + vault_id: vault.vault_id, + loan_scheme, + owner_address: vault.owner_address, + state: vault.state, + liquidation_height: vault.liquidation_height, + liquidation_penalty: vault.liquidation_penalty, + batch_count: vault.batch_count, + }; + vaults.push(res) + } + + Ok(ApiPagedResponse::of(vaults, query.size, |auction| { + format!("{}{}", auction.vault_id.clone(), auction.liquidation_height) + })) +} pub fn router(ctx: Arc) -> Router { Router::new() @@ -310,6 +509,6 @@ pub fn router(ctx: Arc) -> Router { "/vaults/:id/auctions/:height/batches/:batchIndex/history", get(list_vault_auction_history), ) - // .route("/auctions", get(list_auction)) + .route("/auctions", get(list_auction)) .layer(Extension(ctx)) } diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index d6d317c879a..78142d93baf 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -198,7 +198,7 @@ fn calculate_rewards(accounts: &[String], dfi_price_usdt: Decimal) -> Result, ctx: &Context) -> Result<()> { let ticker_id = (self.currency_pair.token, self.currency_pair.currency); - let aggregated_price = services + let aggregated_prices = services .oracle_price_aggregated .by_key .list(Some(ticker_id.clone()), SortOrder::Descending)? .map(|item| { let (_, id) = item?; - let b = services + let aggregated = services .oracle_price_aggregated .by_id .get(&id)? .ok_or("Missing oracle previous history index")?; - Ok(b) + Ok(aggregated) }) - .collect::, Box>>()?; - - if !aggregated_price.is_empty() { - let previous_price = services - .oracle_price_active - .by_key - .list(Some(ticker_id.clone()), SortOrder::Descending)? - .map(|item| { - let (_, id) = item?; - let b = services - .oracle_price_active - .by_id - .get(&id)? - .ok_or("Missing oracle previous history index")?; - - Ok(b) - }) - .collect::, Box>>()?; - let price_active_id = ( - ticker_id.0.clone(), - ticker_id.1.clone(), - aggregated_price[0].block.height, - ); - - let oracle_price_key = (ticker_id.0, ticker_id.1); - let next_price = match aggregated_validate(aggregated_price[0].clone(), ctx) { - true => OraclePriceActiveNext { - amount: aggregated_price[0].aggregated.amount.clone(), - weightage: aggregated_price[0].aggregated.weightage, - oracles: OraclePriceActiveNextOracles { - active: aggregated_price[0].aggregated.oracles.active, - total: aggregated_price[0].aggregated.oracles.total, - }, - }, - false => Default::default(), - }; + .collect::>>()?; - let active_price: OraclePriceActiveActive; + log::debug!( + "set_loan_token indexing aggregated_price: {:?}", + aggregated_prices + ); + + if aggregated_prices.is_empty() { + return Ok(()); + } + let aggregated_price = aggregated_prices.first().unwrap(); - if previous_price.is_empty() { - active_price = OraclePriceActiveActive { - amount: Default::default(), - weightage: Default::default(), + let previous_prices = services + .oracle_price_active + .by_key + .list(Some(ticker_id.clone()), SortOrder::Descending)? + .take(1) + .map(|item| { + let (_, id) = item?; + let price = services + .oracle_price_active + .by_id + .get(&id)? + .ok_or("Missing oracle previous history index")?; + Ok(price) + }) + .collect::>>()?; + + let active_price = if previous_prices.first().is_some() { + if previous_prices[0].next.is_some() { + let price = previous_prices[0].next.clone().unwrap(); + Some(OraclePriceActiveActive { + amount: price.amount, + weightage: price.weightage, oracles: OraclePriceActiveActiveOracles { - active: Default::default(), - total: Default::default(), + active: price.oracles.active, + total: price.oracles.total, }, - }; - } else if let Some(next) = previous_price.first().map(|price| &price.next) { - active_price = OraclePriceActiveActive { - amount: next.amount.clone(), - weightage: next.weightage, + }) + } else if previous_prices[0].active.is_some() { + let price = previous_prices[0].active.clone().unwrap(); + Some(OraclePriceActiveActive { + amount: price.amount, + weightage: price.weightage, oracles: OraclePriceActiveActiveOracles { - active: next.oracles.active, - total: next.oracles.total, + active: price.oracles.active, + total: price.oracles.total, }, - }; + }) } else { - let oracles = OraclePriceActiveActiveOracles { - active: previous_price[0].active.oracles.active, - total: previous_price[0].active.oracles.total, - }; - active_price = OraclePriceActiveActive { - amount: previous_price[0].active.amount.clone(), - weightage: previous_price[0].active.weightage, - oracles, - }; + None } + } else { + None + }; - let oracle_price_active = OraclePriceActive { - id: price_active_id.clone(), - key: oracle_price_key, - sort: hex::encode(ctx.block.height.to_be_bytes()), - active: active_price.clone(), - next: next_price.clone(), - is_live: is_live(Some(active_price), Some(next_price)), - block: ctx.block.clone(), - }; - services - .oracle_price_active - .by_id - .put(&price_active_id, &oracle_price_active)?; - services - .oracle_price_active - .by_key - .put(&oracle_price_active.key, &oracle_price_active.id)?; - } + let price_active_id = ( + ticker_id.0.clone(), + ticker_id.1.clone(), + aggregated_price.block.height, + ); + + let next_price = if is_aggregate_valid(aggregated_price, ctx) { + Some(OraclePriceActiveNext { + amount: aggregated_price.aggregated.amount.clone(), + weightage: aggregated_price.aggregated.weightage, + oracles: OraclePriceActiveNextOracles { + active: aggregated_price.aggregated.oracles.active, + total: aggregated_price.aggregated.oracles.total, + }, + }) + } else { + None + }; + + let oracle_price_active = OraclePriceActive { + id: price_active_id.clone(), + key: ticker_id, + sort: hex::encode(ctx.block.height.to_be_bytes()), + active: active_price.clone(), + next: next_price.clone(), + is_live: is_live(active_price, next_price), + block: ctx.block.clone(), + }; + + services + .oracle_price_active + .by_id + .put(&price_active_id, &oracle_price_active)?; + + services + .oracle_price_active + .by_key + .put(&oracle_price_active.key, &oracle_price_active.id)?; + + log::debug!( + "set_loan_token indexing oracle_price_active: {:?}", + oracle_price_active + ); Ok(()) } + fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { let ticker_id = ( self.currency_pair.token.clone(), @@ -134,52 +149,59 @@ impl Index for SetLoanToken { Ok(()) } } -pub fn aggregated_validate(aggrigated_price: OraclePriceAggregated, context: &Context) -> bool { - let minimum_live_oracles = 2; - if (aggrigated_price.block.time - context.block.time).abs() >= 3600 { + +fn is_aggregate_valid(aggregate: &OraclePriceAggregated, context: &Context) -> bool { + if (aggregate.block.time - context.block.time).abs() >= 3600 { return false; } - if aggrigated_price.aggregated.oracles.active < minimum_live_oracles { + + if aggregate.aggregated.oracles.active < 2 { + // minimum live oracles return false; } - if aggrigated_price.aggregated.weightage <= 0 { + if aggregate.aggregated.weightage <= 0 { return false; } true } -pub fn is_live( - active: Option, - next: Option, -) -> bool { - if let (Some(active), Some(next)) = (active, next) { - let active_price = match Decimal::from_str_exact(&active.amount) { - Ok(num) => num, - Err(_) => return false, - }; +fn is_live(active: Option, next: Option) -> bool { + if active.is_none() { + return false; + } - let next_price = match Decimal::from_str_exact(&next.amount) { - Ok(num) => num, - Err(_) => return false, - }; + if next.is_none() { + return false; + } - if active_price <= Decimal::zero() || next_price <= Decimal::zero() { - return false; - } + let active = active.unwrap(); + let next = next.unwrap(); - let deviation_threshold = Decimal::new(5, 1); // This represents 0.5 + let active_price = match Decimal::from_str(&active.amount) { + Ok(num) => num, + Err(_) => return false, + }; - let diff = next_price - active_price; - let abs_diff = diff.abs(); - let threshold = active_price * deviation_threshold; - if abs_diff >= threshold { - return false; - } + let next_price = match Decimal::from_str(&next.amount) { + Ok(num) => num, + Err(_) => return false, + }; + + if active_price <= Decimal::zero() { + return false; + } - true - } else { - false + if next_price <= Decimal::zero() { + return false; } + + let diff = (next_price - active_price).abs(); + let threshold = active_price * dec!(0.3); // deviation_threshold 0.3 + if diff >= threshold { + return false; + } + + true } diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 983e10cc633..b0d72048f16 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -531,7 +531,7 @@ pub fn index_block(services: &Arc, block: Block) -> Resul DfTx::SetLoanToken(data) => data.index(services, &ctx)?, DfTx::CompositeSwap(data) => data.index(services, &ctx)?, DfTx::CreatePoolPair(data) => data.index(services, &ctx)?, - // DfTx::PlaceAuctionBid(data) => data.index(services, &ctx)?, + DfTx::PlaceAuctionBid(data) => data.index(services, &ctx)?, _ => (), } log_elapsed(start, "Indexed dftx"); diff --git a/lib/ain-ocean/src/model/oracle_price_active.rs b/lib/ain-ocean/src/model/oracle_price_active.rs index 9185cb03d3a..08c08c893eb 100644 --- a/lib/ain-ocean/src/model/oracle_price_active.rs +++ b/lib/ain-ocean/src/model/oracle_price_active.rs @@ -4,14 +4,14 @@ use super::BlockContext; pub type OraclePriceActiveId = (String, String, u32); //token-currency-height pub type OraclePriceActiveKey = (String, String); //token-currency -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct OraclePriceActive { pub id: OraclePriceActiveId, pub key: OraclePriceActiveKey, pub sort: String, //height - pub active: OraclePriceActiveActive, - pub next: OraclePriceActiveNext, + pub active: Option, + pub next: Option, pub is_live: bool, pub block: BlockContext, } diff --git a/lib/ain-ocean/src/model/vault_auction_batch_history.rs b/lib/ain-ocean/src/model/vault_auction_batch_history.rs index c502265a247..0ba11786ce8 100644 --- a/lib/ain-ocean/src/model/vault_auction_batch_history.rs +++ b/lib/ain-ocean/src/model/vault_auction_batch_history.rs @@ -3,8 +3,8 @@ use serde::{Deserialize, Serialize}; use super::BlockContext; -pub type AuctionHistoryKey = (Txid, u32, Txid); -pub type AuctionHistoryByHeightKey = (Txid, u32, u32, usize); +pub type AuctionHistoryKey = (Txid, u32, Txid); // (vault_id, auction_batch_index, txid) +pub type AuctionHistoryByHeightKey = (Txid, u32, u32, usize); // (vault_id, auction_batch_index, block_height, txid) #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] diff --git a/lib/ain-ocean/src/repository/oracle_price_active.rs b/lib/ain-ocean/src/repository/oracle_price_active.rs index de1cfcf5157..172ad0c2013 100644 --- a/lib/ain-ocean/src/repository/oracle_price_active.rs +++ b/lib/ain-ocean/src/repository/oracle_price_active.rs @@ -3,11 +3,11 @@ use std::sync::Arc; use ain_db::LedgerColumn; use ain_macros::Repository; -use super::RepositoryOps; +use super::{RepositoryOps, SecondaryIndex}; use crate::{ model::{OraclePriceActive, OraclePriceActiveId, OraclePriceActiveKey}, storage::{columns, ocean_store::OceanStore}, - Result, + Error, Result, }; #[derive(Repository)] @@ -23,3 +23,16 @@ pub struct OraclePriceActiveKeyRepository { pub store: Arc, col: LedgerColumn, } + +impl SecondaryIndex for OraclePriceActiveKeyRepository { + type Value = OraclePriceActive; + + fn retrieve_primary_value(&self, el: Self::ListItem) -> Result { + let (_, id) = el?; + + let col = self.store.column::(); + let res = col.get(&id)?.ok_or(Error::SecondaryIndex)?; + + Ok(res) + } +} From 9d791155f36314140c6f2cee6cf08c148959c6dc Mon Sep 17 00:00:00 2001 From: canonbrother Date: Tue, 16 Jul 2024 17:32:21 +0800 Subject: [PATCH 116/185] Ocean: vault get + list apis (#2958) * api get_vault * list_auctions plural * list_vaults api * get_loan_token * clippy * use anyhow::Context --- lib/ain-ocean/src/api/loan.rs | 430 +++++++++++++++++++++++----------- 1 file changed, 292 insertions(+), 138 deletions(-) diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index 6725f08118b..7c8bb6fffd0 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -1,21 +1,24 @@ use std::{str::FromStr, sync::Arc}; use ain_macros::ocean_endpoint; -use anyhow::format_err; +use anyhow::{format_err, Context}; use axum::{routing::get, Extension, Router}; use bitcoin::{hashes::Hash, Txid}; use defichain_rpc::{ defichain_rpc_json::{ loan::{CollateralTokenDetail, LoanSchemeResult}, token::TokenInfo, - vault::VaultLiquidationBatch, + vault::{VaultActive, VaultLiquidationBatch}, + }, + json::vault::{ + AuctionPagination, AuctionPaginationStart, ListVaultOptions, VaultLiquidation, + VaultPagination, VaultResult, VaultState, }, - json::vault::{AuctionPagination, AuctionPaginationStart, VaultState}, LoanRPC, VaultRPC, }; use futures::future::try_join_all; use log::debug; -use serde::Serialize; +use serde::{Serialize, Serializer}; use super::{ cache::{get_loan_scheme_cached, get_token_cached}, @@ -217,20 +220,173 @@ async fn list_loan_token( })) } -// #[ocean_endpoint] -// async fn get_loan_token(Path(token_id): Path) -> String { -// format!("Details of loan token with id {}", token_id) -// } +#[ocean_endpoint] +async fn get_loan_token( + Path(token_id): Path, + Extension(ctx): Extension>, +) -> Result> { + let loan_token_result = ctx.client.get_loan_token(token_id).await?; + let res = loan_token_result + .token + .0 + .into_iter() + .next() + .map(|(id, info)| LoanToken { + token_id: id.clone(), + token: TokenData::from_with_id(id, info), + interest: loan_token_result.interest, + }) + .context("Unable to find loan token")?; + + Ok(Response::new(res)) +} + +#[ocean_endpoint] +async fn list_vaults( + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let option = ListVaultOptions { + verbose: Some(true), + owner_address: None, + loan_scheme_id: None, + state: None, + }; + let pagination = VaultPagination { + start: query.next, + including_start: None, + limit: if query.size > 30 { + Some(30) + } else { + Some(query.size) + }, + }; + let vaults = ctx.client.list_vaults(option, pagination).await?; + let mut list = Vec::new(); + for vault in vaults { + let each = match vault { + VaultResult::VaultActive(vault) => { + VaultResponse::Active(map_vault_active(&ctx, vault).await?) + } + VaultResult::VaultLiquidation(vault) => { + VaultResponse::Liquidated(map_vault_liquidation(&ctx, vault).await?) + } + }; + list.push(each) + } + + Ok(ApiPagedResponse::of(list, query.size, |each| match each { + VaultResponse::Active(vault) => vault.vault_id.clone(), + VaultResponse::Liquidated(vault) => vault.vault_id.clone(), + })) +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct LoanScheme { + id: String, + min_col_ratio: String, + interest_rate: String, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct VaultActiveResponse { + vault_id: String, + loan_scheme: LoanScheme, + owner_address: String, + #[serde(default = "VaultState::Active")] + state: VaultState, + informative_ratio: String, + collateral_ratio: String, + collateral_value: String, + loan_value: String, + interest_value: String, + collateral_amounts: Vec, + loan_amounts: Vec, + interest_amounts: Vec, +} + +async fn map_loan_scheme(ctx: &Arc, id: String) -> Result { + let loan_scheme = get_loan_scheme_cached(ctx, id).await?; + Ok(LoanScheme { + id: loan_scheme.id, + min_col_ratio: loan_scheme.mincolratio.to_string(), + interest_rate: loan_scheme.interestrate.to_string(), + }) +} + +async fn map_vault_active( + ctx: &Arc, + vault: VaultActive, +) -> Result { + Ok(VaultActiveResponse { + vault_id: vault.vault_id, + loan_scheme: map_loan_scheme(ctx, vault.loan_scheme_id).await?, + owner_address: vault.owner_address, + state: VaultState::Active, + informative_ratio: vault.informative_ratio.to_string(), + collateral_ratio: vault.collateral_ratio.to_string(), + collateral_value: vault.collateral_value.to_string(), + loan_value: vault.loan_value.to_string(), + interest_value: vault.interest_value.to_string(), + collateral_amounts: map_token_amounts(ctx, vault.collateral_amounts).await?, + loan_amounts: map_token_amounts(ctx, vault.loan_amounts).await?, + interest_amounts: map_token_amounts(ctx, vault.interest_amounts).await?, + }) +} -// #[ocean_endpoint] -// async fn list_vault() -> String { -// "List of vaults".to_string() -// } +async fn map_vault_liquidation( + ctx: &Arc, + vault: VaultLiquidation, +) -> Result { + let loan_scheme = get_loan_scheme_cached(ctx, vault.loan_scheme_id).await?; + Ok(VaultLiquidatedResponse { + batches: map_liquidation_batches(ctx, &vault.vault_id, vault.batches).await?, + vault_id: vault.vault_id, + loan_scheme, + owner_address: vault.owner_address, + state: vault.state, + liquidation_height: vault.liquidation_height, + liquidation_penalty: vault.liquidation_penalty, + batch_count: vault.batch_count, + }) +} + +enum VaultResponse { + Active(VaultActiveResponse), + Liquidated(VaultLiquidatedResponse), +} + +impl Serialize for VaultResponse { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: Serializer, + { + match self { + VaultResponse::Active(v) => v.serialize(serializer), + VaultResponse::Liquidated(v) => v.serialize(serializer), + } + } +} + +#[ocean_endpoint] +async fn get_vault( + Path(vault_id): Path, + Extension(ctx): Extension>, +) -> Result> { + let vault = ctx.client.get_vault(vault_id, Some(false)).await?; + let res = match vault { + VaultResult::VaultActive(vault) => { + VaultResponse::Active(map_vault_active(&ctx, vault).await?) + } + VaultResult::VaultLiquidation(vault) => { + VaultResponse::Liquidated(map_vault_liquidation(&ctx, vault).await?) + } + }; -// #[ocean_endpoint] -// async fn get_vault(Path(vault_id): Path) -> String { -// format!("Details of vault with id {}", vault_id) -// } + Ok(Response::new(res)) +} #[ocean_endpoint] async fn list_vault_auction_history( @@ -296,7 +452,7 @@ async fn list_vault_auction_history( #[derive(Serialize, Debug)] #[serde(rename_all = "camelCase")] -pub struct VaultLiquidationResponse { +pub struct VaultLiquidatedResponse { pub vault_id: String, pub loan_scheme: LoanSchemeResult, pub owner_address: String, @@ -305,7 +461,7 @@ pub struct VaultLiquidationResponse { pub liquidation_height: u64, pub liquidation_penalty: f64, pub batch_count: usize, - pub batches: Vec, + pub batches: Vec, } #[derive(Serialize, Debug)] @@ -317,7 +473,7 @@ pub struct HighestBidResponse { #[derive(Serialize, Debug)] #[serde(rename_all = "camelCase")] -pub struct VaultLiquidationBatchResponse { +pub struct VaultLiquidatedBatchResponse { index: u32, collaterals: Vec, loan: Option, @@ -337,11 +493,121 @@ pub struct VaultTokenAmountResponse { pub active_price: Option, } +async fn map_liquidation_batches( + ctx: &Arc, + vault_id: &str, + batches: Vec, +) -> Result> { + let repo = &ctx.services.auction; + let mut vec = Vec::new(); + for batch in batches { + let highest_bid = if let Some(bid) = batch.highest_bid { + let amount = map_token_amounts(ctx, vec![bid.amount]).await?; + let res = HighestBidResponse { + owner: bid.owner, + amount: amount.first().cloned(), + }; + Some(res) + } else { + None + }; + let id = ( + Txid::from_str(vault_id)?, + batch.index, + Txid::from_byte_array([0xffu8; 32]), + ); + let bids = repo + .by_id + .list(Some(id), SortOrder::Descending)? + .take_while(|item| match item { + Ok(((vid, bindex, _), _)) => vid.to_string() == vault_id && bindex == &batch.index, + _ => true, + }) + .collect::>(); + let froms = bids + .into_iter() + .map(|bid| { + let (_, v) = bid?; + let from_addr = from_script(v.from, ctx.network.into())?; + Ok::(from_addr) + }) + .collect::>>()?; + vec.push(VaultLiquidatedBatchResponse { + index: batch.index, + collaterals: map_token_amounts(ctx, batch.collaterals).await?, + loan: map_token_amounts(ctx, vec![batch.loan]) + .await? + .first() + .cloned(), + froms, + highest_bid, + }) + } + Ok(vec) +} + +async fn map_token_amounts( + ctx: &Arc, + amounts: Vec, +) -> Result> { + if amounts.is_empty() { + return Ok(Vec::new()); + } + let amount_token_symbols = amounts + .into_iter() + .map(|amount| { + let amount = amount.to_owned(); + let parts = amount.split('@').collect::>(); + let [amount, token_symbol] = <[&str; 2]>::try_from(parts) + .map_err(|_| format_err!("Invalid amount structure"))?; + Ok([amount.to_string(), token_symbol.to_string()]) + }) + .collect::>>()?; + + let mut vault_token_amounts = Vec::new(); + for [amount, token_symbol] in amount_token_symbols { + let token = get_token_cached(ctx, &token_symbol).await?; + if token.is_none() { + log::error!("Token {token_symbol} not found"); + continue; + } + let repo = &ctx.services.oracle_price_active; + let (id, token_info) = token.unwrap(); + let keys = repo + .by_key + .list(None, SortOrder::Descending)? + .collect::>(); + log::debug!("list_auctions keys: {:?}, token_id: {:?}", keys, id); + let active_price = repo + .by_key + .list(None, SortOrder::Descending)? + .take(1) + .take_while(|item| match item { + Ok((k, _)) => k.0 == id, + _ => true, + }) + .map(|el| repo.by_key.retrieve_primary_value(el)) + .collect::>>()?; + + vault_token_amounts.push(VaultTokenAmountResponse { + id, + display_symbol: parse_display_symbol(&token_info), + amount: amount.to_string(), + symbol: token_info.symbol, + symbol_key: token_info.symbol_key, + name: token_info.name, + active_price: active_price.first().cloned(), + }) + } + + Ok(vault_token_amounts) +} + #[ocean_endpoint] -async fn list_auction( +async fn list_auctions( Query(query): Query, Extension(ctx): Extension>, -) -> Result> { +) -> Result> { let start = query.next.as_ref().map(|next| { let vault_id = &next[0..64]; let height = &next[64..]; @@ -361,123 +627,11 @@ async fn list_auction( }, }; - async fn map_liquidation_batches( - ctx: &Arc, - vault_id: &str, - batches: Vec, - ) -> Result> { - let repo = &ctx.services.auction; - let mut vec = Vec::new(); - for batch in batches { - let highest_bid = if let Some(bid) = batch.highest_bid { - let amount = map_token_amounts(ctx, vec![bid.amount]).await?; - let res = HighestBidResponse { - owner: bid.owner, - amount: amount.first().cloned(), - }; - Some(res) - } else { - None - }; - let id = ( - Txid::from_str(vault_id)?, - batch.index, - Txid::from_byte_array([0xffu8; 32]), - ); - let bids = repo - .by_id - .list(Some(id), SortOrder::Descending)? - .take_while(|item| match item { - Ok(((vid, bindex, _), _)) => { - vid.to_string() == vault_id && bindex == &batch.index - } - _ => true, - }) - .collect::>(); - let froms = bids - .into_iter() - .map(|bid| { - let (_, v) = bid?; - let from_addr = from_script(v.from, ctx.network.into())?; - Ok::(from_addr) - }) - .collect::>>()?; - vec.push(VaultLiquidationBatchResponse { - index: batch.index, - collaterals: map_token_amounts(ctx, batch.collaterals).await?, - loan: map_token_amounts(ctx, vec![batch.loan]) - .await? - .first() - .cloned(), - froms, - highest_bid, - }) - } - Ok(vec) - } - - async fn map_token_amounts( - ctx: &Arc, - amounts: Vec, - ) -> Result> { - if amounts.is_empty() { - return Ok(Vec::new()); - } - let amount_token_symbols = amounts - .into_iter() - .map(|amount| { - let amount = amount.to_owned(); - let parts = amount.split('@').collect::>(); - let [amount, token_symbol] = <[&str; 2]>::try_from(parts) - .map_err(|_| format_err!("Invalid amount structure"))?; - Ok([amount.to_string(), token_symbol.to_string()]) - }) - .collect::>>()?; - - let mut vault_token_amounts = Vec::new(); - for [amount, token_symbol] in amount_token_symbols { - let token = get_token_cached(ctx, &token_symbol).await?; - if token.is_none() { - log::error!("Token {token_symbol} not found"); - continue; - } - let repo = &ctx.services.oracle_price_active; - let (id, token_info) = token.unwrap(); - let keys = repo - .by_key - .list(None, SortOrder::Descending)? - .collect::>(); - log::debug!("list_auctions keys: {:?}, token_id: {:?}", keys, id); - let active_price = repo - .by_key - .list(None, SortOrder::Descending)? - .take(1) - .take_while(|item| match item { - Ok((k, _)) => k.0 == id, - _ => true, - }) - .map(|el| repo.by_key.retrieve_primary_value(el)) - .collect::>>()?; - - vault_token_amounts.push(VaultTokenAmountResponse { - id, - display_symbol: parse_display_symbol(&token_info), - amount: amount.to_string(), - symbol: token_info.symbol, - symbol_key: token_info.symbol_key, - name: token_info.name, - active_price: active_price.first().cloned(), - }) - } - - Ok(vault_token_amounts) - } - let mut vaults = Vec::new(); let liquidation_vaults = ctx.client.list_auctions(Some(pagination)).await?; for vault in liquidation_vaults { let loan_scheme = get_loan_scheme_cached(&ctx, vault.loan_scheme_id).await?; - let res = VaultLiquidationResponse { + let res = VaultLiquidatedResponse { batches: map_liquidation_batches(&ctx, &vault.vault_id, vault.batches).await?, vault_id: vault.vault_id, loan_scheme, @@ -502,13 +656,13 @@ pub fn router(ctx: Arc) -> Router { .route("/collaterals", get(list_collateral_token)) .route("/collaterals/:id", get(get_collateral_token)) .route("/tokens", get(list_loan_token)) - // .route("/tokens/:id", get(get_loan_token)) - // .route("/vaults", get(list_vault)) - // .route("/vaults/:id", get(get_vault)) + .route("/tokens/:id", get(get_loan_token)) + .route("/vaults", get(list_vaults)) + .route("/vaults/:id", get(get_vault)) .route( "/vaults/:id/auctions/:height/batches/:batchIndex/history", get(list_vault_auction_history), ) - .route("/auctions", get(list_auction)) + .route("/auctions", get(list_auctions)) .layer(Extension(ctx)) } From 53835b1c3bd0b88587b550bbf4702df3f21e3e06 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Tue, 16 Jul 2024 20:32:39 +0800 Subject: [PATCH 117/185] Ocean: finishing get/list loan token api (#2968) * wip * add active price and fixed interval price id on struct LoanToken * sorted by creation_tx * clippy * fmt * rust-defichain-rpc main * fix fake_paginate --- lib/ain-ocean/src/api/loan.rs | 88 ++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index 7c8bb6fffd0..7dbcff26c3b 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -1,7 +1,7 @@ use std::{str::FromStr, sync::Arc}; use ain_macros::ocean_endpoint; -use anyhow::{format_err, Context}; +use anyhow::format_err; use axum::{routing::get, Extension, Router}; use bitcoin::{hashes::Hash, Txid}; use defichain_rpc::{ @@ -159,16 +159,14 @@ async fn get_collateral_token( ))) } -#[derive(Serialize)] +#[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct LoanToken { token_id: String, token: TokenData, - interest: f64, - // activate_after_block: u32, - // fixed_interval_price_id: String, - // TODO when indexing price - // activePrice?: ActivePrice + interest: String, + fixed_interval_price_id: String, + active_price: Option, } #[ocean_endpoint] @@ -181,10 +179,11 @@ async fn list_loan_token( struct FlattenToken { id: String, data: TokenInfo, + fixed_interval_price_id: String, interest: f64, } - let fut = tokens + let res = tokens .into_iter() .flat_map(|el| { el.token @@ -194,26 +193,40 @@ async fn list_loan_token( .map(|(id, data)| FlattenToken { id, data, + fixed_interval_price_id: el.fixed_interval_price_id, interest: el.interest, }) }) .fake_paginate(&query, |token| match &query.next { None => false, - Some(v) => v != &token.id, + Some(v) => v != &token.data.creation_tx, }) - .map(|token| async move { + .map(|flatten_token| { + let fixed_interval_price_id = flatten_token.fixed_interval_price_id.clone(); + let parts = fixed_interval_price_id.split('/').collect::>(); + let [token, currency] = <[&str; 2]>::try_from(parts) + .map_err(|_| format_err!("Invalid fixed interval price id structure"))?; + + let repo = &ctx.services.oracle_price_active; + let key = repo + .by_key + .get(&(token.to_string(), currency.to_string()))?; + let active_price = if let Some(key) = key { + repo.by_id.get(&key)? + } else { + None + }; + let token = LoanToken { - token_id: token.id.clone(), - token: TokenData::from_with_id(token.id, token.data), - interest: token.interest, - // activate_after_block: todo!(), - // fixed_interval_price_id: todo!(), + token_id: flatten_token.data.creation_tx.clone(), + token: TokenData::from_with_id(flatten_token.id, flatten_token.data), + interest: format!("{:.2}", flatten_token.interest), + fixed_interval_price_id, + active_price, }; Ok::(token) }) - .collect::>(); - - let res = try_join_all(fut).await?; + .collect::>>()?; Ok(ApiPagedResponse::of(res, query.size, |loan_scheme| { loan_scheme.token_id.to_owned() @@ -225,20 +238,43 @@ async fn get_loan_token( Path(token_id): Path, Extension(ctx): Extension>, ) -> Result> { - let loan_token_result = ctx.client.get_loan_token(token_id).await?; - let res = loan_token_result + let loan_token_result = ctx.client.get_loan_token(token_id.clone()).await?; + let token = loan_token_result .token .0 .into_iter() .next() - .map(|(id, info)| LoanToken { - token_id: id.clone(), - token: TokenData::from_with_id(id, info), - interest: loan_token_result.interest, + .map(|(id, info)| { + let fixed_interval_price_id = loan_token_result.fixed_interval_price_id.clone(); + let parts = fixed_interval_price_id.split('/').collect::>(); + let [token, currency] = <[&str; 2]>::try_from(parts) + .map_err(|_| format_err!("Invalid fixed interval price id structure"))?; + + let repo = &ctx.services.oracle_price_active; + let key = repo + .by_key + .get(&(token.to_string(), currency.to_string()))?; + let active_price = if let Some(key) = key { + repo.by_id.get(&key)? + } else { + None + }; + + Ok::(LoanToken { + token_id: info.creation_tx.clone(), + token: TokenData::from_with_id(id, info), + interest: format!("{:.2}", loan_token_result.interest), + fixed_interval_price_id, + active_price, + }) }) - .context("Unable to find loan token")?; + .transpose()?; - Ok(Response::new(res)) + if token.is_none() { + return Err(format_err!("Token {:?} does not exist!", token_id).into()); + } + + Ok(Response::new(token.unwrap())) } #[ocean_endpoint] From feb799eb23c59de70d82a590fecd529cc98e4706 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Wed, 17 Jul 2024 16:29:53 +0800 Subject: [PATCH 118/185] Ocean: api list vaults by address (#2974) * refactor + vault by address * api missing addr path --- lib/ain-ocean/src/api/address.rs | 34 +++++++++++++++++++---- lib/ain-ocean/src/api/loan.rs | 47 ++++++++++++++++++++------------ 2 files changed, 58 insertions(+), 23 deletions(-) diff --git a/lib/ain-ocean/src/api/address.rs b/lib/ain-ocean/src/api/address.rs index 991ee0181c9..b461755d5b9 100644 --- a/lib/ain-ocean/src/api/address.rs +++ b/lib/ain-ocean/src/api/address.rs @@ -3,6 +3,7 @@ use std::{collections::BTreeMap, str::FromStr, sync::Arc}; use super::{ cache::get_token_cached, common::{address_to_hid, parse_display_symbol}, + loan::{get_all_vaults, VaultResponse}, path::Path, query::{PaginationQuery, Query}, response::{ApiPagedResponse, Response}, @@ -21,7 +22,10 @@ use ain_macros::ocean_endpoint; use anyhow::Context; use axum::{routing::get, Extension, Router}; use bitcoin::{hashes::Hash, hex::DisplayHex, BlockHash, Txid}; -use defichain_rpc::{json::account::AccountHistory, AccountRPC, RpcApi}; +use defichain_rpc::{ + json::{account::AccountHistory, vault::ListVaultOptions}, + AccountRPC, RpcApi, +}; use serde::{Deserialize, Serialize}; use serde_json::json; use serde_with::skip_serializing_none; @@ -205,9 +209,29 @@ async fn get_aggregation( // format!("List tokens for address {}", address) // } -// async fn list_vault(Path(Address { address }): Path
) -> String { -// format!("List vaults for address {}", address) -// } +#[ocean_endpoint] +async fn list_vaults( + Path(Address { address }): Path
, + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let options = ListVaultOptions { + verbose: Some(true), + owner_address: Some(address), + loan_scheme_id: None, + state: None, + }; + let vaults = get_all_vaults(&ctx, options, &query).await?; + + Ok(ApiPagedResponse::of( + vaults, + query.size, + |each| match each { + VaultResponse::Active(vault) => vault.vault_id.clone(), + VaultResponse::Liquidated(vault) => vault.vault_id.clone(), + }, + )) +} #[skip_serializing_none] #[derive(Debug, Serialize)] @@ -494,7 +518,7 @@ pub fn router(ctx: Arc) -> Router { .route("/:address/balance", get(get_balance)) .route("/:address/aggregation", get(get_aggregation)) .route("/:address/tokens", get(list_tokens)) - // .route("/vaults", get(list_vault)) + .route("/:address/vaults", get(list_vaults)) .route("/:address/transactions", get(list_transactions)) .route( "/:address/transactions/unspent", diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index 7dbcff26c3b..4fdf1eba0d5 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -277,19 +277,13 @@ async fn get_loan_token( Ok(Response::new(token.unwrap())) } -#[ocean_endpoint] -async fn list_vaults( - Query(query): Query, - Extension(ctx): Extension>, -) -> Result> { - let option = ListVaultOptions { - verbose: Some(true), - owner_address: None, - loan_scheme_id: None, - state: None, - }; +pub async fn get_all_vaults( + ctx: &Arc, + options: ListVaultOptions, + query: &PaginationQuery, +) -> Result> { let pagination = VaultPagination { - start: query.next, + start: query.next.to_owned(), including_start: None, limit: if query.size > 30 { Some(30) @@ -297,20 +291,37 @@ async fn list_vaults( Some(query.size) }, }; - let vaults = ctx.client.list_vaults(option, pagination).await?; + + let vaults = ctx.client.list_vaults(options, pagination).await?; let mut list = Vec::new(); for vault in vaults { let each = match vault { VaultResult::VaultActive(vault) => { - VaultResponse::Active(map_vault_active(&ctx, vault).await?) + VaultResponse::Active(map_vault_active(ctx, vault).await?) } VaultResult::VaultLiquidation(vault) => { - VaultResponse::Liquidated(map_vault_liquidation(&ctx, vault).await?) + VaultResponse::Liquidated(map_vault_liquidation(ctx, vault).await?) } }; list.push(each) } + Ok(list) +} + +#[ocean_endpoint] +async fn list_vaults( + Query(query): Query, + Extension(ctx): Extension>, +) -> Result> { + let options = ListVaultOptions { + verbose: Some(true), + owner_address: None, + loan_scheme_id: None, + state: None, + }; + let list = get_all_vaults(&ctx, options, &query).await?; + Ok(ApiPagedResponse::of(list, query.size, |each| match each { VaultResponse::Active(vault) => vault.vault_id.clone(), VaultResponse::Liquidated(vault) => vault.vault_id.clone(), @@ -327,8 +338,8 @@ struct LoanScheme { #[derive(Serialize)] #[serde(rename_all = "camelCase")] -struct VaultActiveResponse { - vault_id: String, +pub struct VaultActiveResponse { + pub vault_id: String, loan_scheme: LoanScheme, owner_address: String, #[serde(default = "VaultState::Active")] @@ -389,7 +400,7 @@ async fn map_vault_liquidation( }) } -enum VaultResponse { +pub enum VaultResponse { Active(VaultActiveResponse), Liquidated(VaultLiquidatedResponse), } From 6b5b7ddfbdb585588580564ce4363fcb76d29159 Mon Sep 17 00:00:00 2001 From: Nagaraj <144004792+nagarajm22@users.noreply.github.com> Date: Wed, 17 Jul 2024 21:53:46 +0800 Subject: [PATCH 119/185] Ocean: Implements `index_block_end ` (#2969) * block end implementation * invalidate block end implementation * indexing_block_end implementation * indexing and invalidating block_end * ocean:indexing block_end * ocean:fixed duplicates invalidate_block * revert cargo.lock e466866 * oop kind refactor * fix * rm unuse clone --------- Co-authored-by: canonbrother --- lib/Cargo.toml | 2 +- lib/ain-ocean/src/indexer/loan_token.rs | 269 +++++++++++++----------- lib/ain-ocean/src/indexer/mod.rs | 10 +- 3 files changed, 160 insertions(+), 121 deletions(-) diff --git a/lib/Cargo.toml b/lib/Cargo.toml index df3ddb4b24d..b3f2a309544 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -125,7 +125,7 @@ substrate-bn = "0.6" #### Ocean dependencies bitcoin = "0.31" cached = { version = "0.48", features = ["async"] } -defichain-rpc = { version = "0.18.0", git = "https://github.com/defich/rust-defichain-rpc.git" } +defichain-rpc = { version = "0.18.0", git = "https://github.com/defich/rust-defichain-rpc.git"} ### Local crates ain-cpp-imports = { path = "./ain-cpp-imports" } diff --git a/lib/ain-ocean/src/indexer/loan_token.rs b/lib/ain-ocean/src/indexer/loan_token.rs index 6f518218f58..262ac91a8ee 100644 --- a/lib/ain-ocean/src/indexer/loan_token.rs +++ b/lib/ain-ocean/src/indexer/loan_token.rs @@ -7,9 +7,10 @@ use rust_decimal_macros::dec; use crate::{ indexer::{Context, Index, Result}, model::{ - OraclePriceActive, OraclePriceActiveActive, OraclePriceActiveActiveOracles, + BlockContext, OraclePriceActive, OraclePriceActiveActive, OraclePriceActiveActiveOracles, OraclePriceActiveNext, OraclePriceActiveNextOracles, OraclePriceAggregated, }, + network::Network, repository::RepositoryOps, storage::SortOrder, Services, @@ -17,121 +18,8 @@ use crate::{ impl Index for SetLoanToken { fn index(self, services: &Arc, ctx: &Context) -> Result<()> { - let ticker_id = (self.currency_pair.token, self.currency_pair.currency); - let aggregated_prices = services - .oracle_price_aggregated - .by_key - .list(Some(ticker_id.clone()), SortOrder::Descending)? - .map(|item| { - let (_, id) = item?; - let aggregated = services - .oracle_price_aggregated - .by_id - .get(&id)? - .ok_or("Missing oracle previous history index")?; - - Ok(aggregated) - }) - .collect::>>()?; - - log::debug!( - "set_loan_token indexing aggregated_price: {:?}", - aggregated_prices - ); - - if aggregated_prices.is_empty() { - return Ok(()); - } - let aggregated_price = aggregated_prices.first().unwrap(); - - let previous_prices = services - .oracle_price_active - .by_key - .list(Some(ticker_id.clone()), SortOrder::Descending)? - .take(1) - .map(|item| { - let (_, id) = item?; - let price = services - .oracle_price_active - .by_id - .get(&id)? - .ok_or("Missing oracle previous history index")?; - Ok(price) - }) - .collect::>>()?; - - let active_price = if previous_prices.first().is_some() { - if previous_prices[0].next.is_some() { - let price = previous_prices[0].next.clone().unwrap(); - Some(OraclePriceActiveActive { - amount: price.amount, - weightage: price.weightage, - oracles: OraclePriceActiveActiveOracles { - active: price.oracles.active, - total: price.oracles.total, - }, - }) - } else if previous_prices[0].active.is_some() { - let price = previous_prices[0].active.clone().unwrap(); - Some(OraclePriceActiveActive { - amount: price.amount, - weightage: price.weightage, - oracles: OraclePriceActiveActiveOracles { - active: price.oracles.active, - total: price.oracles.total, - }, - }) - } else { - None - } - } else { - None - }; - - let price_active_id = ( - ticker_id.0.clone(), - ticker_id.1.clone(), - aggregated_price.block.height, - ); - - let next_price = if is_aggregate_valid(aggregated_price, ctx) { - Some(OraclePriceActiveNext { - amount: aggregated_price.aggregated.amount.clone(), - weightage: aggregated_price.aggregated.weightage, - oracles: OraclePriceActiveNextOracles { - active: aggregated_price.aggregated.oracles.active, - total: aggregated_price.aggregated.oracles.total, - }, - }) - } else { - None - }; - - let oracle_price_active = OraclePriceActive { - id: price_active_id.clone(), - key: ticker_id, - sort: hex::encode(ctx.block.height.to_be_bytes()), - active: active_price.clone(), - next: next_price.clone(), - is_live: is_live(active_price, next_price), - block: ctx.block.clone(), - }; - - services - .oracle_price_active - .by_id - .put(&price_active_id, &oracle_price_active)?; - - services - .oracle_price_active - .by_key - .put(&oracle_price_active.key, &oracle_price_active.id)?; - - log::debug!( - "set_loan_token indexing oracle_price_active: {:?}", - oracle_price_active - ); - + let ticker = (self.currency_pair.token, self.currency_pair.currency); + perform_active_price_tick(services, ticker, &ctx.block)?; Ok(()) } @@ -150,8 +38,8 @@ impl Index for SetLoanToken { } } -fn is_aggregate_valid(aggregate: &OraclePriceAggregated, context: &Context) -> bool { - if (aggregate.block.time - context.block.time).abs() >= 3600 { +fn is_aggregate_valid(aggregate: &OraclePriceAggregated, block: &BlockContext) -> bool { + if (aggregate.block.time - block.time).abs() >= 3600 { return false; } @@ -205,3 +93,148 @@ fn is_live(active: Option, next: Option, block: &BlockContext) -> Result<()> { + let block_interval = match Network::Regtest { + Network::Regtest => 6, + _ => 120, + }; + if block.height % block_interval == 0 { + let pt = services + .price_ticker + .by_id + .list(None, SortOrder::Ascending)? + .map(|item| { + let (_, priceticker) = item?; + Ok(priceticker) + }) + .collect::>>()?; + + for ticker in pt { + perform_active_price_tick(services, ticker.id, block)?; + } + } + Ok(()) +} + +pub fn perform_active_price_tick( + services: &Arc, + ticker_id: (String, String), + block: &BlockContext, +) -> Result<()> { + let aggregated_prices = services + .oracle_price_aggregated + .by_key + .list(Some(ticker_id.clone()), SortOrder::Descending)? + .map(|item| { + let (_, id) = item?; + let aggregated = services + .oracle_price_aggregated + .by_id + .get(&id)? + .ok_or("Missing oracle previous history index")?; + + Ok(aggregated) + }) + .collect::>>()?; + + log::debug!( + "set_loan_token indexing aggregated_price: {:?}", + aggregated_prices + ); + + if aggregated_prices.is_empty() { + return Ok(()); + } + let aggregated_price = aggregated_prices.first().unwrap(); + + let previous_prices = services + .oracle_price_active + .by_key + .list(Some(ticker_id.clone()), SortOrder::Descending)? + .take(1) + .map(|item| { + let (_, id) = item?; + let price = services + .oracle_price_active + .by_id + .get(&id)? + .ok_or("Missing oracle previous history index")?; + Ok(price) + }) + .collect::>>()?; + + let active_price = if previous_prices.first().is_some() { + if previous_prices[0].next.is_some() { + let price = previous_prices[0].next.clone().unwrap(); + Some(OraclePriceActiveActive { + amount: price.amount, + weightage: price.weightage, + oracles: OraclePriceActiveActiveOracles { + active: price.oracles.active, + total: price.oracles.total, + }, + }) + } else if previous_prices[0].active.is_some() { + let price = previous_prices[0].active.clone().unwrap(); + Some(OraclePriceActiveActive { + amount: price.amount, + weightage: price.weightage, + oracles: OraclePriceActiveActiveOracles { + active: price.oracles.active, + total: price.oracles.total, + }, + }) + } else { + None + } + } else { + None + }; + + let price_active_id = ( + ticker_id.0.clone(), + ticker_id.1.clone(), + aggregated_price.block.height, + ); + + let next_price = if is_aggregate_valid(aggregated_price, block) { + Some(OraclePriceActiveNext { + amount: aggregated_price.aggregated.amount.clone(), + weightage: aggregated_price.aggregated.weightage, + oracles: OraclePriceActiveNextOracles { + active: aggregated_price.aggregated.oracles.active, + total: aggregated_price.aggregated.oracles.total, + }, + }) + } else { + None + }; + + let oracle_price_active = OraclePriceActive { + id: price_active_id.clone(), + key: ticker_id, + sort: hex::encode(block.height.to_be_bytes()), + active: active_price.clone(), + next: next_price.clone(), + is_live: is_live(active_price, next_price), + block: block.clone(), + }; + + services + .oracle_price_active + .by_id + .put(&price_active_id, &oracle_price_active)?; + + services + .oracle_price_active + .by_key + .put(&oracle_price_active.key, &oracle_price_active.id)?; + + log::debug!( + "set_loan_token indexing oracle_price_active: {:?}", + oracle_price_active + ); + + Ok(()) +} diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index b0d72048f16..744528dc558 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -465,6 +465,11 @@ fn index_script_unspent(services: &Arc, block: &Block) -> Ok(()) } +fn index_block_end(services: &Arc, block: &BlockContext) -> Result<()> { + loan_token::index_active_price(services, block)?; + Ok(()) +} + pub fn index_block(services: &Arc, block: Block) -> Result<()> { debug!("[index_block] Indexing block..."); let start = Instant::now(); @@ -490,7 +495,6 @@ pub fn index_block(services: &Arc, block: Block) -> Resul if is_skipped_tx(&tx.txid) { continue; } - let start = Instant::now(); let ctx = Context { block: block_ctx.clone(), @@ -511,7 +515,6 @@ pub fn index_block(services: &Arc, block: Block) -> Resul 0x4e => 4, _ => 1, }; - let raw_tx = &bytes[offset..]; match deserialize::(raw_tx) { Err(bitcoin::consensus::encode::Error::ParseFailed("Invalid marker")) => { @@ -568,6 +571,9 @@ pub fn index_block(services: &Arc, block: Block) -> Resul .by_height .put(&block_ctx.height, &block_hash)?; + //index block end + index_block_end(services, &block_ctx)?; + Ok(()) } From 47a8f1b98f89cf4454eb3516610982fa5d89bf43 Mon Sep 17 00:00:00 2001 From: Nagaraj <144004792+nagarajm22@users.noreply.github.com> Date: Thu, 18 Jul 2024 18:41:07 +0800 Subject: [PATCH 120/185] Ocean: Fixed oracle invalidate methods (#2973) * update oracle invalidate function * fixed remove and update oracle invalidate * Clippy fix --------- Co-authored-by: jouzo --- lib/ain-ocean/src/indexer/oracle.rs | 121 ++++++++++++++++------------ 1 file changed, 69 insertions(+), 52 deletions(-) diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index 2d2df15c4ec..22943e28379 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -1,6 +1,7 @@ use std::{str::FromStr, sync::Arc, vec}; use ain_dftx::{common::CompactVec, oracles::*}; +use anyhow::anyhow; use bitcoin::Txid; use rust_decimal::{ prelude::{FromPrimitive, ToPrimitive, Zero}, @@ -106,6 +107,7 @@ impl Index for AppointOracle { context.block.height, context.tx.txid, ))?; + services.oracle_history.by_key.delete(&(oracle_id))?; for currency_pair in self.price_feeds.as_ref().iter() { let token_currency_id = ( currency_pair.token.to_owned(), @@ -139,18 +141,29 @@ impl Index for RemoveOracle { Ok(previous_oracle) => { for oracle_history in &previous_oracle { for price_feed_item in &oracle_history.price_feeds { - let deletion_key = ( + let deletion_id = ( price_feed_item.token.to_owned(), price_feed_item.currency.to_owned(), oracle_history.oracle_id, ); - match services.oracle_token_currency.by_id.delete(&deletion_key) { + let deletion_key = ( + price_feed_item.token.to_owned(), + price_feed_item.currency.to_owned(), + oracle_history.block.height, + ); + match services.oracle_token_currency.by_id.delete(&deletion_id) { + Ok(_) => { + // Successfully deleted + } + Err(err) => { + return Err(Error::DBError(ain_db::DBError::Custom(err.into()))); + } + } + match services.oracle_token_currency.by_key.delete(&deletion_key) { Ok(_) => { // Successfully deleted } Err(err) => { - let error_message = format!("Error: remove_oracle: {:?}", err); - eprintln!("{}", error_message); return Err(Error::DBError(ain_db::DBError::Custom(err.into()))); } } @@ -158,9 +171,7 @@ impl Index for RemoveOracle { } } Err(err) => { - let error_message = format!("Error: remove_oracle: {:?}", err); - eprintln!("{}", error_message); - return Err(Error::NotFound(NotFoundKind::Oracle)); + return Err(Error::Other(anyhow!("remove oracle : {}", err))); } } Ok(()) @@ -168,7 +179,6 @@ impl Index for RemoveOracle { fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { let oracle_id = context.tx.txid; let previous_oracle_history_result = get_previous_oracle_history_list(services, oracle_id); - match previous_oracle_history_result { Ok(previous_oracle_history) => { for previous_oracle in previous_oracle_history { @@ -204,11 +214,15 @@ impl Index for RemoveOracle { .oracle_token_currency .by_id .put(&oracle_token_currency.id, &oracle_token_currency)?; + + services + .oracle_token_currency + .by_key + .put(&oracle_token_currency.key, &oracle_token_currency.id)?; } } } Err(err) => { - eprintln!("Error remove_oracle invalidate : {:?}", err); return Err(Error::from(err)); } } @@ -254,8 +268,6 @@ impl Index for UpdateOracle { // Successfully deleted } Err(err) => { - let error_message = format!("Error:update oracle: {:?}", err); - eprintln!("{}", error_message); return Err(Error::DBError(ain_db::DBError::Custom(err.into()))); } } @@ -269,8 +281,6 @@ impl Index for UpdateOracle { // Successfully deleted } Err(err) => { - let error_message = format!("Error: update_oracle: {:?}", err); - eprintln!("{}", error_message); return Err(Error::DBError(ain_db::DBError::Custom(err.into()))); } } @@ -278,9 +288,7 @@ impl Index for UpdateOracle { } } Err(err) => { - let error_message = format!("Error:update oracle: {:?}", err); - eprintln!("{}", error_message); - return Err(Error::NotFound(NotFoundKind::Oracle)); + return Err(Error::Other(anyhow!("update oracle : {}", err))); } } @@ -361,31 +369,47 @@ impl Index for UpdateOracle { match previous_oracle_history_result { Ok(previous_oracle_result) => { for previous_oracle in previous_oracle_result { - for price_feed_item in &previous_oracle.price_feeds { - let deletion_key = ( - price_feed_item.token.clone(), - price_feed_item.currency.clone(), - previous_oracle.oracle_id, - ); + let oracle = Oracle { + id: previous_oracle.oracle_id, + owner_address: previous_oracle.owner_address, + weightage: previous_oracle.weightage, + price_feeds: previous_oracle.price_feeds.clone(), + block: previous_oracle.block.clone(), + }; + services.oracle.by_id.put(&oracle.id, &oracle)?; + for prev_token_currency in &previous_oracle.price_feeds { + let oracle_token_currency = OracleTokenCurrency { + id: ( + prev_token_currency.token.clone(), + prev_token_currency.currency.clone(), + oracle.id, + ), + key: ( + prev_token_currency.token.clone(), + prev_token_currency.currency.clone(), + context.block.height, + ), + token: prev_token_currency.token.clone(), + currency: prev_token_currency.currency.to_owned(), + oracle_id, + weightage: oracle.weightage, + block: oracle.block.clone(), + }; - match services.oracle_token_currency.by_id.delete(&deletion_key) { - Ok(_) => { - // Successfully deleted - } - Err(err) => { - let error_message = - format!("Error updating oracle invalidate: {:?}", err); - eprintln!("{}", error_message); - return Err(Error::DBError(ain_db::DBError::Custom(err.into()))); - } - } + services + .oracle_token_currency + .by_id + .put(&oracle_token_currency.id, &oracle_token_currency)?; + + services + .oracle_token_currency + .by_key + .put(&oracle_token_currency.key, &oracle_token_currency.id)?; } } } Err(err) => { - let error_message = format!("Error updating oracle invalidate: {:?}", err); - eprintln!("{}", error_message); - return Err(Error::NotFound(NotFoundKind::Oracle)); + return Err(Error::Other(anyhow!("update oracle invalidate : {}", err))); } } Ok(()) @@ -593,6 +617,7 @@ impl Index for SetOracleData { for (token, currency) in pairs.iter() { let aggreated_id = (token.to_owned(), currency.to_owned(), context.block.height); + let aggreated_key = (token.to_owned(), currency.to_owned()); let aggregated_price = services.oracle_price_aggregated.by_id.get(&aggreated_id)?; if let Some(aggregated) = aggregated_price { for interval in &intervals { @@ -610,6 +635,10 @@ impl Index for SetOracleData { .oracle_price_aggregated .by_id .delete(&aggreated_id)?; + services + .oracle_price_aggregated + .by_key + .delete(&aggreated_key)?; } Ok(()) } @@ -721,12 +750,9 @@ pub fn index_interval_mapper( let err = previous_aggrigated_interval.err(); match err { Some(e) => { - let error_message = format!("Error updating oracle index interval mapper: {:?}", e); - eprintln!("{}", error_message); - return Err(Error::NotFound(NotFoundKind::Oracle)); + return Err(Error::Other(anyhow!("oracle index mapper : {}", e))); } None => { - eprintln!("Unknown index interval mapper error "); return Err(Error::NotFound(NotFoundKind::Oracle)); } } @@ -818,12 +844,9 @@ pub fn invalidate_oracle_interval( let err = previous_aggrigated_interval.err(); match err { Some(e) => { - let error_message = format!("Error updating oracle interval: {:?}", e); - eprintln!("{}", error_message); - return Err(Error::NotFound(NotFoundKind::Oracle)); + return Err(Error::Other(anyhow!("oracle invalidate interval : {}", e))); } None => { - eprintln!("Unknown previous_aggrigated_interval error "); return Err(Error::NotFound(NotFoundKind::Oracle)); } } @@ -891,10 +914,7 @@ fn forward_aggregate_number(last_value: i32, new_value: i32, count: i32) -> i32 let result = (last_value_decimal * count_decimal + new_value_decimal) / (count_decimal + Decimal::from(1)); - result.to_i32().unwrap_or_else(|| { - eprintln!("Result is too large to fit into i32, returning 0"); - i32::MAX - }) + result.to_i32().unwrap_or(i32::MAX) } fn forward_aggregate_value(last_value: &str, new_value: &str, count: i32) -> Decimal { @@ -924,10 +944,7 @@ fn backward_aggregate_number(last_value: i32, new_value: i32, count: u32) -> i32 let result = (last_value_decimal * count_decimal - new_value_decimal) / (count_decimal - Decimal::from(1)); - result.to_i32().unwrap_or_else(|| { - eprintln!("Result is too large to fit into i32, returning 0"); - 0 - }) + result.to_i32().unwrap_or(0) } fn get_previous_oracle_history_list( From a9defef2219a7846f6b19516bd2ce765d7f31684 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Thu, 18 Jul 2024 14:55:49 +0100 Subject: [PATCH 121/185] Ocean: Error handling cleanup (#2978) * Cleanup oracle * Cleanup error handling --- lib/ain-ocean/src/api/block.rs | 10 +- lib/ain-ocean/src/api/common.rs | 4 +- lib/ain-ocean/src/api/loan.rs | 36 +-- lib/ain-ocean/src/api/masternode/mod.rs | 10 +- lib/ain-ocean/src/api/pool_pair/mod.rs | 17 +- lib/ain-ocean/src/api/pool_pair/path.rs | 30 ++- lib/ain-ocean/src/api/pool_pair/service.rs | 19 +- lib/ain-ocean/src/api/prices.rs | 4 +- lib/ain-ocean/src/api/rawtx.rs | 5 +- lib/ain-ocean/src/api/stats/cache.rs | 9 +- lib/ain-ocean/src/indexer/oracle.rs | 250 +++++++++------------ 11 files changed, 176 insertions(+), 218 deletions(-) diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 7a6df07fee7..419bf896eaa 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; -use anyhow::format_err; +use anyhow::Context; use axum::{routing::get, Extension, Router}; use bitcoin::{BlockHash, Txid}; use rust_decimal::Decimal; @@ -95,9 +95,7 @@ async fn list_blocks( .next .as_ref() .map(|q| { - let height = q - .parse::() - .map_err(|_| format_err!("Invalid height"))?; + let height = q.parse::().context("Invalid height")?; Ok::(height) }) .transpose()?; @@ -142,9 +140,7 @@ async fn get_transactions( let next = query.next.as_ref().map_or( Ok(TransactionByBlockHashRepository::initial_key(hash)), |q| { - let height = q - .parse::() - .map_err(|_| format_err!("Invalid height"))?; + let height = q.parse::().context("Invalid height")?; Ok::<(BlockHash, usize), Error>((hash, height)) }, )?; diff --git a/lib/ain-ocean/src/api/common.rs b/lib/ain-ocean/src/api/common.rs index 80c604c60e7..b7636680104 100644 --- a/lib/ain-ocean/src/api/common.rs +++ b/lib/ain-ocean/src/api/common.rs @@ -1,4 +1,4 @@ -use anyhow::format_err; +use anyhow::Context; use bitcoin::{Address, Network, ScriptBuf}; use defichain_rpc::json::token::TokenInfo; use rust_decimal::Decimal; @@ -56,7 +56,7 @@ pub fn to_script(address: &str, network: Network) -> crate::Result { } pub fn address_to_hid(address: &str, network: Network) -> crate::Result { - let script = to_script(address, network).map_err(|_| format_err!("InvalidDefiAddress"))?; + let script = to_script(address, network).context("InvalidDefiAddress")?; let bytes = script.to_bytes(); Ok(as_sha256(bytes)) } diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index 4fdf1eba0d5..c97993b6787 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -1,7 +1,7 @@ use std::{str::FromStr, sync::Arc}; use ain_macros::ocean_endpoint; -use anyhow::format_err; +use anyhow::{format_err, Context}; use axum::{routing::get, Extension, Router}; use bitcoin::{hashes::Hash, Txid}; use defichain_rpc::{ @@ -130,7 +130,7 @@ async fn list_collateral_token( .map(|v| async { let (id, info) = get_token_cached(&ctx, &v.token_id) .await? - .ok_or(format_err!("None is not valid"))?; + .context("None is not valid")?; Ok::(CollateralToken::from_with_id(id, v, info)) }) .collect::>(); @@ -150,7 +150,7 @@ async fn get_collateral_token( let collateral_token = ctx.client.get_collateral_token(token_id).await?; let (id, info) = get_token_cached(&ctx, &collateral_token.token_id) .await? - .ok_or(format_err!("None is not valid"))?; + .context("None is not valid")?; Ok(Response::new(CollateralToken::from_with_id( id, @@ -203,9 +203,14 @@ async fn list_loan_token( }) .map(|flatten_token| { let fixed_interval_price_id = flatten_token.fixed_interval_price_id.clone(); - let parts = fixed_interval_price_id.split('/').collect::>(); - let [token, currency] = <[&str; 2]>::try_from(parts) - .map_err(|_| format_err!("Invalid fixed interval price id structure"))?; + let mut parts = fixed_interval_price_id.split('/'); + + let token = parts + .next() + .context("Invalid fixed interval price id structure")?; + let currency = parts + .next() + .context("Invalid fixed interval price id structure")?; let repo = &ctx.services.oracle_price_active; let key = repo @@ -246,9 +251,13 @@ async fn get_loan_token( .next() .map(|(id, info)| { let fixed_interval_price_id = loan_token_result.fixed_interval_price_id.clone(); - let parts = fixed_interval_price_id.split('/').collect::>(); - let [token, currency] = <[&str; 2]>::try_from(parts) - .map_err(|_| format_err!("Invalid fixed interval price id structure"))?; + let mut parts = fixed_interval_price_id.split('/'); + let token = parts + .next() + .context("Invalid fixed interval price id structure")?; + let currency = parts + .next() + .context("Invalid fixed interval price id structure")?; let repo = &ctx.services.oracle_price_active; let key = repo @@ -604,10 +613,11 @@ async fn map_token_amounts( .into_iter() .map(|amount| { let amount = amount.to_owned(); - let parts = amount.split('@').collect::>(); - let [amount, token_symbol] = <[&str; 2]>::try_from(parts) - .map_err(|_| format_err!("Invalid amount structure"))?; - Ok([amount.to_string(), token_symbol.to_string()]) + let mut parts = amount.split('@'); + + let amount = parts.next().context("Invalid amount structure")?; + let token_symbol = parts.next().context("Invalid amount structure")?; + Ok::<[String; 2], Error>([amount.to_string(), token_symbol.to_string()]) }) .collect::>>()?; diff --git a/lib/ain-ocean/src/api/masternode/mod.rs b/lib/ain-ocean/src/api/masternode/mod.rs index 3c9a95020c2..9162d84e8b5 100644 --- a/lib/ain-ocean/src/api/masternode/mod.rs +++ b/lib/ain-ocean/src/api/masternode/mod.rs @@ -3,7 +3,7 @@ use std::sync::Arc; mod state; use ain_macros::ocean_endpoint; -use anyhow::format_err; +use anyhow::Context; use axum::{ extract::{Path, Query}, routing::get, @@ -100,12 +100,8 @@ async fn list_masternodes( .next .as_ref() .map(|q| { - let height = q[0..8] - .parse::() - .map_err(|_| format_err!("Invalid height"))?; - let txid = q[8..] - .parse::() - .map_err(|_| format_err!("Invalid txid"))?; + let height = q[0..8].parse::().context("Invalid height")?; + let txid = q[8..].parse::().context("Invalid txid")?; Ok::<(u32, bitcoin::Txid), Error>((height, txid)) }) diff --git a/lib/ain-ocean/src/api/pool_pair/mod.rs b/lib/ain-ocean/src/api/pool_pair/mod.rs index 529507fb6ce..e06dc0bb886 100644 --- a/lib/ain-ocean/src/api/pool_pair/mod.rs +++ b/lib/ain-ocean/src/api/pool_pair/mod.rs @@ -4,7 +4,7 @@ use std::{ }; use ain_macros::ocean_endpoint; -use anyhow::format_err; +use anyhow::Context; use axum::{routing::get, Extension, Router}; use defichain_rpc::{ json::{ @@ -211,9 +211,10 @@ impl PoolPairResponse { apr: PoolPairAprResponse, volume: PoolPairVolumeResponse, ) -> Result { - let parts = p.symbol.split('-').collect::>(); - let [a, b] = <[&str; 2]>::try_from(parts) - .map_err(|_| format_err!("Invalid pool pair symbol structure"))?; + let mut parts = p.symbol.split('-'); + let a = parts.next().context("Missing symbol a")?; + let b = parts.next().context("Missing symbol b")?; + let a_parsed = parse_dat_symbol(a); let b_parsed = parse_dat_symbol(b); @@ -302,7 +303,7 @@ async fn list_pool_pairs( }, ) = get_token_cached(&ctx, &p.id_token_a) .await? - .ok_or(format_err!("None is not valid"))?; + .context("None is not valid")?; let ( _, TokenInfo { @@ -310,7 +311,7 @@ async fn list_pool_pairs( }, ) = get_token_cached(&ctx, &p.id_token_b) .await? - .ok_or(format_err!("None is not valid"))?; + .context("None is not valid")?; let total_liquidity_usd = get_total_liquidity_usd(&ctx, &p).await?; let apr = get_apr(&ctx, &id, &p).await?; @@ -351,7 +352,7 @@ async fn get_pool_pair( }, ) = get_token_cached(&ctx, &pool.id_token_a) .await? - .ok_or(format_err!("None is not valid"))?; + .context("None is not valid")?; let ( _, TokenInfo { @@ -359,7 +360,7 @@ async fn get_pool_pair( }, ) = get_token_cached(&ctx, &pool.id_token_b) .await? - .ok_or(format_err!("None is not valid"))?; + .context("None is not valid")?; let res = PoolPairResponse::from_with_id( id, pool, diff --git a/lib/ain-ocean/src/api/pool_pair/path.rs b/lib/ain-ocean/src/api/pool_pair/path.rs index 12b0015b504..57d010190ef 100644 --- a/lib/ain-ocean/src/api/pool_pair/path.rs +++ b/lib/ain-ocean/src/api/pool_pair/path.rs @@ -1,6 +1,6 @@ use std::{collections::HashSet, str::FromStr, sync::Arc, time::Duration}; -use anyhow::format_err; +use anyhow::{format_err, Context}; use defichain_rpc::json::poolpair::PoolPairInfo; use rust_decimal::{prelude::FromPrimitive, Decimal}; use rust_decimal_macros::dec; @@ -431,14 +431,11 @@ pub async fn compute_return_less_dex_fees_in_destination_token( }; } else { pool.token_a.id.clone_into(&mut from_token_id); - price_ratio = - Decimal::from_str(pool.price_ratio.ab.as_str()).map_err(|e| format_err!(e))?; + price_ratio = Decimal::from_str(pool.price_ratio.ab.as_str())?; (from_token_fee_pct, to_token_fee_pct) = if let Some(estimated_dex_fees_in_pct) = &pool.estimated_dex_fees_in_pct { - let ab = Decimal::from_str(estimated_dex_fees_in_pct.ab.as_str()) - .map_err(|e| format_err!(e))?; - let ba = Decimal::from_str(estimated_dex_fees_in_pct.ba.as_str()) - .map_err(|e| format_err!(e))?; + let ab = Decimal::from_str(estimated_dex_fees_in_pct.ab.as_str())?; + let ba = Decimal::from_str(estimated_dex_fees_in_pct.ba.as_str())?; (Some(ab), Some(ba)) } else { (None, None) @@ -447,41 +444,40 @@ pub async fn compute_return_less_dex_fees_in_destination_token( estimated_return = estimated_return .checked_mul(price_ratio) - .ok_or_else(|| format_err!("estimated_return overflow"))?; + .context("estimated_return overflow")?; // less commission fee - let commission_fee_in_pct = - Decimal::from_str(pool.commission_fee_in_pct.as_str()).map_err(|e| format_err!(e))?; + let commission_fee_in_pct = Decimal::from_str(pool.commission_fee_in_pct.as_str())?; let commission_fee = estimated_return_less_dex_fees .checked_mul(commission_fee_in_pct) - .ok_or_else(|| format_err!("commission_fee overflow"))?; + .context("commission_fee overflow")?; estimated_return_less_dex_fees = estimated_return_less_dex_fees .checked_sub(commission_fee) - .ok_or_else(|| format_err!("estimated_return_less_dex_fees underflow"))?; + .context("estimated_return_less_dex_fees underflow")?; // less dex fee from_token let from_token_estimated_dex_fee = from_token_fee_pct .unwrap_or_default() .checked_mul(estimated_return_less_dex_fees) - .ok_or_else(|| format_err!("from_token_fee_pct overflow"))?; + .context("from_token_fee_pct overflow")?; estimated_return_less_dex_fees = estimated_return_less_dex_fees .checked_sub(from_token_estimated_dex_fee) - .ok_or_else(|| format_err!("estimated_return_less_dex_fees underflow"))?; + .context("estimated_return_less_dex_fees underflow")?; // convert to to_token let from_token_estimated_return_less_dex_fee = estimated_return_less_dex_fees .checked_mul(price_ratio) - .ok_or_else(|| format_err!("from_token_estimated_return_less_dex_fee overflow"))?; + .context("from_token_estimated_return_less_dex_fee overflow")?; let to_token_estimated_dex_fee = to_token_fee_pct .unwrap_or_default() .checked_mul(from_token_estimated_return_less_dex_fee) - .ok_or_else(|| format_err!("to_token_estimated_dex_fee overflow"))?; + .context("to_token_estimated_dex_fee overflow")?; // less dex fee to_token estimated_return_less_dex_fees = from_token_estimated_return_less_dex_fee .checked_sub(to_token_estimated_dex_fee) - .ok_or_else(|| format_err!("estimated_return_less_dex_fees underflow"))?; + .context("estimated_return_less_dex_fees underflow")?; } Ok(EstimatedLessDexFeeInfo { diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index 78142d93baf..14707a36e67 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -148,9 +148,9 @@ async fn get_total_liquidity_usd_by_best_path( } pub async fn get_total_liquidity_usd(ctx: &Arc, p: &PoolPairInfo) -> Result { - let parts = p.symbol.split('-').collect::>(); - let [a, b] = <[&str; 2]>::try_from(parts) - .map_err(|_| format_err!("Invalid pool pair symbol structure"))?; + let mut parts = p.symbol.split('-'); + let a = parts.next().context("Missing symbol a")?; + let b = parts.next().context("Missing symbol b")?; let reserve_a = Decimal::from_f64(p.reserve_a).unwrap_or_default(); let reserve_b = Decimal::from_f64(p.reserve_b).unwrap_or_default(); @@ -194,11 +194,9 @@ pub async fn get_total_liquidity_usd(ctx: &Arc, p: &PoolPairInfo) -> fn calculate_rewards(accounts: &[String], dfi_price_usdt: Decimal) -> Result { let rewards = accounts.iter().try_fold(dec!(0), |accumulate, account| { - let parts = account.split('@').collect::>(); - let [amount, token] = parts - .as_slice() - .try_into() - .context("Invalid amount structure")?; + let mut parts = account.split('@'); + let amount = parts.next().context("Invalid amount structure")?; + let token = parts.next().context("Invalid amount structure")?; if token != "0" && token != "DFI" { return Ok(accumulate); @@ -492,9 +490,8 @@ async fn get_token_usd_value(ctx: &Arc, token_id: &str) -> Result>(); - let [a, _] = <[&str; 2]>::try_from(parts) - .map_err(|_| format_err!("Invalid pool pair symbol structure"))?; + let mut parts = p.symbol.split('-'); + let a = parts.next().context("Invalid pool pair symbol structure")?; let reserve_a = Decimal::from_f64(p.reserve_a).ok_or(Error::DecimalConversionError)?; let reserve_b = Decimal::from_f64(p.reserve_b).ok_or(Error::DecimalConversionError)?; if a == "DUSD" { diff --git a/lib/ain-ocean/src/api/prices.rs b/lib/ain-ocean/src/api/prices.rs index f5d96ef2266..4b87a81e02a 100644 --- a/lib/ain-ocean/src/api/prices.rs +++ b/lib/ain-ocean/src/api/prices.rs @@ -1,7 +1,7 @@ use std::{str::FromStr, sync::Arc}; use ain_macros::ocean_endpoint; -use anyhow::anyhow; +use anyhow::{anyhow, Context}; use axum::{ extract::{Path, Query}, routing::get, @@ -60,7 +60,7 @@ async fn list_prices( .price_ticker .by_id .get(&id)? - .ok_or("Missing price ticker index")?; + .context("Missing price ticker index")?; let original_amount = price_ticker.price.aggregated.amount; let amount_decimal = Decimal::from_str(&original_amount).unwrap_or_default(); diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index f178b16c740..bd535046b82 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -138,10 +138,7 @@ async fn get_raw_tx( .client .get_raw_transaction_info(&tx_hash, None) .await - .map_err(|e| { - eprintln!("Failed to get raw transaction hex: {:?}", e); - Error::RpcError(e) - })?; + .map_err(Error::RpcError)?; let result = RawTransactionResult { in_active_chain: tx_info.in_active_chain, hex: tx_info.hex, diff --git a/lib/ain-ocean/src/api/stats/cache.rs b/lib/ain-ocean/src/api/stats/cache.rs index 4bd3df8edab..8854a977dfa 100644 --- a/lib/ain-ocean/src/api/stats/cache.rs +++ b/lib/ain-ocean/src/api/stats/cache.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, str::FromStr, sync::Arc}; -use anyhow::format_err; +use anyhow::Context; use cached::proc_macro::cached; use defichain_rpc::{ defichain_rpc_json::token::TokenPagination, json::account::AccountAmount, AccountRPC, Client, @@ -133,9 +133,10 @@ pub async fn get_burned_total(ctx: &AppContext) -> Result { let fee = Decimal::from_f64(burn_info.feeburn).ok_or(Error::DecimalConversionError)?; let account_balance = if let AccountAmount::List(accounts) = accounts { for account in accounts { - let parts = account.split('@').collect::>(); - let [amount, token_id] = <[&str; 2]>::try_from(parts) - .map_err(|_| format_err!("Invalid account structure"))?; + let mut parts = account.split('@'); + + let amount = parts.next().context("Missing amount")?; + let token_id = parts.next().context("Missing token_id")?; if token_id == "DFI" { return Ok(Decimal::from_str(amount).unwrap_or_default()); diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index 22943e28379..5d0fa2ece45 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -1,8 +1,9 @@ use std::{str::FromStr, sync::Arc, vec}; use ain_dftx::{common::CompactVec, oracles::*}; -use anyhow::anyhow; +use anyhow::{anyhow, Context as _}; use bitcoin::Txid; +use log::debug; use rust_decimal::{ prelude::{FromPrimitive, ToPrimitive, Zero}, Decimal, @@ -151,22 +152,11 @@ impl Index for RemoveOracle { price_feed_item.currency.to_owned(), oracle_history.block.height, ); - match services.oracle_token_currency.by_id.delete(&deletion_id) { - Ok(_) => { - // Successfully deleted - } - Err(err) => { - return Err(Error::DBError(ain_db::DBError::Custom(err.into()))); - } - } - match services.oracle_token_currency.by_key.delete(&deletion_key) { - Ok(_) => { - // Successfully deleted - } - Err(err) => { - return Err(Error::DBError(ain_db::DBError::Custom(err.into()))); - } - } + services.oracle_token_currency.by_id.delete(&deletion_id)?; + services + .oracle_token_currency + .by_key + .delete(&deletion_key)?; } } } @@ -179,51 +169,46 @@ impl Index for RemoveOracle { fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { let oracle_id = context.tx.txid; let previous_oracle_history_result = get_previous_oracle_history_list(services, oracle_id); - match previous_oracle_history_result { - Ok(previous_oracle_history) => { - for previous_oracle in previous_oracle_history { - let oracle = Oracle { - id: previous_oracle.oracle_id, - owner_address: previous_oracle.owner_address, - weightage: previous_oracle.weightage, - price_feeds: previous_oracle.price_feeds.clone(), - block: previous_oracle.block, - }; - services.oracle.by_id.put(&oracle.id, &oracle)?; - - for prev_token_currency in previous_oracle.price_feeds { - let oracle_token_currency = OracleTokenCurrency { - id: ( - prev_token_currency.token.clone(), - prev_token_currency.currency.clone(), - oracle.id, - ), - key: ( - prev_token_currency.token.clone(), - prev_token_currency.currency.clone(), - context.block.height, - ), - token: prev_token_currency.token, - currency: prev_token_currency.currency.to_owned(), - oracle_id, - weightage: oracle.weightage, - block: oracle.block.clone(), - }; + let previous_oracle_history = previous_oracle_history_result?; + + for previous_oracle in previous_oracle_history { + let oracle = Oracle { + id: previous_oracle.oracle_id, + owner_address: previous_oracle.owner_address, + weightage: previous_oracle.weightage, + price_feeds: previous_oracle.price_feeds.clone(), + block: previous_oracle.block, + }; + services.oracle.by_id.put(&oracle.id, &oracle)?; + + for prev_token_currency in previous_oracle.price_feeds { + let oracle_token_currency = OracleTokenCurrency { + id: ( + prev_token_currency.token.clone(), + prev_token_currency.currency.clone(), + oracle.id, + ), + key: ( + prev_token_currency.token.clone(), + prev_token_currency.currency.clone(), + context.block.height, + ), + token: prev_token_currency.token, + currency: prev_token_currency.currency.to_owned(), + oracle_id, + weightage: oracle.weightage, + block: oracle.block.clone(), + }; - services - .oracle_token_currency - .by_id - .put(&oracle_token_currency.id, &oracle_token_currency)?; + services + .oracle_token_currency + .by_id + .put(&oracle_token_currency.id, &oracle_token_currency)?; - services - .oracle_token_currency - .by_key - .put(&oracle_token_currency.key, &oracle_token_currency.id)?; - } - } - } - Err(err) => { - return Err(Error::from(err)); + services + .oracle_token_currency + .by_key + .put(&oracle_token_currency.key, &oracle_token_currency.id)?; } } @@ -254,41 +239,25 @@ impl Index for UpdateOracle { //save oracle services.oracle.by_id.put(&oracle.id, &oracle)?; let previous_oracle_history_result = get_previous_oracle_history_list(services, oracle_id); - match previous_oracle_history_result { - Ok(previous_oracle) => { - for oracle in previous_oracle { - for price_feed_item in &oracle.price_feeds { - let deletion_id = ( - price_feed_item.token.clone(), - price_feed_item.currency.clone(), - oracle_id, - ); - match services.oracle_token_currency.by_id.delete(&deletion_id) { - Ok(_) => { - // Successfully deleted - } - Err(err) => { - return Err(Error::DBError(ain_db::DBError::Custom(err.into()))); - } - } - let deletion_key = ( - price_feed_item.token.clone(), - price_feed_item.currency.clone(), - ctx.block.height, - ); - match services.oracle_token_currency.by_key.delete(&deletion_key) { - Ok(_) => { - // Successfully deleted - } - Err(err) => { - return Err(Error::DBError(ain_db::DBError::Custom(err.into()))); - } - } - } - } - } - Err(err) => { - return Err(Error::Other(anyhow!("update oracle : {}", err))); + let previous_oracle = previous_oracle_history_result?; + + for oracle in previous_oracle { + for price_feed_item in &oracle.price_feeds { + let deletion_id = ( + price_feed_item.token.clone(), + price_feed_item.currency.clone(), + oracle_id, + ); + services.oracle_token_currency.by_id.delete(&deletion_id)?; + let deletion_key = ( + price_feed_item.token.clone(), + price_feed_item.currency.clone(), + ctx.block.height, + ); + services + .oracle_token_currency + .by_key + .delete(&deletion_key)?; } } @@ -366,50 +335,45 @@ impl Index for UpdateOracle { ))?; } let previous_oracle_history_result = get_previous_oracle_history_list(services, oracle_id); - match previous_oracle_history_result { - Ok(previous_oracle_result) => { - for previous_oracle in previous_oracle_result { - let oracle = Oracle { - id: previous_oracle.oracle_id, - owner_address: previous_oracle.owner_address, - weightage: previous_oracle.weightage, - price_feeds: previous_oracle.price_feeds.clone(), - block: previous_oracle.block.clone(), - }; - services.oracle.by_id.put(&oracle.id, &oracle)?; - for prev_token_currency in &previous_oracle.price_feeds { - let oracle_token_currency = OracleTokenCurrency { - id: ( - prev_token_currency.token.clone(), - prev_token_currency.currency.clone(), - oracle.id, - ), - key: ( - prev_token_currency.token.clone(), - prev_token_currency.currency.clone(), - context.block.height, - ), - token: prev_token_currency.token.clone(), - currency: prev_token_currency.currency.to_owned(), - oracle_id, - weightage: oracle.weightage, - block: oracle.block.clone(), - }; + let previous_oracle_result = previous_oracle_history_result?; + + for previous_oracle in previous_oracle_result { + let oracle = Oracle { + id: previous_oracle.oracle_id, + owner_address: previous_oracle.owner_address, + weightage: previous_oracle.weightage, + price_feeds: previous_oracle.price_feeds.clone(), + block: previous_oracle.block.clone(), + }; + services.oracle.by_id.put(&oracle.id, &oracle)?; + for prev_token_currency in &previous_oracle.price_feeds { + let oracle_token_currency = OracleTokenCurrency { + id: ( + prev_token_currency.token.clone(), + prev_token_currency.currency.clone(), + oracle.id, + ), + key: ( + prev_token_currency.token.clone(), + prev_token_currency.currency.clone(), + context.block.height, + ), + token: prev_token_currency.token.clone(), + currency: prev_token_currency.currency.to_owned(), + oracle_id, + weightage: oracle.weightage, + block: oracle.block.clone(), + }; - services - .oracle_token_currency - .by_id - .put(&oracle_token_currency.id, &oracle_token_currency)?; + services + .oracle_token_currency + .by_id + .put(&oracle_token_currency.id, &oracle_token_currency)?; - services - .oracle_token_currency - .by_key - .put(&oracle_token_currency.key, &oracle_token_currency.id)?; - } - } - } - Err(err) => { - return Err(Error::Other(anyhow!("update oracle invalidate : {}", err))); + services + .oracle_token_currency + .by_key + .put(&oracle_token_currency.key, &oracle_token_currency.id)?; } } Ok(()) @@ -474,7 +438,7 @@ impl Index for SetOracleData { for oracle in oracle_entries { if oracle.weightage == 0 { - println!("Skipping oracle with zero weightage: {:?}", oracle); + debug!("Skipping oracle with zero weightage: {:?}", oracle); continue; } @@ -703,7 +667,7 @@ pub fn index_interval_mapper( .oracle_price_aggregated_interval .by_id .get(&id)? - .ok_or("Missing oracle price aggregated interval index")?; + .context("Missing oracle price aggregated interval index")?; Ok(price_agrregated_interval) }) .collect::>>(); @@ -783,7 +747,7 @@ pub fn invalidate_oracle_interval( .oracle_price_aggregated_interval .by_id .get(&id)? - .ok_or("Missing oracle price aggregated interval index")?; + .context("Missing oracle price aggregated interval index")?; Ok(price_agrregated_interval) }) .collect::>>(); @@ -950,7 +914,7 @@ fn backward_aggregate_number(last_value: i32, new_value: i32, count: u32) -> i32 fn get_previous_oracle_history_list( services: &Arc, oracle_id: Txid, -) -> std::result::Result, Box> { +) -> Result> { let history = services .oracle_history .by_key @@ -961,10 +925,10 @@ fn get_previous_oracle_history_list( .oracle_history .by_id .get(&id)? - .ok_or("Missing oracle previous history index")?; + .context("Missing oracle previous history index")?; Ok(b) }) - .collect::, Box>>()?; + .collect::>>()?; Ok(history) } From cad2fa403e50bdd1e50f98ea2a797e0fa1b76381 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Thu, 18 Jul 2024 22:35:02 +0800 Subject: [PATCH 122/185] Ocean: fix decimal division by zero (#2977) * fallible division by zero * fmt --- lib/ain-ocean/src/api/oracle.rs | 10 ++-- lib/ain-ocean/src/api/prices.rs | 19 ++++---- lib/ain-ocean/src/api/stats/cache.rs | 4 +- lib/ain-ocean/src/api/stats/mod.rs | 3 +- lib/ain-ocean/src/indexer/oracle.rs | 70 ++++++++++++++++------------ 5 files changed, 60 insertions(+), 46 deletions(-) diff --git a/lib/ain-ocean/src/api/oracle.rs b/lib/ain-ocean/src/api/oracle.rs index a275cd26801..a20ba32d791 100644 --- a/lib/ain-ocean/src/api/oracle.rs +++ b/lib/ain-ocean/src/api/oracle.rs @@ -8,7 +8,8 @@ use axum::{ Extension, Router, }; use bitcoin::Txid; -use rust_decimal::{prelude::FromPrimitive, Decimal}; +use rust_decimal::Decimal; +use rust_decimal_macros::dec; use super::{ common::split_key, @@ -76,9 +77,10 @@ async fn get_feed( for (_, feed) in &price_feed_list { let (token, currency, oracle_id, _) = &feed.id; if key.0.eq(token) && key.1.eq(currency) && key.2.eq(oracle_id) { - let amount_decimal = Decimal::from_i64(feed.amount).unwrap_or_default(); - let conversion_factor = Decimal::from_i32(100000000).unwrap_or_default(); - let amount = amount_decimal / conversion_factor; + let amount_decimal = Decimal::new(feed.amount, 0); + let amount = amount_decimal + .checked_div(dec!(100_000_000)) + .ok_or_else(|| Error::UnderflowError)?; oracle_price_feeds.push(ApiResponseOraclePriceFeed { id: format!("{}-{}-{}-{}", token, currency, feed.oracle_id, feed.txid), key: format!("{}-{}-{}", token, currency, feed.oracle_id), diff --git a/lib/ain-ocean/src/api/prices.rs b/lib/ain-ocean/src/api/prices.rs index 4b87a81e02a..f05fdd4bc44 100644 --- a/lib/ain-ocean/src/api/prices.rs +++ b/lib/ain-ocean/src/api/prices.rs @@ -8,7 +8,8 @@ use axum::{ Extension, Router, }; use indexmap::IndexSet; -use rust_decimal::{prelude::FromPrimitive, Decimal}; +use rust_decimal::Decimal; +use rust_decimal_macros::dec; use super::{ common::split_key, @@ -62,10 +63,10 @@ async fn list_prices( .get(&id)? .context("Missing price ticker index")?; - let original_amount = price_ticker.price.aggregated.amount; - let amount_decimal = Decimal::from_str(&original_amount).unwrap_or_default(); - let conversion_factor = Decimal::from_i32(100000000).unwrap_or_default(); - let amount = amount_decimal / conversion_factor; + let amount_decimal = Decimal::from_str(&price_ticker.price.aggregated.amount)?; + let amount = amount_decimal + .checked_div(dec!(100_000_000)) + .ok_or_else(|| Error::UnderflowError)?; Ok(PriceTickerApi { id: format!("{}-{}", price_ticker.id.0, price_ticker.id.1), sort: price_ticker.sort, @@ -107,10 +108,10 @@ async fn get_price( if price_ticker.price.token.eq(&price_ticker_id.0) && price_ticker.price.currency.eq(&price_ticker_id.1) { - let original_amount = price_ticker.price.aggregated.amount; - let amount_decimal = Decimal::from_str(&original_amount).unwrap_or_default(); - let conversion_factor = Decimal::from_i32(100000000).unwrap_or_default(); - let amount = amount_decimal / conversion_factor; + let amount_decimal = Decimal::from_str(&price_ticker.price.aggregated.amount)?; + let amount = amount_decimal + .checked_div(dec!(100_000_000)) + .ok_or_else(|| Error::UnderflowError)?; let ticker = PriceTickerApi { id: format!("{}-{}", price_ticker.id.0, price_ticker.id.1), sort: price_ticker.sort, diff --git a/lib/ain-ocean/src/api/stats/cache.rs b/lib/ain-ocean/src/api/stats/cache.rs index 8854a977dfa..a10d51a0130 100644 --- a/lib/ain-ocean/src/api/stats/cache.rs +++ b/lib/ain-ocean/src/api/stats/cache.rs @@ -175,7 +175,9 @@ pub fn get_emission(height: u32) -> Result { let dex = distribution.liquidity; let community = distribution.community; let anchor = distribution.anchor; - let total = subsidy / COIN; + let total = subsidy + .checked_div(COIN) + .ok_or_else(|| Error::UnderflowError)?; let burned = total - (masternode + dex + community + anchor); Ok(Emission { diff --git a/lib/ain-ocean/src/api/stats/mod.rs b/lib/ain-ocean/src/api/stats/mod.rs index e646a22eade..2b60583d42c 100644 --- a/lib/ain-ocean/src/api/stats/mod.rs +++ b/lib/ain-ocean/src/api/stats/mod.rs @@ -163,7 +163,8 @@ async fn get_supply(Extension(ctx): Extension>) -> Result().unwrap()); + let result = total + .checked_div(Decimal::from(weightage)) + .ok_or_else(|| Error::UnderflowError)?; + let amount = format!("{:.8}", result); let aggregated_value = Some(OraclePriceAggregated { id: ( token.to_string(), @@ -708,7 +710,7 @@ pub fn index_interval_mapper( &oracle_price_aggregated_interval.id, )?; } else { - process_inner_values(services, &previous_oracle_price_aggreated[0], aggregated); + process_inner_values(services, &previous_oracle_price_aggreated[0], aggregated)? } } else { let err = previous_aggrigated_interval.err(); @@ -772,25 +774,25 @@ pub fn invalidate_oracle_interval( lastprice.amount.as_str(), &aggregated.aggregated.amount.to_string(), count as u32, - ) + )? .to_string(), weightage: backward_aggregate_number( lastprice.weightage, aggregated.aggregated.weightage, count as u32, - ), + )?, count, oracles: OraclePriceAggregatedIntervalAggregatedOracles { active: backward_aggregate_number( lastprice.oracles.active, aggregated.aggregated.oracles.active, lastprice.count as u32, - ), + )?, total: backward_aggregate_number( lastprice.oracles.total, aggregated.aggregated.oracles.total, lastprice.count as u32, - ), + )?, }, }, block: oracle_price_aggreated[0].block.clone(), @@ -822,7 +824,7 @@ fn process_inner_values( services: &Arc, previous_data: &OraclePriceAggregatedInterval, aggregated: &OraclePriceAggregated, -) { +) -> Result<()> { let lastprice = previous_data.aggregated.clone(); let count = lastprice.count + 1; @@ -837,25 +839,25 @@ fn process_inner_values( lastprice.amount.as_str(), aggregated.aggregated.amount.as_str(), count, - ) + )? .to_string(), weightage: forward_aggregate_number( lastprice.weightage, aggregated.aggregated.weightage, count, - ), + )?, count, oracles: OraclePriceAggregatedIntervalAggregatedOracles { active: forward_aggregate_number( lastprice.oracles.active, aggregated.aggregated.oracles.active, lastprice.count, - ), + )?, total: forward_aggregate_number( lastprice.oracles.total, aggregated.aggregated.oracles.total, lastprice.count, - ), + )?, }, }, block: previous_data.block.clone(), @@ -868,47 +870,53 @@ fn process_inner_values( .oracle_price_aggregated_interval .by_key .put(&aggregated_interval.key, &aggregated_interval.id); + + Ok(()) } -fn forward_aggregate_number(last_value: i32, new_value: i32, count: i32) -> i32 { +fn forward_aggregate_number(last_value: i32, new_value: i32, count: i32) -> Result { let count_decimal = Decimal::from(count); let last_value_decimal = Decimal::from(last_value); let new_value_decimal = Decimal::from(new_value); let result = (last_value_decimal * count_decimal + new_value_decimal) - / (count_decimal + Decimal::from(1)); + .checked_div(count_decimal + Decimal::from(1)) + .ok_or_else(|| Error::UnderflowError)?; - result.to_i32().unwrap_or(i32::MAX) + Ok(result.to_i32().unwrap_or(i32::MAX)) } -fn forward_aggregate_value(last_value: &str, new_value: &str, count: i32) -> Decimal { - let last_decimal = Decimal::from_str(last_value).unwrap(); - let new_decimal = Decimal::from_str(new_value).unwrap(); +fn forward_aggregate_value(last_value: &str, new_value: &str, count: i32) -> Result { + let last_decimal = Decimal::from_str(last_value)?; + let new_decimal = Decimal::from_str(new_value)?; let count_decimal = Decimal::from(count); let result = last_decimal * count_decimal + new_decimal; - result / (count_decimal + Decimal::from(1)) + result + .checked_div(count_decimal + Decimal::from(1)) + .ok_or_else(|| Error::UnderflowError) } -fn backward_aggregate_value(last_value: &str, new_value: &str, count: u32) -> Decimal { - let last_value_decimal = Decimal::from_str(last_value).unwrap_or_else(|_| Decimal::zero()); - let new_value_decimal = Decimal::from_str(new_value).unwrap_or_else(|_| Decimal::zero()); +fn backward_aggregate_value(last_value: &str, new_value: &str, count: u32) -> Result { + let last_value_decimal = Decimal::from_str(last_value)?; + let new_value_decimal = Decimal::from_str(new_value)?; let count_decimal = Decimal::from(count); - (last_value_decimal * count_decimal - new_value_decimal) / (count_decimal - Decimal::from(1)) + (last_value_decimal * count_decimal - new_value_decimal) + .checked_div(count_decimal - Decimal::from(1)) + .ok_or_else(|| Error::UnderflowError) } -fn backward_aggregate_number(last_value: i32, new_value: i32, count: u32) -> i32 { - let last_value_decimal = - Decimal::from_str(&last_value.to_string()).unwrap_or_else(|_| Decimal::zero()); - let new_value_decimal = - Decimal::from_str(&new_value.to_string()).unwrap_or_else(|_| Decimal::zero()); +fn backward_aggregate_number(last_value: i32, new_value: i32, count: u32) -> Result { + let last_value_decimal = Decimal::from(last_value); + let new_value_decimal = Decimal::from(new_value); let count_decimal = Decimal::from(count); let result = (last_value_decimal * count_decimal - new_value_decimal) - / (count_decimal - Decimal::from(1)); + .checked_div(count_decimal - Decimal::from(1)) + .ok_or_else(|| Error::UnderflowError)?; - result.to_i32().unwrap_or(0) + Ok(result.to_i32().unwrap_or(0)) } fn get_previous_oracle_history_list( From 8249b2fe57fa3c3c0d71492246bde426428d5e70 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Fri, 19 Jul 2024 09:23:01 +0100 Subject: [PATCH 123/185] Remove unwrap (#2979) --- lib/ain-ocean/src/api/address.rs | 14 +++--- lib/ain-ocean/src/api/loan.rs | 20 ++++----- lib/ain-ocean/src/api/masternode/mod.rs | 2 +- lib/ain-ocean/src/api/pool_pair/path.rs | 8 ++-- lib/ain-ocean/src/api/pool_pair/service.rs | 43 +++++++------------ lib/ain-ocean/src/api/stats/cache.rs | 4 +- lib/ain-ocean/src/indexer/loan_token.rs | 21 ++++----- lib/ain-ocean/src/indexer/mod.rs | 32 ++++++-------- lib/ain-ocean/src/indexer/oracle.rs | 29 +++++++------ .../src/storage/columns/price_ticker.rs | 13 +++++- 10 files changed, 84 insertions(+), 102 deletions(-) diff --git a/lib/ain-ocean/src/api/address.rs b/lib/ain-ocean/src/api/address.rs index b461755d5b9..24bc4b82aeb 100644 --- a/lib/ain-ocean/src/api/address.rs +++ b/lib/ain-ocean/src/api/address.rs @@ -187,11 +187,10 @@ async fn get_balance( Extension(ctx): Extension>, ) -> Result> { let hid = address_to_hid(&address, ctx.network.into())?; - let aggregation = get_latest_aggregation(&ctx, hid)?; - if aggregation.is_none() { + let Some(aggregation) = get_latest_aggregation(&ctx, hid)? else { return Ok(Response::new("0.00000000".to_string())); - } - let aggregation = aggregation.unwrap(); + }; + Ok(Response::new(aggregation.amount.unspent)) } @@ -487,11 +486,10 @@ async fn list_tokens( let mut vec = Vec::new(); for (k, v) in account { - let token = get_token_cached(&ctx, &k).await?; - if token.is_none() { + let Some((id, info)) = get_token_cached(&ctx, &k).await? else { continue; - } - let (id, info) = token.unwrap(); + }; + let address_token = AddressToken { id, amount: format!("{:.8}", v), diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index c97993b6787..8bf2a1af0b3 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -244,7 +244,7 @@ async fn get_loan_token( Extension(ctx): Extension>, ) -> Result> { let loan_token_result = ctx.client.get_loan_token(token_id.clone()).await?; - let token = loan_token_result + let Some(token) = loan_token_result .token .0 .into_iter() @@ -277,13 +277,12 @@ async fn get_loan_token( active_price, }) }) - .transpose()?; - - if token.is_none() { + .transpose()? + else { return Err(format_err!("Token {:?} does not exist!", token_id).into()); - } + }; - Ok(Response::new(token.unwrap())) + Ok(Response::new(token)) } pub async fn get_all_vaults( @@ -495,7 +494,7 @@ async fn list_vault_auction_history( .auction .by_id .get(&id)? - .ok_or("Missing auction index")?; + .context("Missing auction index")?; Ok(auction) }) @@ -623,13 +622,12 @@ async fn map_token_amounts( let mut vault_token_amounts = Vec::new(); for [amount, token_symbol] in amount_token_symbols { - let token = get_token_cached(ctx, &token_symbol).await?; - if token.is_none() { + let Some((id, token_info)) = get_token_cached(ctx, &token_symbol).await? else { log::error!("Token {token_symbol} not found"); continue; - } + }; let repo = &ctx.services.oracle_price_active; - let (id, token_info) = token.unwrap(); + let keys = repo .by_key .list(None, SortOrder::Descending)? diff --git a/lib/ain-ocean/src/api/masternode/mod.rs b/lib/ain-ocean/src/api/masternode/mod.rs index 9162d84e8b5..4716fe28277 100644 --- a/lib/ain-ocean/src/api/masternode/mod.rs +++ b/lib/ain-ocean/src/api/masternode/mod.rs @@ -119,7 +119,7 @@ async fn list_masternodes( .paginate(&query) .map(|el| repository.retrieve_primary_value(el)) .map(|v| { - let mn = v.unwrap(); + let mn = v?; let state = MasternodeService::new(ctx.network).get_masternode_state(&mn, height); Ok(MasternodeData::from_with_state(mn, state)) }) diff --git a/lib/ain-ocean/src/api/pool_pair/path.rs b/lib/ain-ocean/src/api/pool_pair/path.rs index 57d010190ef..3bbdb8727b7 100644 --- a/lib/ain-ocean/src/api/pool_pair/path.rs +++ b/lib/ain-ocean/src/api/pool_pair/path.rs @@ -361,12 +361,10 @@ pub async fn compute_paths_between_tokens( })? .to_string(); - let pool = get_pool_pair_cached(ctx, pool_pair_id.clone()).await?; - if pool.is_none() { + let Some((_, pool_pair_info)) = get_pool_pair_cached(ctx, pool_pair_id.clone()).await? + else { return Err(format_err!("Pool pair by id {pool_pair_id} not found").into()); - } - - let (_, pool_pair_info) = pool.unwrap(); + }; let estimated_dex_fees_in_pct = get_dex_fees_pct(pool_pair_info.clone(), from_token_id, to_token_id); diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index 14707a36e67..e54922fba34 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -107,13 +107,10 @@ async fn get_total_liquidity_usd_by_best_path( ctx: &Arc, p: &PoolPairInfo, ) -> Result { - let usdt = get_token_cached(ctx, "USDT").await?; - if usdt.is_none() { + let Some((usdt_id, _)) = get_token_cached(ctx, "USDT").await? else { return Ok(dec!(0)); }; - let (usdt_id, _) = usdt.unwrap(); - let mut a_token_rate = dec!(1); let mut b_token_rate = dec!(1); @@ -587,11 +584,9 @@ fn call_dftx(ctx: &Arc, txid: Txid) -> Result> { } fn find_composite_swap_dftx(ctx: &Arc, txid: Txid) -> Result> { - let dftx = call_dftx(ctx, txid)?; - if dftx.is_none() { + let Some(dftx) = call_dftx(ctx, txid)? else { return Ok(None); - } - let dftx = dftx.unwrap(); + }; let composite_swap_dftx = match dftx { DfTx::CompositeSwap(data) => Some(data), @@ -618,11 +613,9 @@ pub async fn find_swap_from( } = swap; let from_address = from_script(from, ctx.network.into())?; - let from_token = get_token_cached(ctx, &from_token_id.to_string()).await?; - if from_token.is_none() { + let Some((_, from_token)) = get_token_cached(ctx, &from_token_id.to_string()).await? else { return Ok(None); - } - let (_, from_token) = from_token.unwrap(); + }; Ok(Some(PoolSwapFromToData { address: from_address, @@ -648,11 +641,9 @@ pub async fn find_swap_to( let to_address = from_script(to, ctx.network.into())?; - let to_token = get_token_cached(ctx, &to_token_id.to_string()).await?; - if to_token.is_none() { + let Some((_, to_token)) = get_token_cached(ctx, &to_token_id.to_string()).await? else { return Ok(None); - } - let (_, to_token) = to_token.unwrap(); + }; let display_symbol = parse_display_symbol(&to_token); @@ -701,11 +692,11 @@ async fn get_pool_swap_type( ctx: &Arc, swap: crate::model::PoolSwap, ) -> Result> { - let pool_pair = get_pool_pair_cached(ctx, swap.pool_id.to_string()).await?; - if pool_pair.is_none() { + let Some((_, pool_pair_info)) = get_pool_pair_cached(ctx, swap.pool_id.to_string()).await? + else { return Ok(None); - } - let (_, pool_pair_info) = pool_pair.unwrap(); + }; + let id_token_a = pool_pair_info.id_token_a.parse::()?; let swap_type = if id_token_a == swap.from_token_id { SwapType::SELL @@ -719,11 +710,9 @@ pub async fn check_swap_type( ctx: &Arc, swap: crate::model::PoolSwap, ) -> Result> { - let dftx = find_composite_swap_dftx(ctx, swap.txid)?; - if dftx.is_none() { + let Some(dftx) = find_composite_swap_dftx(ctx, swap.txid)? else { return get_pool_swap_type(ctx, swap).await; - } - let dftx = dftx.unwrap(); + }; if dftx.pools.iter().count() <= 1 { return get_pool_swap_type(ctx, swap).await; @@ -732,11 +721,9 @@ pub async fn check_swap_type( let mut prev = swap.from_token_id.to_string(); for pool in dftx.pools.iter() { let pool_id = pool.id.0.to_string(); - let pool_pair = get_pool_pair_cached(ctx, pool_id.clone()).await?; - if pool_pair.is_none() { + let Some((_, pool_pair_info)) = get_pool_pair_cached(ctx, pool_id.clone()).await? else { break; - } - let (_, pool_pair_info) = pool_pair.unwrap(); + }; // if this is current pool pair, if previous token is primary token, indicator = sell if pool_id == swap.pool_id.to_string() { diff --git a/lib/ain-ocean/src/api/stats/cache.rs b/lib/ain-ocean/src/api/stats/cache.rs index a10d51a0130..c855e51f152 100644 --- a/lib/ain-ocean/src/api/stats/cache.rs +++ b/lib/ain-ocean/src/api/stats/cache.rs @@ -120,7 +120,9 @@ lazy_static::lazy_static! { convert = r#"{ format!("burned_total") }"# )] pub async fn get_burned_total(ctx: &AppContext) -> Result { - let burn_address = BURN_ADDRESS.get(ctx.network.as_str()).unwrap(); + let burn_address = BURN_ADDRESS + .get(ctx.network.as_str()) + .context("Missing burn address")?; let accounts = ctx .client .get_account(burn_address, None, Some(true)) diff --git a/lib/ain-ocean/src/indexer/loan_token.rs b/lib/ain-ocean/src/indexer/loan_token.rs index 262ac91a8ee..6da704056fa 100644 --- a/lib/ain-ocean/src/indexer/loan_token.rs +++ b/lib/ain-ocean/src/indexer/loan_token.rs @@ -56,25 +56,20 @@ fn is_aggregate_valid(aggregate: &OraclePriceAggregated, block: &BlockContext) - } fn is_live(active: Option, next: Option) -> bool { - if active.is_none() { + let Some(active) = active else { return false; - } + }; - if next.is_none() { + let Some(next) = next else { return false; - } - - let active = active.unwrap(); - let next = next.unwrap(); + }; - let active_price = match Decimal::from_str(&active.amount) { - Ok(num) => num, - Err(_) => return false, + let Ok(active_price) = Decimal::from_str(&active.amount) else { + return false; }; - let next_price = match Decimal::from_str(&next.amount) { - Ok(num) => num, - Err(_) => return false, + let Ok(next_price) = Decimal::from_str(&next.amount) else { + return false; }; if active_price <= Decimal::zero() { diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 744528dc558..d21dbbf9ae7 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -172,17 +172,14 @@ fn index_script_activity(services: &Arc, block: &Block) - } for vin in tx.vin.iter() { - let vin_standard = get_vin_standard(vin); - if vin_standard.is_none() { + let Some(vin) = get_vin_standard(vin) else { continue; - } - let vin = vin_standard.unwrap(); - let vout = find_tx_vout(services, block, &vin)?; - if vout.is_none() { + }; + + let Some(vout) = find_tx_vout(services, block, &vin)? else { log::error!("attempting to sync: {:?} but type: TransactionVout with id:{}-{} cannot be found in the index", IndexAction::Index, vin.txid, vin.vout); continue; - } - let vout = vout.unwrap(); + }; let hid = as_sha256(vout.script.hex.clone()); // as key let script_activity = ScriptActivity { @@ -324,18 +321,14 @@ fn index_script_aggregation(services: &Arc, block: &Block } for vin in tx.vin.iter() { - let vin_standard = get_vin_standard(vin); - if vin_standard.is_none() { + let Some(vin) = get_vin_standard(vin) else { continue; - } - let vin = vin_standard.unwrap(); + }; - let vout = find_tx_vout(services, block, &vin)?; - if vout.is_none() { + let Some(vout) = find_tx_vout(services, block, &vin)? else { log::error!("attempting to sync: {:?} but type: TransactionVout with id:{}-{} cannot be found in the index", IndexAction::Index, vin.txid, vin.vout); continue; - } - let vout = vout.unwrap(); + }; // SPENT (REMOVE) let mut aggregation = @@ -408,11 +401,10 @@ fn index_script_unspent(services: &Arc, block: &Block) -> } for vin in tx.vin.iter() { - let vin_standard = get_vin_standard(vin); - if vin_standard.is_none() { + let Some(vin) = get_vin_standard(vin) else { continue; - } - let vin = vin_standard.unwrap(); + }; + let key = (block.height, vin.txid, vin.vout); let id = services.script_unspent.by_key.get(&key)?; if let Some(id) = id { diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index 8406c16fe37..d8f83f78f33 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -471,9 +471,11 @@ impl Index for SetOracleData { } } } + let result = total .checked_div(Decimal::from(weightage)) .ok_or_else(|| Error::UnderflowError)?; + let amount = format!("{:.8}", result); let aggregated_value = Some(OraclePriceAggregated { id: ( @@ -541,18 +543,19 @@ impl Index for SetOracleData { .put(&price_ticker.id, &price_ticker)?; //SetOracleInterval - let aggregated = services.oracle_price_aggregated.by_id.get(&( - token.to_owned(), - currency.to_owned(), - context.block.height, - ))?; + let aggregated = services + .oracle_price_aggregated + .by_id + .get(&(token.to_owned(), currency.to_owned(), context.block.height))? + .context("Missing aggregate value")?; + for interval in intervals.clone() { index_interval_mapper( services, &context.block, token, currency, - aggregated.as_ref().unwrap(), + &aggregated, &interval, )?; } @@ -710,7 +713,7 @@ pub fn index_interval_mapper( &oracle_price_aggregated_interval.id, )?; } else { - process_inner_values(services, &previous_oracle_price_aggreated[0], aggregated)? + process_inner_values(services, &previous_oracle_price_aggreated[0], aggregated)?; } } else { let err = previous_aggrigated_interval.err(); @@ -862,15 +865,14 @@ fn process_inner_values( }, block: previous_data.block.clone(), }; - let _err = services + services .oracle_price_aggregated_interval .by_id - .put(&aggregated_interval.id, &aggregated_interval); - let _err = services + .put(&aggregated_interval.id, &aggregated_interval)?; + services .oracle_price_aggregated_interval .by_key - .put(&aggregated_interval.key, &aggregated_interval.id); - + .put(&aggregated_interval.key, &aggregated_interval.id)?; Ok(()) } @@ -883,7 +885,7 @@ fn forward_aggregate_number(last_value: i32, new_value: i32, count: i32) -> Resu .checked_div(count_decimal + Decimal::from(1)) .ok_or_else(|| Error::UnderflowError)?; - Ok(result.to_i32().unwrap_or(i32::MAX)) + Ok(result.to_i32().context("Error converting decimal to i32")?) } fn forward_aggregate_value(last_value: &str, new_value: &str, count: i32) -> Result { @@ -892,6 +894,7 @@ fn forward_aggregate_value(last_value: &str, new_value: &str, count: i32) -> Res let count_decimal = Decimal::from(count); let result = last_decimal * count_decimal + new_decimal; + result .checked_div(count_decimal + Decimal::from(1)) .ok_or_else(|| Error::UnderflowError) diff --git a/lib/ain-ocean/src/storage/columns/price_ticker.rs b/lib/ain-ocean/src/storage/columns/price_ticker.rs index 871a682b522..bf69e578709 100644 --- a/lib/ain-ocean/src/storage/columns/price_ticker.rs +++ b/lib/ain-ocean/src/storage/columns/price_ticker.rs @@ -38,8 +38,17 @@ impl Column for PriceTickerKey { } fn get_key(raw_key: Box<[u8]>) -> Result { - let total = i32::from_be_bytes(raw_key[0..4].try_into().unwrap()); - let height = u32::from_be_bytes(raw_key[4..8].try_into().unwrap()); + let total = i32::from_be_bytes( + raw_key[0..4] + .try_into() + .map_err(|_| DBError::WrongKeyLength)?, + ); + let height = u32::from_be_bytes( + raw_key[4..8] + .try_into() + .map_err(|_| DBError::WrongKeyLength)?, + ); + let currency_n = raw_key.len() - 3; // 3 letters of currency code let token = std::str::from_utf8(&raw_key[8..currency_n]) .map_err(|_| DBError::ParseKey)? From 2a25a87901aa8f221814b34ed972849379e2be25 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Wed, 24 Jul 2024 16:49:19 +0800 Subject: [PATCH 124/185] Ocean: `checked_div` default value as 1 (#2981) * COIN * neat dec * rm checked_div for logical conversion * checked_div default 1 if none * refine a bit * fmt_rs --- lib/ain-ocean/src/api/oracle.rs | 7 ++---- lib/ain-ocean/src/api/prices.rs | 14 +++++------- lib/ain-ocean/src/api/rawtx.rs | 9 +++----- lib/ain-ocean/src/api/stats/cache.rs | 4 +--- lib/ain-ocean/src/api/stats/distribution.rs | 2 +- lib/ain-ocean/src/api/stats/mod.rs | 7 ++---- lib/ain-ocean/src/indexer/oracle.rs | 24 ++++++++++----------- lib/ain-ocean/src/indexer/poolswap.rs | 8 +++---- 8 files changed, 29 insertions(+), 46 deletions(-) diff --git a/lib/ain-ocean/src/api/oracle.rs b/lib/ain-ocean/src/api/oracle.rs index a20ba32d791..c6b7aec2a79 100644 --- a/lib/ain-ocean/src/api/oracle.rs +++ b/lib/ain-ocean/src/api/oracle.rs @@ -1,5 +1,6 @@ use std::{str::FromStr, sync::Arc}; +use ain_dftx::COIN; use ain_macros::ocean_endpoint; use anyhow::anyhow; use axum::{ @@ -9,7 +10,6 @@ use axum::{ }; use bitcoin::Txid; use rust_decimal::Decimal; -use rust_decimal_macros::dec; use super::{ common::split_key, @@ -77,10 +77,7 @@ async fn get_feed( for (_, feed) in &price_feed_list { let (token, currency, oracle_id, _) = &feed.id; if key.0.eq(token) && key.1.eq(currency) && key.2.eq(oracle_id) { - let amount_decimal = Decimal::new(feed.amount, 0); - let amount = amount_decimal - .checked_div(dec!(100_000_000)) - .ok_or_else(|| Error::UnderflowError)?; + let amount = Decimal::from(feed.amount / COIN); oracle_price_feeds.push(ApiResponseOraclePriceFeed { id: format!("{}-{}-{}-{}", token, currency, feed.oracle_id, feed.txid), key: format!("{}-{}-{}", token, currency, feed.oracle_id), diff --git a/lib/ain-ocean/src/api/prices.rs b/lib/ain-ocean/src/api/prices.rs index f05fdd4bc44..a8a024c976c 100644 --- a/lib/ain-ocean/src/api/prices.rs +++ b/lib/ain-ocean/src/api/prices.rs @@ -1,5 +1,6 @@ use std::{str::FromStr, sync::Arc}; +use ain_dftx::COIN; use ain_macros::ocean_endpoint; use anyhow::{anyhow, Context}; use axum::{ @@ -9,7 +10,6 @@ use axum::{ }; use indexmap::IndexSet; use rust_decimal::Decimal; -use rust_decimal_macros::dec; use super::{ common::split_key, @@ -63,10 +63,8 @@ async fn list_prices( .get(&id)? .context("Missing price ticker index")?; - let amount_decimal = Decimal::from_str(&price_ticker.price.aggregated.amount)?; - let amount = amount_decimal - .checked_div(dec!(100_000_000)) - .ok_or_else(|| Error::UnderflowError)?; + let amount = + Decimal::from_str(&price_ticker.price.aggregated.amount)? / Decimal::from(COIN); Ok(PriceTickerApi { id: format!("{}-{}", price_ticker.id.0, price_ticker.id.1), sort: price_ticker.sort, @@ -108,10 +106,8 @@ async fn get_price( if price_ticker.price.token.eq(&price_ticker_id.0) && price_ticker.price.currency.eq(&price_ticker_id.1) { - let amount_decimal = Decimal::from_str(&price_ticker.price.aggregated.amount)?; - let amount = amount_decimal - .checked_div(dec!(100_000_000)) - .ok_or_else(|| Error::UnderflowError)?; + let amount = + Decimal::from_str(&price_ticker.price.aggregated.amount)? / Decimal::from(COIN); let ticker = PriceTickerApi { id: format!("{}-{}", price_ticker.id.0, price_ticker.id.1), sort: price_ticker.sort, diff --git a/lib/ain-ocean/src/api/rawtx.rs b/lib/ain-ocean/src/api/rawtx.rs index bd535046b82..a75484c23e0 100644 --- a/lib/ain-ocean/src/api/rawtx.rs +++ b/lib/ain-ocean/src/api/rawtx.rs @@ -1,6 +1,6 @@ use std::{result::Result as StdResult, str::FromStr, sync::Arc}; -use ain_dftx::{deserialize, DfTx}; +use ain_dftx::{deserialize, DfTx, COIN}; use ain_macros::ocean_endpoint; use axum::{ extract::{Json, Path}, @@ -10,7 +10,6 @@ use axum::{ use bitcoin::{Transaction, Txid}; use defichain_rpc::{PoolPairRPC, RpcApi}; use rust_decimal::prelude::ToPrimitive; -use rust_decimal_macros::dec; use serde::{Deserialize, Serialize, Serializer}; use super::{query::Query, response::Response, AppContext}; @@ -38,8 +37,7 @@ async fn send_raw_tx( validate(ctx.clone(), raw_tx_dto.hex.clone()).await?; let max_fee = match raw_tx_dto.max_fee_rate { Some(fee_rate) => { - let sat_per_bitcoin = dec!(100_000_000); - let fee_in_satoshis = fee_rate.checked_mul(sat_per_bitcoin); + let fee_in_satoshis = fee_rate.checked_mul(COIN.into()); match fee_in_satoshis { Some(value) => Some(value.to_u64().unwrap_or_default()), None => Some(default_max_fee_rate().to_sat()), @@ -71,8 +69,7 @@ async fn test_raw_tx( let trx = defichain_rpc::RawTx::raw_hex(raw_tx_dto.hex); let max_fee = match raw_tx_dto.max_fee_rate { Some(fee_rate) => { - let sat_per_bitcoin = dec!(100_000_000); - let fee_in_satoshis = fee_rate.checked_mul(sat_per_bitcoin); + let fee_in_satoshis = fee_rate.checked_mul(COIN.into()); match fee_in_satoshis { Some(value) => Some(value.to_u64().unwrap_or_default()), None => Some(default_max_fee_rate().to_sat()), diff --git a/lib/ain-ocean/src/api/stats/cache.rs b/lib/ain-ocean/src/api/stats/cache.rs index c855e51f152..c72a1f38e34 100644 --- a/lib/ain-ocean/src/api/stats/cache.rs +++ b/lib/ain-ocean/src/api/stats/cache.rs @@ -177,9 +177,7 @@ pub fn get_emission(height: u32) -> Result { let dex = distribution.liquidity; let community = distribution.community; let anchor = distribution.anchor; - let total = subsidy - .checked_div(COIN) - .ok_or_else(|| Error::UnderflowError)?; + let total = subsidy / Decimal::from(COIN); let burned = total - (masternode + dex + community + anchor); Ok(Emission { diff --git a/lib/ain-ocean/src/api/stats/distribution.rs b/lib/ain-ocean/src/api/stats/distribution.rs index 580e731b3bd..676e403a93e 100644 --- a/lib/ain-ocean/src/api/stats/distribution.rs +++ b/lib/ain-ocean/src/api/stats/distribution.rs @@ -40,5 +40,5 @@ pub fn get_block_reward_distribution(subsidy: Decimal) -> BlockRewardDistributio } fn calculate_reward(amount: Decimal, percent: Decimal) -> Decimal { - (amount * percent) / dec!(10000) / COIN + (amount * percent) / dec!(10000) / Decimal::from(COIN) } diff --git a/lib/ain-ocean/src/api/stats/mod.rs b/lib/ain-ocean/src/api/stats/mod.rs index 2b60583d42c..091b2834fac 100644 --- a/lib/ain-ocean/src/api/stats/mod.rs +++ b/lib/ain-ocean/src/api/stats/mod.rs @@ -4,6 +4,7 @@ mod subsidy; use std::sync::Arc; +use ain_dftx::COIN; use ain_macros::ocean_endpoint; use axum::{routing::get, Extension, Router}; use defichain_rpc::{ @@ -11,7 +12,6 @@ use defichain_rpc::{ AccountRPC, RpcApi, }; use rust_decimal::{prelude::FromPrimitive, Decimal}; -use rust_decimal_macros::dec; use serde::{Deserialize, Serialize}; use self::{ @@ -28,8 +28,6 @@ use crate::{ Result, }; -const COIN: Decimal = dec!(100_000_000); - #[derive(Debug, Serialize, Deserialize, Default)] pub struct StatsData { pub count: Count, @@ -163,8 +161,7 @@ async fn get_supply(Extension(ctx): Extension>) -> Result = Vec::new(); + let mut pairs = Vec::new(); for feed in &feeds { pairs.push((feed.token.clone(), feed.currency.clone(), feed.oracle_id)); services.oracle_price_feed.by_key.put(&feed.key, &feed.id)?; @@ -400,8 +401,7 @@ impl Index for SetOracleData { OracleIntervalSeconds::OneDay, ]; for (token, currency, oracle) in pairs.iter() { - let oracle_token_id: (String, String, Txid) = - (token.to_string(), currency.to_string(), *oracle); + let oracle_token_id = (token.to_string(), currency.to_string(), *oracle); let oracle_entries = services .oracle_token_currency .by_key @@ -460,8 +460,7 @@ impl Index for SetOracleData { if (oracle_price.time - context.block.time as i32) < 3600 { count += 1; weightage += oracle.weightage as i32; - let amount = oracle_price.amount; - let weighted_amount = amount * oracle.weightage as i64; + let weighted_amount = oracle_price.amount * oracle.weightage as i64; total += Decimal::from(weighted_amount); } } @@ -472,11 +471,10 @@ impl Index for SetOracleData { } } - let result = total + let amount = total .checked_div(Decimal::from(weightage)) - .ok_or_else(|| Error::UnderflowError)?; + .unwrap_or(dec!(1)); - let amount = format!("{:.8}", result); let aggregated_value = Some(OraclePriceAggregated { id: ( token.to_string(), @@ -492,7 +490,7 @@ impl Index for SetOracleData { token: token.to_string(), currency: currency.to_string(), aggregated: OraclePriceAggregatedAggregated { - amount, + amount: format!("{:.8}", amount), weightage, oracles: OraclePriceAggregatedAggregatedOracles { active: count, @@ -882,7 +880,7 @@ fn forward_aggregate_number(last_value: i32, new_value: i32, count: i32) -> Resu let new_value_decimal = Decimal::from(new_value); let result = (last_value_decimal * count_decimal + new_value_decimal) - .checked_div(count_decimal + Decimal::from(1)) + .checked_div(count_decimal + dec!(1)) .ok_or_else(|| Error::UnderflowError)?; Ok(result.to_i32().context("Error converting decimal to i32")?) @@ -896,7 +894,7 @@ fn forward_aggregate_value(last_value: &str, new_value: &str, count: i32) -> Res let result = last_decimal * count_decimal + new_decimal; result - .checked_div(count_decimal + Decimal::from(1)) + .checked_div(count_decimal + dec!(1)) .ok_or_else(|| Error::UnderflowError) } @@ -906,7 +904,7 @@ fn backward_aggregate_value(last_value: &str, new_value: &str, count: u32) -> Re let count_decimal = Decimal::from(count); (last_value_decimal * count_decimal - new_value_decimal) - .checked_div(count_decimal - Decimal::from(1)) + .checked_div(count_decimal - dec!(1)) .ok_or_else(|| Error::UnderflowError) } @@ -916,7 +914,7 @@ fn backward_aggregate_number(last_value: i32, new_value: i32, count: u32) -> Res let count_decimal = Decimal::from(count); let result = (last_value_decimal * count_decimal - new_value_decimal) - .checked_div(count_decimal - Decimal::from(1)) + .checked_div(count_decimal - dec!(1)) .ok_or_else(|| Error::UnderflowError)?; Ok(result.to_i32().unwrap_or(0)) diff --git a/lib/ain-ocean/src/indexer/poolswap.rs b/lib/ain-ocean/src/indexer/poolswap.rs index 6d380981fcd..0a6dad68aff 100644 --- a/lib/ain-ocean/src/indexer/poolswap.rs +++ b/lib/ain-ocean/src/indexer/poolswap.rs @@ -1,6 +1,6 @@ -use std::{ops::Div, str::FromStr, sync::Arc}; +use std::{str::FromStr, sync::Arc}; -use ain_dftx::pool::*; +use ain_dftx::{pool::*, COIN}; use anyhow::format_err; use bitcoin::{BlockHash, Txid}; // use bitcoin::Address; @@ -74,7 +74,7 @@ fn index_swap_aggregated( .unwrap_or(dec!(0)); let aggregated_amount = amount - .checked_add(Decimal::from(from_amount).div(dec!(100_000_000))) + .checked_add(Decimal::from(from_amount / COIN)) .ok_or(Error::OverflowError)?; aggregated.aggregated.amounts.insert( @@ -137,7 +137,7 @@ fn invalidate_swap_aggregated( .unwrap_or(dec!(0)); let aggregated_amount = amount - .checked_sub(Decimal::from(from_amount).div(dec!(100_000_000))) + .checked_sub(Decimal::from(from_amount / COIN)) .ok_or(Error::UnderflowError)?; aggregated.aggregated.amounts.insert( From 8e6811d5a0f56233720bd45967d94e64641866fe Mon Sep 17 00:00:00 2001 From: canonbrother Date: Mon, 29 Jul 2024 16:10:53 +0800 Subject: [PATCH 125/185] Ocean: set loopback + cors (#2983) * default ocean endpoint as loopback * cors * refine cors * fmt_rs * desc --- lib/ain-ocean/src/api/mod.rs | 46 +++++++++++++++++++++++++++++++++--- src/init.cpp | 2 +- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index 0b90f58e894..d56d53195f6 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -1,6 +1,12 @@ use std::{str::FromStr, sync::Arc}; -use axum::{extract::Request, http::StatusCode, response::IntoResponse, Json, Router}; +use axum::{ + extract::Request, + http::{HeaderValue, StatusCode}, + middleware::{from_fn, Next}, + response::{IntoResponse, Response}, + Json, Router, +}; mod address; mod block; @@ -55,6 +61,40 @@ pub struct AppContext { network: Network, } +// NOTE(canonbrother): manually scratch cors since CorsLayer + Axum can only be supported in `tower-http 0.5` +async fn cors(request: Request, next: Next) -> Response { + let mut response = next.run(request).await; + + response + .headers_mut() + .append("Access-Control-Allow-Origin", HeaderValue::from_static("*")); + response.headers_mut().append( + "Access-Control-Allow-Methods", + HeaderValue::from_static("GET"), + ); + response.headers_mut().append( + "Access-Control-Allow-Methods", + HeaderValue::from_static("POST"), + ); + response.headers_mut().append( + "Access-Control-Allow-Methods", + HeaderValue::from_static("PUT"), + ); + response.headers_mut().append( + "Access-Control-Allow-Methods", + HeaderValue::from_static("DELETE"), + ); + response.headers_mut().append( + "Access-Control-Allow-Headers", + HeaderValue::from_static("Content-Type"), + ); + response + .headers_mut() + .append("Access-Control-Max-Age", HeaderValue::from_static("10080")); // 60 * 24 * 7 + + response +} + pub async fn ocean_router( services: &Arc, client: Arc, @@ -65,7 +105,6 @@ pub async fn ocean_router( services: services.clone(), network: Network::from_str(&network)?, }); - println!("{:?}", context.network); let context_cloned = context.clone(); tokio::spawn(async move { pool_pair::path::sync_token_graph(&context_cloned).await }); @@ -86,6 +125,7 @@ pub async fn ocean_router( .nest("/tokens", tokens::router(Arc::clone(&context))) .nest("/transactions", transactions::router(Arc::clone(&context))) .nest("/blocks", block::router(Arc::clone(&context))) - .fallback(not_found), + .fallback(not_found) + .layer(from_fn(cors)), // NOTE(canonbrother): the `layer()` calls work in reverse order, hence cors layer must be at bottom )) } diff --git a/src/init.cpp b/src/init.cpp index e0570f215d1..4a0c3c7de7f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2386,7 +2386,7 @@ bool AppInitMain(InitInterfaces& interfaces) // for (auto it = ocean_endpoints.begin(); it != ocean_endpoints.end(); ++it) { // LogPrint(BCLog::HTTP, "Binding ocean server on endpoint %s\n", *it); auto port = gArgs.GetArg("-oceanarchiveport", DEFAULT_OCEAN_ARCHIVE_PORT); - auto res = XResultStatusLogged(ain_rs_init_network_rest_ocean(result, strprintf("127.0.0.1:%s", port))) + auto res = XResultStatusLogged(ain_rs_init_network_rest_ocean(result, strprintf("0.0.0.0:%s", port))) if (!res) { // LogPrintf("Binding websocket server on endpoint %s failed.\n", *it); return false; From 1726a74e52942fdfb3c562cad1f7ed44c7f9914d Mon Sep 17 00:00:00 2001 From: canonbrother Date: Mon, 5 Aug 2024 19:57:15 +0800 Subject: [PATCH 126/185] Ocean: revamp setoracledata indexer (#2987) * infer * revamp setoracle index * forward aggregate value * backward aggregate value * invalidate * fmt * note the changes * rm unuse -.- * revert - * div correction * revert price_ticket by_key * revert not put at oracle_price_agg by_key * fmt --- lib/ain-ocean/src/api/oracle.rs | 2 +- lib/ain-ocean/src/indexer/oracle.rs | 867 +++++++++++++------------- lib/ain-ocean/src/indexer/poolswap.rs | 4 +- 3 files changed, 433 insertions(+), 440 deletions(-) diff --git a/lib/ain-ocean/src/api/oracle.rs b/lib/ain-ocean/src/api/oracle.rs index c6b7aec2a79..0fe62f74153 100644 --- a/lib/ain-ocean/src/api/oracle.rs +++ b/lib/ain-ocean/src/api/oracle.rs @@ -77,7 +77,7 @@ async fn get_feed( for (_, feed) in &price_feed_list { let (token, currency, oracle_id, _) = &feed.id; if key.0.eq(token) && key.1.eq(currency) && key.2.eq(oracle_id) { - let amount = Decimal::from(feed.amount / COIN); + let amount = Decimal::from(feed.amount) / Decimal::from(COIN); oracle_price_feeds.push(ApiResponseOraclePriceFeed { id: format!("{}-{}-{}-{}", token, currency, feed.oracle_id, feed.txid), key: format!("{}-{}-{}", token, currency, feed.oracle_id), diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index 5442b3f2c6a..5364323134a 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -1,6 +1,6 @@ -use std::{str::FromStr, sync::Arc, vec}; +use std::{collections::HashSet, str::FromStr, sync::Arc, vec}; -use ain_dftx::{common::CompactVec, oracles::*}; +use ain_dftx::oracles::*; use anyhow::{anyhow, Context as _}; use bitcoin::Txid; use log::debug; @@ -11,7 +11,6 @@ use rust_decimal::{ use rust_decimal_macros::dec; use crate::{ - error::NotFoundKind, indexer::{Context, Index, Result}, model::{ BlockContext, Oracle, OracleHistory, OracleIntervalSeconds, OraclePriceAggregated, @@ -25,17 +24,23 @@ use crate::{ Error, Services, }; +pub const AGGREGATED_INTERVALS: [OracleIntervalSeconds; 3] = [ + OracleIntervalSeconds::FifteenMinutes, + OracleIntervalSeconds::OneDay, + OracleIntervalSeconds::OneHour, +]; + impl Index for AppointOracle { fn index(self, services: &Arc, ctx: &Context) -> Result<()> { let oracle_id = ctx.tx.txid; - let price_feeds_items: Vec = self + let price_feeds_items = self .price_feeds .iter() .map(|pair| PriceFeedsItem { token: pair.token.clone(), currency: pair.currency.clone(), }) - .collect(); + .collect::>(); let oracle = Oracle { id: oracle_id, owner_address: self.script.to_hex_string(), @@ -220,7 +225,7 @@ impl Index for RemoveOracle { impl Index for UpdateOracle { fn index(self, services: &Arc, ctx: &Context) -> Result<()> { let oracle_id = ctx.tx.txid; - let price_feeds_items: Vec = self + let price_feeds_items = self .price_feeds .iter() .map(|pair| PriceFeedsItem { @@ -381,347 +386,355 @@ impl Index for UpdateOracle { } } -impl Index for SetOracleData { - fn index(self, services: &Arc, context: &Context) -> Result<()> { - let set_oracle_data = SetOracleData { - oracle_id: self.oracle_id, - timestamp: self.timestamp, - token_prices: self.token_prices, - }; - let feeds = map_price_feeds(&set_oracle_data, context)?; - let mut pairs = Vec::new(); - for feed in &feeds { - pairs.push((feed.token.clone(), feed.currency.clone(), feed.oracle_id)); - services.oracle_price_feed.by_key.put(&feed.key, &feed.id)?; - services.oracle_price_feed.by_id.put(&feed.id, feed)?; +fn map_price_aggregated( + services: &Arc, + context: &Context, + pair: (String, String), +) -> Result> { + let (token, currency) = pair; + let oracle_repo = &services.oracle_token_currency; + let feed_repo = &services.oracle_price_feed; + + let keys_ids = oracle_repo + .by_key + .list( + Some((token.clone(), currency.clone(), u32::MAX)), + SortOrder::Descending, + )? + .take_while(|item| match item { + Ok((k, _)) => k.0 == token && k.1 == currency, + _ => true, + }) + .flatten() + .collect::>(); + + let mut oracles = Vec::new(); + for (_, id) in keys_ids { + let oracle = oracle_repo.by_id.get(&id)?; + let Some(oracle) = oracle else { continue }; + oracles.push(oracle); + } + + let mut aggregated_total = Decimal::zero(); + let mut aggregated_count = 0; + let mut aggregated_weightage = 0; + + let oracles_len = oracles.len(); + for oracle in oracles { + if oracle.weightage == 0 { + debug!("Skipping oracle with zero weightage: {:?}", oracle); + continue; } - let intervals: Vec = vec![ - OracleIntervalSeconds::FifteenMinutes, - OracleIntervalSeconds::OneHour, - OracleIntervalSeconds::OneDay, - ]; - for (token, currency, oracle) in pairs.iter() { - let oracle_token_id = (token.to_string(), currency.to_string(), *oracle); - let oracle_entries = services - .oracle_token_currency - .by_key - .list( - Some((token.clone(), currency.clone(), u32::zero())), - SortOrder::Ascending, - )? - .filter_map(|item| { - match item { - Ok((_, id)) => { - if id.0 == oracle_token_id.0.clone() - && id.1 == oracle_token_id.1.clone() - { - match services.oracle_token_currency.by_id.get(&id) { - Ok(b) => Some(Ok(b?)), - Err(e) => Some(Err(e)), - } - } else { - None - } - } - Err(e) => Some(Err(e).map_err(|e| e.into())), // Convert DBError to error::Error - } - }) - .collect::>>()?; - if oracle_entries.is_empty() { - continue; - } - let total_count = oracle_entries.len(); - let mut total = Decimal::zero(); - let mut count = 0; - let mut weightage = 0; - - for oracle in oracle_entries { - if oracle.weightage == 0 { - debug!("Skipping oracle with zero weightage: {:?}", oracle); - continue; - } + let feed_id = feed_repo + .by_key + .get(&(oracle.token, oracle.currency, oracle.oracle_id))?; - let key = ( - oracle.token.to_string(), - oracle.currency.to_string(), - oracle.oracle_id, - ); - let oracle_price_id = services.oracle_price_feed.by_key.get(&key)?; - match oracle_price_id { - Some((token, currency, oracle_id, some_other_id)) => { - let oracle_price = services.oracle_price_feed.by_id.get(&( - token, - currency, - oracle_id, - some_other_id, - ))?; - if let Some(oracle_price) = oracle_price { - if (oracle_price.time - context.block.time as i32) < 3600 { - count += 1; - weightage += oracle.weightage as i32; - let weighted_amount = oracle_price.amount * oracle.weightage as i64; - total += Decimal::from(weighted_amount); - } - } - } - None => { - continue; - } - } - } + let Some(feed_id) = feed_id else { continue }; - let amount = total - .checked_div(Decimal::from(weightage)) - .unwrap_or(dec!(1)); + let feed = feed_repo.by_id.get(&feed_id)?; - let aggregated_value = Some(OraclePriceAggregated { - id: ( - token.to_string(), - currency.to_string(), - context.block.height, - ), - key: (token.to_string(), currency.to_string()), + let Some(feed) = feed else { continue }; + + let time_diff = Decimal::from(feed.time) - Decimal::from(context.block.time); + if Decimal::abs(&time_diff) < dec!(3600) { + aggregated_count += 1; + aggregated_weightage += oracle.weightage; + log::debug!( + "SetOracleData weightage: {:?} * oracle_price.amount: {:?}", + aggregated_weightage, + feed.amount + ); + let weighted_amount = Decimal::from(feed.amount) + .checked_mul(Decimal::from(oracle.weightage)) + .context("weighted_amount overflow")?; + aggregated_total += weighted_amount; + } + } + + if aggregated_count == 0 { + return Ok(None); + } + + // NOTE(canonbrother): default by zero since it has not executed within the bucket yet + let aggregated_amount = aggregated_total + .checked_div(Decimal::from(aggregated_weightage)) + .unwrap_or_default(); + + let key = (token.clone(), currency.clone()); + Ok(Some(OraclePriceAggregated { + key: key.clone(), + id: (key.0, key.1, context.block.height), + sort: format!( + "{}{}", + hex::encode(context.block.median_time.to_be_bytes()), + hex::encode(context.block.height.to_be_bytes()) + ), + token, + currency, + aggregated: OraclePriceAggregatedAggregated { + amount: format!("{:.8}", aggregated_amount), + weightage: aggregated_weightage as i32, + oracles: OraclePriceAggregatedAggregatedOracles { + active: aggregated_count, + total: oracles_len as i32, + }, + }, + block: context.block.clone(), + })) +} + +fn index_set_oracle_data( + services: &Arc, + context: &Context, + pairs: HashSet<(String, String)>, +) -> Result<()> { + let oracle_repo = &services.oracle_price_aggregated; + let ticker_repo = &services.price_ticker; + + for pair in pairs.into_iter() { + let price_aggregated = map_price_aggregated(services, context, pair)?; + + let Some(price_aggregated) = price_aggregated else { + continue; + }; + + let key = ( + price_aggregated.token.clone(), + price_aggregated.currency.clone(), + ); + let id = (key.0.clone(), key.1.clone(), price_aggregated.block.height); + // oracle_repo.by_key.put(&key, &id)?; + oracle_repo.by_id.put(&id, &price_aggregated)?; + + let id = ( + price_aggregated.token.clone(), + price_aggregated.currency.clone(), + ); + let key = ( + price_aggregated.aggregated.oracles.total, + price_aggregated.block.height, + price_aggregated.token.clone(), + price_aggregated.currency.clone(), + ); + ticker_repo.by_key.put(&key, &id)?; + ticker_repo.by_id.put( + &id.clone(), + &PriceTicker { sort: format!( - "{}{}", - hex::encode(context.block.median_time.to_be_bytes()), - hex::encode(context.block.height.to_be_bytes()) + "{}{}{}-{}", + hex::encode(price_aggregated.aggregated.oracles.total.to_be_bytes()), + hex::encode(price_aggregated.block.height.to_be_bytes()), + id.0.clone(), + id.1.clone(), ), - token: token.to_string(), - currency: currency.to_string(), - aggregated: OraclePriceAggregatedAggregated { - amount: format!("{:.8}", amount), - weightage, - oracles: OraclePriceAggregatedAggregatedOracles { - active: count, - total: total_count as i32, - }, - }, - block: context.block.clone(), - }); - - if let Some(value) = aggregated_value { - let aggreated_id = ( - value.token.clone(), - value.currency.clone(), - value.block.height, - ); - let price_ticker_id = (value.token.clone(), value.currency.clone()); - let price_ticker_key = ( - value.aggregated.oracles.total, - value.block.height, - value.token.clone(), - value.currency.clone(), - ); + id, + price: price_aggregated, + }, + )?; + } + Ok(()) +} - services - .oracle_price_aggregated - .by_id - .put(&aggreated_id, &value)?; - - let price_ticker = PriceTicker { - id: price_ticker_id, - sort: format!( - "{}{}{}-{}", - hex::encode(value.aggregated.oracles.total.to_be_bytes()), - hex::encode(value.block.height.to_be_bytes()), - value.token.clone(), - value.currency.clone(), - ), - price: value, - }; +fn index_set_oracle_data_interval( + services: &Arc, + context: &Context, + pairs: HashSet<(String, String)>, +) -> Result<()> { + for (token, currency) in pairs.into_iter() { + let aggregated = services.oracle_price_aggregated.by_id.get(&( + token.clone(), + currency.clone(), + context.block.height, + ))?; - services - .price_ticker - .by_key - .put(&price_ticker_key, &price_ticker.id)?; - services - .price_ticker - .by_id - .put(&price_ticker.id, &price_ticker)?; + let Some(aggregated) = aggregated else { + continue; + }; - //SetOracleInterval - let aggregated = services - .oracle_price_aggregated - .by_id - .get(&(token.to_owned(), currency.to_owned(), context.block.height))? - .context("Missing aggregate value")?; - - for interval in intervals.clone() { - index_interval_mapper( - services, - &context.block, - token, - currency, - &aggregated, - &interval, - )?; - } - } + for interval in AGGREGATED_INTERVALS { + index_interval_mapper( + services, + &context.block, + token.clone(), + currency.clone(), + &aggregated, + interval, + )?; + } + } + + Ok(()) +} + +impl Index for SetOracleData { + fn index(self, services: &Arc, context: &Context) -> Result<()> { + let feed_repo = &services.oracle_price_feed; + + let mut pairs = HashSet::new(); + let feeds = map_price_feeds(&self, context); + for feed in &feeds { + pairs.insert((feed.token.clone(), feed.currency.clone())); + feed_repo.by_key.put(&feed.key, &feed.id)?; + feed_repo.by_id.put(&feed.id, feed)?; } + index_set_oracle_data(services, context, pairs.clone())?; + + index_set_oracle_data_interval(services, context, pairs)?; + Ok(()) } fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { - let set_oracle_data = SetOracleData { - oracle_id: self.oracle_id, - timestamp: self.timestamp, - token_prices: CompactVec::from(Vec::new()), - }; - let intervals: Vec = vec![ - OracleIntervalSeconds::FifteenMinutes, - OracleIntervalSeconds::OneHour, - OracleIntervalSeconds::OneDay, - ]; - let feeds = map_price_feeds(&set_oracle_data, context)?; - let mut pairs: Vec<(String, String)> = Vec::new(); + let oracle_repo = &services.oracle_price_aggregated; + let feed_repo = &services.oracle_price_feed; + + let mut pairs = HashSet::new(); + let feeds = map_price_feeds(self, context); for feed in feeds { - pairs.push((feed.token.clone(), feed.currency.clone())); - services.oracle_price_feed.by_id.delete(&feed.id)?; - services.oracle_price_feed.by_key.delete(&feed.key)?; + pairs.insert((feed.token.clone(), feed.currency.clone())); + feed_repo.by_id.delete(&feed.id)?; + feed_repo.by_key.delete(&feed.key)?; } for (token, currency) in pairs.iter() { - let aggreated_id = (token.to_owned(), currency.to_owned(), context.block.height); - let aggreated_key = (token.to_owned(), currency.to_owned()); - let aggregated_price = services.oracle_price_aggregated.by_id.get(&aggreated_id)?; - if let Some(aggregated) = aggregated_price { - for interval in &intervals { - let _err = invalidate_oracle_interval( - services, - &context.block, - token, - currency, - &aggregated, - interval, - ); - } + let key = (token.clone(), currency.clone()); + let id = (key.0.clone(), key.1.clone(), context.block.height); + + let aggregated = services.oracle_price_aggregated.by_id.get(&id)?; + + let Some(aggregated) = aggregated else { + continue; + }; + + for interval in AGGREGATED_INTERVALS { + invalidate_oracle_interval( + services, + &context.block, + token, + currency, + &aggregated, + &interval, + )? } - services - .oracle_price_aggregated - .by_id - .delete(&aggreated_id)?; - services - .oracle_price_aggregated - .by_key - .delete(&aggreated_key)?; + + // invalidate_set_oracle_data + oracle_repo.by_id.delete(&id)?; + oracle_repo.by_key.delete(&key)?; } Ok(()) } } -fn map_price_feeds( - set_oracle_data: &SetOracleData, - context: &Context, -) -> Result> { - let mut result: Vec = Vec::new(); - let token_prices = set_oracle_data.token_prices.as_ref(); +fn map_price_feeds(data: &SetOracleData, ctx: &Context) -> Vec { + let mut feeds = Vec::new(); + let token_prices = data.token_prices.as_ref(); for token_price in token_prices { for token_amount in token_price.prices.as_ref() { let token = token_price.token.clone(); let currency = token_amount.currency.clone(); - let id = ( - token.clone(), - currency.clone(), - set_oracle_data.oracle_id, - context.tx.txid, - ); - - let key = (token.clone(), currency.clone(), set_oracle_data.oracle_id); + let key = (token.clone(), currency.clone(), data.oracle_id); let oracle_price_feed = OraclePriceFeed { - id: id.clone(), - key, - sort: hex::encode(context.block.height.to_string() + &context.tx.txid.to_string()), + key: key.clone(), + id: (key.0, key.1, key.2, ctx.tx.txid), + sort: hex::encode(ctx.block.height.to_string() + &ctx.tx.txid.to_string()), amount: token_amount.amount, - currency: currency.clone(), - block: context.block.clone(), - oracle_id: set_oracle_data.oracle_id, - time: set_oracle_data.timestamp as i32, + currency, + block: ctx.block.clone(), + oracle_id: data.oracle_id, + time: data.timestamp as i32, token, - txid: context.tx.txid, + txid: ctx.tx.txid, }; - result.push(oracle_price_feed); + feeds.push(oracle_price_feed); } } - Ok(result) + feeds +} + +fn start_new_bucket( + services: &Arc, + block: &BlockContext, + token: String, + currency: String, + aggregated: &OraclePriceAggregated, + interval: OracleIntervalSeconds, +) -> Result<()> { + let key = (token.clone(), currency.clone(), interval); + let id = (key.0.clone(), key.1.clone(), key.2.clone(), block.height); + let repo = &services.oracle_price_aggregated_interval; + repo.by_id.put( + &id, + &OraclePriceAggregatedInterval { + id: id.clone(), + key: key.clone(), + sort: aggregated.sort.clone(), + token, + currency, + aggregated: OraclePriceAggregatedIntervalAggregated { + amount: aggregated.aggregated.amount.clone(), + weightage: aggregated.aggregated.weightage, + count: 1, + oracles: OraclePriceAggregatedIntervalAggregatedOracles { + active: aggregated.aggregated.oracles.active, + total: aggregated.aggregated.oracles.total, + }, + }, + block: block.clone(), + }, + )?; + repo.by_key.put(&key, &id)?; + + Ok(()) } pub fn index_interval_mapper( services: &Arc, block: &BlockContext, - token: &str, - currency: &str, + token: String, + currency: String, aggregated: &OraclePriceAggregated, - interval: &OracleIntervalSeconds, + interval: OracleIntervalSeconds, ) -> Result<()> { - let previous_aggrigated_interval = services - .oracle_price_aggregated_interval + let repo = &services.oracle_price_aggregated_interval; + let previous = repo .by_key .list( - Some((token.to_owned(), currency.to_owned(), interval.clone())), - SortOrder::Ascending, + Some((token.clone(), currency.clone(), interval.clone())), + SortOrder::Descending, )? .take(1) - .map(|item| { - let (_, id) = item?; - let price_agrregated_interval = services - .oracle_price_aggregated_interval - .by_id - .get(&id)? - .context("Missing oracle price aggregated interval index")?; - Ok(price_agrregated_interval) - }) - .collect::>>(); - - if let Ok(previous_oracle_price_aggreated) = previous_aggrigated_interval { - if previous_oracle_price_aggreated.is_empty() - || (block.median_time - previous_oracle_price_aggreated[0].block.median_time - > interval.clone() as i64) - { - let oracle_price_aggregated_interval = OraclePriceAggregatedInterval { - id: ( - token.to_owned(), - currency.to_owned(), - interval.clone(), - block.height, - ), - key: (token.to_owned(), currency.to_owned(), interval.clone()), - sort: aggregated.sort.to_owned(), - token: token.to_owned(), - currency: currency.to_owned(), - aggregated: OraclePriceAggregatedIntervalAggregated { - amount: aggregated.aggregated.amount.clone(), - weightage: aggregated.aggregated.weightage, - count: 1, - oracles: OraclePriceAggregatedIntervalAggregatedOracles { - active: aggregated.aggregated.oracles.active, - total: aggregated.aggregated.oracles.total, - }, - }, - block: block.clone(), - }; - services.oracle_price_aggregated_interval.by_id.put( - &oracle_price_aggregated_interval.id, - &oracle_price_aggregated_interval, - )?; - services.oracle_price_aggregated_interval.by_key.put( - &oracle_price_aggregated_interval.key, - &oracle_price_aggregated_interval.id, - )?; - } else { - process_inner_values(services, &previous_oracle_price_aggreated[0], aggregated)?; - } - } else { - let err = previous_aggrigated_interval.err(); - match err { - Some(e) => { - return Err(Error::Other(anyhow!("oracle index mapper : {}", e))); - } - None => { - return Err(Error::NotFound(NotFoundKind::Oracle)); + .flatten() + .collect::>(); + + if previous.is_empty() { + return start_new_bucket( + services, + block, + token.clone(), + currency.clone(), + aggregated, + interval, + ); + } + + for (_, id) in previous { + let aggregated_interval = repo.by_id.get(&id)?; + if let Some(aggregated_interval) = aggregated_interval { + if block.median_time - aggregated.block.median_time > interval.clone() as i64 { + return start_new_bucket( + services, + block, + token.clone(), + currency.clone(), + aggregated, + interval, + ); } + + forward_aggregate(services, &aggregated_interval, aggregated)?; } } @@ -736,132 +749,138 @@ pub fn invalidate_oracle_interval( aggregated: &OraclePriceAggregated, interval: &OracleIntervalSeconds, ) -> Result<()> { - let previous_aggrigated_interval = services - .oracle_price_aggregated_interval + let repo = &services.oracle_price_aggregated_interval; + let previous = repo .by_key .list( - Some((token.to_owned(), currency.to_owned(), interval.clone())), + Some((token.to_string(), currency.to_string(), interval.clone())), SortOrder::Descending, )? .take(1) .map(|item| { let (_, id) = item?; - let price_agrregated_interval = services + let price = services .oracle_price_aggregated_interval .by_id .get(&id)? .context("Missing oracle price aggregated interval index")?; - Ok(price_agrregated_interval) + Ok(price) }) - .collect::>>(); + .collect::>>()?; - if let Ok(oracle_price_aggreated) = previous_aggrigated_interval { - if oracle_price_aggreated[0].aggregated.count != 1 { - let _err = services - .oracle_price_aggregated_interval - .by_id - .delete(&oracle_price_aggreated[0].id); - } else { - let lastprice = oracle_price_aggreated[0].aggregated.clone(); - let count = lastprice.count - 1; - let previous_aggregated_interval = OraclePriceAggregatedInterval { - id: oracle_price_aggreated[0].id.clone(), - key: oracle_price_aggreated[0].key.clone(), - sort: oracle_price_aggreated[0].sort.clone(), - token: oracle_price_aggreated[0].token.clone(), - currency: oracle_price_aggreated[0].currency.clone(), - aggregated: OraclePriceAggregatedIntervalAggregated { - amount: backward_aggregate_value( - lastprice.amount.as_str(), - &aggregated.aggregated.amount.to_string(), - count as u32, - )? - .to_string(), - weightage: backward_aggregate_number( - lastprice.weightage, - aggregated.aggregated.weightage, - count as u32, - )?, - count, - oracles: OraclePriceAggregatedIntervalAggregatedOracles { - active: backward_aggregate_number( - lastprice.oracles.active, - aggregated.aggregated.oracles.active, - lastprice.count as u32, - )?, - total: backward_aggregate_number( - lastprice.oracles.total, - aggregated.aggregated.oracles.total, - lastprice.count as u32, - )?, - }, - }, - block: oracle_price_aggreated[0].block.clone(), - }; - let _err = services.oracle_price_aggregated_interval.by_id.put( - &previous_aggregated_interval.id, - &previous_aggregated_interval, - ); - let _err = services.oracle_price_aggregated_interval.by_key.put( - &previous_aggregated_interval.key, - &previous_aggregated_interval.id, - ); - } - } else { - let err = previous_aggrigated_interval.err(); - match err { - Some(e) => { - return Err(Error::Other(anyhow!("oracle invalidate interval : {}", e))); - } - None => { - return Err(Error::NotFound(NotFoundKind::Oracle)); - } - } + let previous = &previous[0]; + + if previous.aggregated.count == 1 { + return repo.by_id.delete(&previous.id); } + + let last_price = previous.aggregated.clone(); + let count = last_price.count - 1; + + let aggregated_amount = backward_aggregate_value( + Decimal::from_str(&last_price.amount)?, + Decimal::from_str(&aggregated.aggregated.amount)?, + Decimal::from(count), + )?; + + let aggregated_weightage = backward_aggregate_value( + Decimal::from(last_price.weightage), + Decimal::from(aggregated.aggregated.weightage), + Decimal::from(count), + )?; + + let aggregated_active = backward_aggregate_value( + Decimal::from(last_price.oracles.active), + Decimal::from(aggregated.aggregated.oracles.active), + Decimal::from(last_price.count), + )?; + + let aggregated_total = backward_aggregate_value( + Decimal::from(last_price.oracles.total), + Decimal::from(aggregated.aggregated.oracles.total), + Decimal::from(last_price.count), + )?; + + let aggregated_interval = OraclePriceAggregatedInterval { + id: previous.id.clone(), + key: previous.key.clone(), + sort: previous.sort.clone(), + token: previous.token.clone(), + currency: previous.currency.clone(), + aggregated: OraclePriceAggregatedIntervalAggregated { + amount: aggregated_amount.to_string(), + weightage: aggregated_weightage + .to_i32() + .context("Err: Decimal.to_i32()")?, + count, + oracles: OraclePriceAggregatedIntervalAggregatedOracles { + active: aggregated_active + .to_i32() + .context("Err: Decimal.to_i32()")?, + total: aggregated_total.to_i32().context("Err: Decimal.to_i32()")?, + }, + }, + block: previous.block.clone(), + }; + repo.by_id + .put(&aggregated_interval.id, &aggregated_interval)?; + repo.by_key + .put(&aggregated_interval.key, &aggregated_interval.id)?; Ok(()) } -fn process_inner_values( +fn forward_aggregate( services: &Arc, - previous_data: &OraclePriceAggregatedInterval, + previous: &OraclePriceAggregatedInterval, aggregated: &OraclePriceAggregated, ) -> Result<()> { - let lastprice = previous_data.aggregated.clone(); - let count = lastprice.count + 1; + let last_price = previous.aggregated.clone(); + let count = last_price.count + 1; + + let aggregated_amount = forward_aggregate_value( + Decimal::from_str(&last_price.amount)?, + Decimal::from_str(&aggregated.aggregated.amount)?, + Decimal::from(count), + )?; + + let aggregated_weightage = forward_aggregate_value( + Decimal::from(last_price.weightage), + Decimal::from(aggregated.aggregated.weightage), + Decimal::from(count), + )?; + + let aggregated_active = forward_aggregate_value( + Decimal::from(last_price.oracles.active), + Decimal::from(aggregated.aggregated.oracles.active), + Decimal::from(last_price.count), + )?; + + let aggregated_total = forward_aggregate_value( + Decimal::from(last_price.oracles.total), + Decimal::from(aggregated.aggregated.oracles.total), + Decimal::from(last_price.count), + )?; let aggregated_interval = OraclePriceAggregatedInterval { - id: previous_data.id.clone(), - key: previous_data.key.clone(), - sort: previous_data.sort.clone(), - token: previous_data.token.clone(), - currency: previous_data.currency.clone(), + id: previous.id.clone(), + key: previous.key.clone(), + sort: previous.sort.clone(), + token: previous.token.clone(), + currency: previous.currency.clone(), aggregated: OraclePriceAggregatedIntervalAggregated { - amount: forward_aggregate_value( - lastprice.amount.as_str(), - aggregated.aggregated.amount.as_str(), - count, - )? - .to_string(), - weightage: forward_aggregate_number( - lastprice.weightage, - aggregated.aggregated.weightage, - count, - )?, + amount: aggregated_amount.to_string(), + weightage: aggregated_weightage + .to_i32() + .context("Err: Decimal.to_i32()")?, count, oracles: OraclePriceAggregatedIntervalAggregatedOracles { - active: forward_aggregate_number( - lastprice.oracles.active, - aggregated.aggregated.oracles.active, - lastprice.count, - )?, - total: forward_aggregate_number( - lastprice.oracles.total, - aggregated.aggregated.oracles.total, - lastprice.count, - )?, + active: aggregated_active + .to_i32() + .context("Err: Decimal.to_i32()")?, + total: aggregated_total.to_i32().context("Err: Decimal.to_i32()")?, }, }, - block: previous_data.block.clone(), + block: previous.block.clone(), }; services .oracle_price_aggregated_interval @@ -874,52 +893,26 @@ fn process_inner_values( Ok(()) } -fn forward_aggregate_number(last_value: i32, new_value: i32, count: i32) -> Result { - let count_decimal = Decimal::from(count); - let last_value_decimal = Decimal::from(last_value); - let new_value_decimal = Decimal::from(new_value); - - let result = (last_value_decimal * count_decimal + new_value_decimal) - .checked_div(count_decimal + dec!(1)) - .ok_or_else(|| Error::UnderflowError)?; - - Ok(result.to_i32().context("Error converting decimal to i32")?) -} - -fn forward_aggregate_value(last_value: &str, new_value: &str, count: i32) -> Result { - let last_decimal = Decimal::from_str(last_value)?; - let new_decimal = Decimal::from_str(new_value)?; - let count_decimal = Decimal::from(count); - - let result = last_decimal * count_decimal + new_decimal; - - result - .checked_div(count_decimal + dec!(1)) +fn forward_aggregate_value( + last_value: Decimal, + new_value: Decimal, + count: Decimal, +) -> Result { + (last_value * count + new_value) + .checked_div(count + dec!(1)) .ok_or_else(|| Error::UnderflowError) } -fn backward_aggregate_value(last_value: &str, new_value: &str, count: u32) -> Result { - let last_value_decimal = Decimal::from_str(last_value)?; - let new_value_decimal = Decimal::from_str(new_value)?; - let count_decimal = Decimal::from(count); - - (last_value_decimal * count_decimal - new_value_decimal) - .checked_div(count_decimal - dec!(1)) +fn backward_aggregate_value( + last_value: Decimal, + new_value: Decimal, + count: Decimal, +) -> Result { + (last_value * count - new_value) + .checked_div(count - dec!(1)) .ok_or_else(|| Error::UnderflowError) } -fn backward_aggregate_number(last_value: i32, new_value: i32, count: u32) -> Result { - let last_value_decimal = Decimal::from(last_value); - let new_value_decimal = Decimal::from(new_value); - let count_decimal = Decimal::from(count); - - let result = (last_value_decimal * count_decimal - new_value_decimal) - .checked_div(count_decimal - dec!(1)) - .ok_or_else(|| Error::UnderflowError)?; - - Ok(result.to_i32().unwrap_or(0)) -} - fn get_previous_oracle_history_list( services: &Arc, oracle_id: Txid, diff --git a/lib/ain-ocean/src/indexer/poolswap.rs b/lib/ain-ocean/src/indexer/poolswap.rs index 0a6dad68aff..e2007458096 100644 --- a/lib/ain-ocean/src/indexer/poolswap.rs +++ b/lib/ain-ocean/src/indexer/poolswap.rs @@ -74,7 +74,7 @@ fn index_swap_aggregated( .unwrap_or(dec!(0)); let aggregated_amount = amount - .checked_add(Decimal::from(from_amount / COIN)) + .checked_add(Decimal::from(from_amount) / Decimal::from(COIN)) .ok_or(Error::OverflowError)?; aggregated.aggregated.amounts.insert( @@ -137,7 +137,7 @@ fn invalidate_swap_aggregated( .unwrap_or(dec!(0)); let aggregated_amount = amount - .checked_sub(Decimal::from(from_amount / COIN)) + .checked_sub(Decimal::from(from_amount) / Decimal::from(COIN)) .ok_or(Error::UnderflowError)?; aggregated.aggregated.amounts.insert( From 6f0a9b1f574da68d861741ffcaa1f196ed647011 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Thu, 8 Aug 2024 17:10:00 +0800 Subject: [PATCH 127/185] Ocean: fix todo on get_stats (#2989) * fix:todo get_stats * get_count: add blocks and prices * get_mn: tvl * usd * fmt * fmt --- lib/ain-ocean/src/api/pool_pair/service.rs | 2 +- lib/ain-ocean/src/api/stats/cache.rs | 103 +++++++++++++-------- lib/ain-ocean/src/api/stats/mod.rs | 16 +--- 3 files changed, 70 insertions(+), 51 deletions(-) diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index e54922fba34..6bdcd3fe110 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -52,7 +52,7 @@ pub struct PoolSwapFromTo { pub to: Option, } -async fn get_usd_per_dfi(ctx: &Arc) -> Result { +pub async fn get_usd_per_dfi(ctx: &Arc) -> Result { let usdt = get_pool_pair_cached(ctx, "USDT-DFI".to_string()).await?; let usdc = get_pool_pair_cached(ctx, "USDC-DFI".to_string()).await?; diff --git a/lib/ain-ocean/src/api/stats/cache.rs b/lib/ain-ocean/src/api/stats/cache.rs index c72a1f38e34..71d8d15543d 100644 --- a/lib/ain-ocean/src/api/stats/cache.rs +++ b/lib/ain-ocean/src/api/stats/cache.rs @@ -15,9 +15,17 @@ use serde::{Deserialize, Serialize}; use super::{subsidy::BLOCK_SUBSIDY, COIN}; use crate::{ - api::{common::find_token_balance, stats::get_block_reward_distribution, AppContext}, + api::{ + cache::list_pool_pairs_cached, + common::find_token_balance, + pool_pair::service::{get_total_liquidity_usd, get_usd_per_dfi}, + stats::get_block_reward_distribution, + AppContext, + }, model::MasternodeStatsData, - Error, Result, Services, + repository::RepositoryOps, + storage::SortOrder, + Error, Result, }; #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -64,7 +72,7 @@ pub async fn get_burned(client: &Client) -> Result { pub struct Count { pub blocks: u32, pub tokens: usize, - pub prices: u64, + pub prices: usize, pub masternodes: u32, } @@ -93,12 +101,18 @@ pub async fn get_count(ctx: &Arc) -> Result { .get_latest()? .map_or(0, |mn| mn.stats.count); + let prices = ctx + .services + .price_ticker + .by_id + .list(None, SortOrder::Descending)? + .collect::>(); + Ok(Count { + blocks: 0, tokens: tokens.0.len(), masternodes, - // TODO handle prices - // prices: - ..Default::default() + prices: prices.len(), }) } @@ -253,21 +267,23 @@ pub struct Masternodes { key = "String", convert = r#"{ format!("masternodes") }"# )] -pub fn get_masternodes(services: &Services) -> Result { - let stats = services +pub async fn get_masternodes(ctx: &Arc) -> Result { + let stats = ctx + .services .masternode .stats .get_latest()? .map_or(MasternodeStatsData::default(), |mn| mn.stats); - // TODO Tvl * DUSD value + let usd = get_usd_per_dfi(ctx).await?; + Ok(Masternodes { locked: stats .locked .into_iter() .map(|(k, v)| Locked { weeks: k, - tvl: v.tvl, + tvl: v.tvl * usd, count: v.count, }) .collect(), @@ -278,7 +294,7 @@ pub fn get_masternodes(services: &Services) -> Result { pub struct Tvl { pub total: Decimal, pub dex: Decimal, - pub loan: f64, + pub loan: Decimal, pub masternodes: Decimal, } @@ -289,40 +305,51 @@ pub struct Tvl { convert = r#"{ format!("tvl") }"# )] pub async fn get_tvl(ctx: &Arc) -> Result { - // let mut dex = 0f64; - // let pairs = ctx - // .client - // .list_pool_pairs( - - // including_start: true, - // start: 0, - // limit: 1000, - // }), - // Some(true), - // ) - // .await; - - let loan = get_loan(&ctx.client).await?; - - // TODO value in DUSD - let masternodes = ctx + // dex + let mut dex = dec!(0); + let pools = list_pool_pairs_cached(ctx).await?.0; + for (_, info) in pools { + let total_liquidity_usd = get_total_liquidity_usd(ctx, &info).await?; + dex += total_liquidity_usd; + } + + // masternodes + let usd = get_usd_per_dfi(ctx).await?; + let mut masternodes = ctx .services .masternode .stats .get_latest()? .map_or(Decimal::zero(), |mn| mn.stats.tvl); + masternodes *= usd; + + // loan + let loan = get_loan(&ctx.client).await?; + let loan = Decimal::from_f64(loan.value.collateral).unwrap_or_default(); - // return { - // dex: dex.toNumber(), - // masternodes: masternodeTvlUSD, - // loan: loan.value.collateral, - // total: dex.toNumber() + masternodeTvlUSD + loan.value.collateral - // } Ok(Tvl { - loan: loan.value.collateral, + loan, masternodes, - // TODO dex - // TODO total - ..Default::default() + dex, + total: dex + masternodes + loan, }) } + +#[derive(Debug, Serialize, Deserialize, Default, Clone)] +pub struct Price { + pub usd: Decimal, + #[deprecated(note = "use USD instead of aggregation over multiple pairs")] + pub usdt: Decimal, +} + +#[cached( + result = true, + time = 300, + key = "String", + convert = r#"{ format!("price") }"# +)] +pub async fn get_price(ctx: &Arc) -> Result { + let usd = get_usd_per_dfi(ctx).await?; + #[allow(deprecated)] + Ok(Price { usd, usdt: usd }) +} diff --git a/lib/ain-ocean/src/api/stats/mod.rs b/lib/ain-ocean/src/api/stats/mod.rs index 091b2834fac..404833b50e0 100644 --- a/lib/ain-ocean/src/api/stats/mod.rs +++ b/lib/ain-ocean/src/api/stats/mod.rs @@ -16,8 +16,8 @@ use serde::{Deserialize, Serialize}; use self::{ cache::{ - get_burned, get_count, get_emission, get_loan, get_masternodes, get_tvl, Burned, Count, - Emission, Loan, Masternodes, Tvl, + get_burned, get_count, get_emission, get_loan, get_masternodes, get_price, get_tvl, Burned, + Count, Emission, Loan, Masternodes, Price, Tvl, }, distribution::get_block_reward_distribution, }; @@ -41,13 +41,6 @@ pub struct StatsData { pub net: Net, } -#[derive(Debug, Serialize, Deserialize, Default)] -pub struct Price { - pub usd: f64, - #[deprecated(note = "use USD instead of aggregation over multiple pairs")] - pub usdt: f64, -} - #[derive(Debug, Serialize, Deserialize, Default)] pub struct Blockchain { pub difficulty: f64, @@ -91,10 +84,9 @@ async fn get_stats(Extension(ctx): Extension>) -> Result Date: Thu, 8 Aug 2024 17:14:08 +0800 Subject: [PATCH 128/185] weightage u8 (#2992) --- lib/ain-ocean/src/indexer/loan_token.rs | 2 +- lib/ain-ocean/src/indexer/oracle.rs | 10 +++++----- lib/ain-ocean/src/model/oracle_price_active.rs | 4 ++-- lib/ain-ocean/src/model/oracle_price_aggregated.rs | 2 +- .../src/model/oracle_price_aggregated_interval.rs | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/ain-ocean/src/indexer/loan_token.rs b/lib/ain-ocean/src/indexer/loan_token.rs index 6da704056fa..34d07f1885b 100644 --- a/lib/ain-ocean/src/indexer/loan_token.rs +++ b/lib/ain-ocean/src/indexer/loan_token.rs @@ -48,7 +48,7 @@ fn is_aggregate_valid(aggregate: &OraclePriceAggregated, block: &BlockContext) - return false; } - if aggregate.aggregated.weightage <= 0 { + if aggregate.aggregated.weightage == 0 { return false; } diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index 5364323134a..1556b8b4464 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -474,7 +474,7 @@ fn map_price_aggregated( currency, aggregated: OraclePriceAggregatedAggregated { amount: format!("{:.8}", aggregated_amount), - weightage: aggregated_weightage as i32, + weightage: aggregated_weightage, oracles: OraclePriceAggregatedAggregatedOracles { active: aggregated_count, total: oracles_len as i32, @@ -810,8 +810,8 @@ pub fn invalidate_oracle_interval( aggregated: OraclePriceAggregatedIntervalAggregated { amount: aggregated_amount.to_string(), weightage: aggregated_weightage - .to_i32() - .context("Err: Decimal.to_i32()")?, + .to_u8() + .context("Err: Decimal.to_u8()")?, count, oracles: OraclePriceAggregatedIntervalAggregatedOracles { active: aggregated_active @@ -870,8 +870,8 @@ fn forward_aggregate( aggregated: OraclePriceAggregatedIntervalAggregated { amount: aggregated_amount.to_string(), weightage: aggregated_weightage - .to_i32() - .context("Err: Decimal.to_i32()")?, + .to_u8() + .context("Err: Decimal.to_u8()")?, count, oracles: OraclePriceAggregatedIntervalAggregatedOracles { active: aggregated_active diff --git a/lib/ain-ocean/src/model/oracle_price_active.rs b/lib/ain-ocean/src/model/oracle_price_active.rs index 08c08c893eb..6f3953e256f 100644 --- a/lib/ain-ocean/src/model/oracle_price_active.rs +++ b/lib/ain-ocean/src/model/oracle_price_active.rs @@ -20,7 +20,7 @@ pub struct OraclePriceActive { #[serde(rename_all = "camelCase")] pub struct OraclePriceActiveActive { pub amount: String, - pub weightage: i32, + pub weightage: u8, pub oracles: OraclePriceActiveActiveOracles, } @@ -28,7 +28,7 @@ pub struct OraclePriceActiveActive { #[serde(rename_all = "camelCase")] pub struct OraclePriceActiveNext { pub amount: String, - pub weightage: i32, + pub weightage: u8, pub oracles: OraclePriceActiveNextOracles, } diff --git a/lib/ain-ocean/src/model/oracle_price_aggregated.rs b/lib/ain-ocean/src/model/oracle_price_aggregated.rs index ecc30eb2209..21070ef3145 100644 --- a/lib/ain-ocean/src/model/oracle_price_aggregated.rs +++ b/lib/ain-ocean/src/model/oracle_price_aggregated.rs @@ -19,7 +19,7 @@ pub struct OraclePriceAggregated { #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedAggregated { pub amount: String, - pub weightage: i32, + pub weightage: u8, pub oracles: OraclePriceAggregatedAggregatedOracles, } diff --git a/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs index 6c36c769330..12b9d299044 100644 --- a/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs +++ b/lib/ain-ocean/src/model/oracle_price_aggregated_interval.rs @@ -31,7 +31,7 @@ pub struct OraclePriceAggregatedInterval { #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedIntervalAggregated { pub amount: String, - pub weightage: i32, + pub weightage: u8, pub count: i32, pub oracles: OraclePriceAggregatedIntervalAggregatedOracles, } From f523e1949d18cb272e68e6f7b89c7575493df93f Mon Sep 17 00:00:00 2001 From: jouzo <15011228+Jouzo@users.noreply.github.com> Date: Thu, 8 Aug 2024 22:59:56 +0200 Subject: [PATCH 129/185] Auto ocean port --- lib/ain-grpc/src/lib.rs | 8 ++++- lib/ain-ocean/src/indexer/mod.rs | 4 +-- src/ffi/ffiexports.cpp | 6 +++- src/init.cpp | 60 +++++++++++++++++++++++++------- src/logging.cpp | 2 ++ src/logging.h | 3 +- 6 files changed, 65 insertions(+), 18 deletions(-) diff --git a/lib/ain-grpc/src/lib.rs b/lib/ain-grpc/src/lib.rs index 24b761084bf..7cbd9843386 100644 --- a/lib/ain-grpc/src/lib.rs +++ b/lib/ain-grpc/src/lib.rs @@ -35,7 +35,7 @@ use anyhow::{format_err, Result}; use hyper::{header::HeaderValue, Method}; use jsonrpsee::core::server::rpc_module::Methods; use jsonrpsee_server::ServerBuilder; -use log::info; +use log::{debug, info}; use logging::CppLogTarget; use tower_http::cors::CorsLayer; @@ -126,6 +126,10 @@ pub async fn init_ocean_server(addr: String) -> Result<()> { let listener = tokio::net::TcpListener::bind(addr).await?; + let local_addr = listener.local_addr()?; + info!("Starting ocean server at {}", local_addr); + ain_cpp_imports::print_port_usage(4, local_addr.port()); + let (user, pass) = ain_cpp_imports::get_rpc_auth().map_err(|e| format_err!("{e}"))?; let client = Arc::new( Client::new( @@ -134,6 +138,7 @@ pub async fn init_ocean_server(addr: String) -> Result<()> { ) .await?, ); + debug!("client : {:?}", client); let network = ain_cpp_imports::get_network(); let ocean_router = ain_ocean::ocean_router(&OCEAN_SERVICES, client, network).await?; @@ -143,6 +148,7 @@ pub async fn init_ocean_server(addr: String) -> Result<()> { log::error!("Server encountered an error: {}", e); } }); + *runtime.ocean_handle.lock() = Some(server_handle); Ok(()) } diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index d21dbbf9ae7..015da6fd35a 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -534,8 +534,6 @@ pub fn index_block(services: &Arc, block: Block) -> Resul } } - log_elapsed(start, "Indexed block"); - let block_mapper = BlockMapper { hash: block_hash, id: block_hash, @@ -566,6 +564,8 @@ pub fn index_block(services: &Arc, block: Block) -> Resul //index block end index_block_end(services, &block_ctx)?; + log_elapsed(start, "Indexed block"); + Ok(()) } diff --git a/src/ffi/ffiexports.cpp b/src/ffi/ffiexports.cpp index f3436c13973..f6ed1c23125 100644 --- a/src/ffi/ffiexports.cpp +++ b/src/ffi/ffiexports.cpp @@ -30,7 +30,11 @@ uint64_t getChainId() { } int getRPCPort() { - return gArgs.GetArg("-rpcport", BaseParams().RPCPort()); + auto dvmport = gArgs.GetArg("-rpcport", BaseParams().RPCPort()); + if (const auto port = GetPortFromLockFile(AutoPort::RPC); port) { + dvmport = port; + } + return dvmport; } rust::string getRPCAuth() { diff --git a/src/init.cpp b/src/init.cpp index 185236edc75..1b63c5b3a12 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -679,6 +679,7 @@ void SetupServerArgs() gArgs.AddArg("-ethsubscription", strprintf("Enable subscription notifications ETH RPCs (default: %b)", DEFAULT_ETH_SUBSCRIPTION_ENABLED), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); gArgs.AddArg("-oceanarchive", strprintf("Enable ocean archive and REST server (default: %b)", DEFAULT_OCEAN_ARCHIVE_ENABLED), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); gArgs.AddArg("-oceanarchiveport=", strprintf("Listen for ocean archive connections on (default: %u)", DEFAULT_OCEAN_ARCHIVE_PORT), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC); + gArgs.AddArg("-oceanarchivebind=[:port]", "Bind to given address to listen for Ocean connections. Do not expose the Ocean server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -oceanarchiveport. This option can be specified multiple times (default: 127.0.0.1 i.e., localhost)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC); #if HAVE_DECL_DAEMON gArgs.AddArg("-daemon", "Run in the background as a daemon and accept commands", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -1604,7 +1605,7 @@ void SetupCacheSizes(CacheSizes& cacheSizes) { LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", nCoinCacheUsage * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024)); } -static void SetupRPCPorts(std::vector& ethEndpoints, std::vector& wsEndpoints) { +static void SetupRPCPorts(std::vector& ethEndpoints, std::vector& wsEndpoints, std::vector& oceanEndpoints) { std::string default_address = "127.0.0.1"; bool setAutoPort{}; @@ -1615,7 +1616,7 @@ static void SetupRPCPorts(std::vector& ethEndpoints, std::vector& ethEndpoints, std::vector& ethEndpoints, std::vector eth_endpoints, ws_endpoints; - SetupRPCPorts(eth_endpoints, ws_endpoints); + std::vector eth_endpoints, ws_endpoints, ocean_endpoints; + SetupRPCPorts(eth_endpoints, ws_endpoints, ocean_endpoints); CrossBoundaryResult result; // Bind ETH RPC addresses @@ -2391,15 +2420,20 @@ bool AppInitMain(InitInterfaces& interfaces) // bind ocean REST addresses if (gArgs.GetBoolArg("-oceanarchive", DEFAULT_OCEAN_ARCHIVE_ENABLED)) { - // for (auto it = ocean_endpoints.begin(); it != ocean_endpoints.end(); ++it) { - // LogPrint(BCLog::HTTP, "Binding ocean server on endpoint %s\n", *it); - auto port = gArgs.GetArg("-oceanarchiveport", DEFAULT_OCEAN_ARCHIVE_PORT); - auto res = XResultStatusLogged(ain_rs_init_network_rest_ocean(result, strprintf("0.0.0.0:%s", port))) - if (!res) { - // LogPrintf("Binding websocket server on endpoint %s failed.\n", *it); - return false; + // bind ocean addresses + for (auto it = ocean_endpoints.begin(); it != ocean_endpoints.end(); ++it) { + LogPrint(BCLog::HTTP, "Binding ocean server on endpoint %s\n", *it); + const auto addr = rs_try_from_utf8(result, ffi_from_string_to_slice(*it)); + if (!result.ok) { + LogPrint(BCLog::HTTP, "Invalid ocean address, not UTF-8 valid\n"); + return false; + } + auto res = XResultStatusLogged(ain_rs_init_network_rest_ocean(result, addr)) + if (!res) { + LogPrintf("Binding ocean server on endpoint %s failed.\n", *it); + return false; + } } - // } } } uiInterface.InitMessage(_("Done loading").translated); diff --git a/src/logging.cpp b/src/logging.cpp index a90354b4e3a..d78b7bfc3f9 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -336,6 +336,8 @@ static std::string GetAutoPortString(const AutoPort type) return "ethrpcport"; case WEBSOCKET: return "wsport"; + case OCEAN: + return "ocean"; default: return "Unknown"; } diff --git a/src/logging.h b/src/logging.h index 017d4d7965d..c70397d5339 100644 --- a/src/logging.h +++ b/src/logging.h @@ -32,6 +32,7 @@ enum AutoPort : uint8_t { P2P, ETHRPC, WEBSOCKET, + OCEAN }; struct CLogCategoryActive @@ -207,7 +208,7 @@ static inline void LogPrintCategoryOrThreadThrottled(const BCLog::LogFlags& cate LogPrintf(args...); it->second = current_time; } - } + } else { // No entry yet -> log directly and save timestamp last_log_timestamps.insert(std::make_pair(message_key, current_time)); From 0e287ea6907a36c00dc70055790f07e86c19e05b Mon Sep 17 00:00:00 2001 From: canonbrother Date: Tue, 13 Aug 2024 15:50:53 +0800 Subject: [PATCH 130/185] fix typo (#2995) --- src/init.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 1b63c5b3a12..8d21f4426b9 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1670,15 +1670,15 @@ static void SetupRPCPorts(std::vector& ethEndpoints, std::vector& ethEndpoints, std::vector Date: Fri, 16 Aug 2024 15:15:16 +0800 Subject: [PATCH 131/185] Ocean: cache refined (#2999) * cache ttl 600 * rm init sync_token_graph.. lazy load will do * rename list_tokens_cached * gov -> getgov * enable cache on list_pool_pairs_cached --- lib/ain-ocean/src/api/cache.rs | 29 ++++++++++++++++++------ lib/ain-ocean/src/api/mod.rs | 3 --- lib/ain-ocean/src/api/pool_pair/price.rs | 4 ++-- lib/ain-ocean/src/api/stats/cache.rs | 16 ++++++------- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/lib/ain-ocean/src/api/cache.rs b/lib/ain-ocean/src/api/cache.rs index 428033b9630..2b5689c4caa 100644 --- a/lib/ain-ocean/src/api/cache.rs +++ b/lib/ain-ocean/src/api/cache.rs @@ -16,6 +16,7 @@ use crate::Result; #[cached( result = true, + time = 600, key = "String", convert = r#"{ format!("gettoken{symbol}") }"# )] @@ -50,7 +51,13 @@ pub async fn get_token_cached( Ok(token) } -pub async fn list_token_cached(ctx: &Arc) -> Result { +#[cached( + result = true, + time = 600, + key = "String", + convert = r#"{ format!("listtokens") }"# +)] +pub async fn list_tokens_cached(ctx: &Arc) -> Result { let tokens = ctx .client .list_tokens( @@ -68,6 +75,7 @@ pub async fn list_token_cached(ctx: &Arc) -> Result { #[cached( result = true, + time = 600, key = "String", convert = r#"{ format!("getpoolpair{id}") }"# )] @@ -102,11 +110,12 @@ pub async fn get_pool_pair_cached( Ok(pool_pair) } -// #[cached( -// result = true, -// key = "String", -// convert = r#"{ format!("listpoolpairs") }"# -// )] +#[cached( + result = true, + time = 600, + key = "String", + convert = r#"{ format!("listpoolpairs") }"# +)] pub async fn list_pool_pairs_cached(ctx: &Arc) -> Result { let pool_pairs = ctx .client @@ -122,7 +131,12 @@ pub async fn list_pool_pairs_cached(ctx: &Arc) -> Result, id: String, @@ -133,6 +147,7 @@ pub async fn get_gov_cached( #[cached( result = true, + time = 600, key = "String", convert = r#"{ format!("getloanscheme{id}") }"# )] diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index d56d53195f6..2ec33f22ada 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -106,9 +106,6 @@ pub async fn ocean_router( network: Network::from_str(&network)?, }); - let context_cloned = context.clone(); - tokio::spawn(async move { pool_pair::path::sync_token_graph(&context_cloned).await }); - Ok(Router::new().nest( format!("/v0/{}", context.network).as_str(), Router::new() diff --git a/lib/ain-ocean/src/api/pool_pair/price.rs b/lib/ain-ocean/src/api/pool_pair/price.rs index 1bdb408d163..baad1bad90c 100644 --- a/lib/ain-ocean/src/api/pool_pair/price.rs +++ b/lib/ain-ocean/src/api/pool_pair/price.rs @@ -6,7 +6,7 @@ use serde::Serialize; use super::{path::get_best_path, AppContext}; use crate::{ api::{ - cache::{get_token_cached, list_token_cached}, + cache::{get_token_cached, list_tokens_cached}, common::parse_display_symbol, }, error::{Error, NotFoundKind}, @@ -40,7 +40,7 @@ pub async fn list_dex_prices(ctx: &Arc, symbol: String) -> Result Date: Mon, 19 Aug 2024 17:58:12 +0800 Subject: [PATCH 132/185] Ocean: fix loan token indexer (#2998) * get_network * sort desc * camelcase * rm dup model - refer OraclePriceActiveNext * fix map_active_price * fmt_rs * add missing oracle_price_aggregated by_key put * refine * fmt_rs --- lib/ain-ocean/src/api/prices.rs | 6 +- lib/ain-ocean/src/indexer/loan_token.rs | 173 +++++++----------- lib/ain-ocean/src/indexer/oracle.rs | 15 +- lib/ain-ocean/src/lib.rs | 6 +- .../src/model/oracle_price_active.rs | 17 +- .../src/model/oracle_price_aggregated.rs | 23 +-- .../src/repository/oracle_price_aggregated.rs | 2 +- 7 files changed, 88 insertions(+), 154 deletions(-) diff --git a/lib/ain-ocean/src/api/prices.rs b/lib/ain-ocean/src/api/prices.rs index a8a024c976c..f203eb50c0d 100644 --- a/lib/ain-ocean/src/api/prices.rs +++ b/lib/ain-ocean/src/api/prices.rs @@ -21,7 +21,7 @@ use crate::{ error::{ApiError, Error, NotFoundKind}, model::{ ApiResponseOraclePriceFeed, OracleIntervalSeconds, OraclePriceActive, - OraclePriceAggregated, OraclePriceAggregatedAggregated, OraclePriceAggregatedApi, + OraclePriceActiveNext, OraclePriceAggregated, OraclePriceAggregatedApi, OraclePriceAggregatedInterval, OraclePriceAggregatedIntervalAggregated, OracleTokenCurrency, PriceOracles, PriceTickerApi, }, @@ -77,7 +77,7 @@ async fn list_prices( sort: price_ticker.price.sort, token: price_ticker.price.token, currency: price_ticker.price.currency, - aggregated: OraclePriceAggregatedAggregated { + aggregated: OraclePriceActiveNext { amount: amount.to_string(), weightage: price_ticker.price.aggregated.weightage, oracles: price_ticker.price.aggregated.oracles, @@ -120,7 +120,7 @@ async fn get_price( sort: price_ticker.price.sort, token: price_ticker.price.token, currency: price_ticker.price.currency, - aggregated: OraclePriceAggregatedAggregated { + aggregated: OraclePriceActiveNext { amount: amount.to_string(), weightage: price_ticker.price.aggregated.weightage, oracles: price_ticker.price.aggregated.oracles, diff --git a/lib/ain-ocean/src/indexer/loan_token.rs b/lib/ain-ocean/src/indexer/loan_token.rs index 34d07f1885b..b5c2489fddc 100644 --- a/lib/ain-ocean/src/indexer/loan_token.rs +++ b/lib/ain-ocean/src/indexer/loan_token.rs @@ -6,10 +6,7 @@ use rust_decimal_macros::dec; use crate::{ indexer::{Context, Index, Result}, - model::{ - BlockContext, OraclePriceActive, OraclePriceActiveActive, OraclePriceActiveActiveOracles, - OraclePriceActiveNext, OraclePriceActiveNextOracles, OraclePriceAggregated, - }, + model::{BlockContext, OraclePriceActive, OraclePriceActiveNext, OraclePriceAggregated}, network::Network, repository::RepositoryOps, storage::SortOrder, @@ -55,7 +52,7 @@ fn is_aggregate_valid(aggregate: &OraclePriceAggregated, block: &BlockContext) - true } -fn is_live(active: Option, next: Option) -> bool { +fn is_live(active: Option, next: Option) -> bool { let Some(active) = active else { return false; }; @@ -90,7 +87,8 @@ fn is_live(active: Option, next: Option, block: &BlockContext) -> Result<()> { - let block_interval = match Network::Regtest { + let network = ain_cpp_imports::get_network(); + let block_interval = match Network::from_str(&network)? { Network::Regtest => 6, _ => 120, }; @@ -98,7 +96,7 @@ pub fn index_active_price(services: &Arc, block: &BlockContext) -> Res let pt = services .price_ticker .by_id - .list(None, SortOrder::Ascending)? + .list(None, SortOrder::Descending)? .map(|item| { let (_, priceticker) = item?; Ok(priceticker) @@ -112,124 +110,89 @@ pub fn index_active_price(services: &Arc, block: &BlockContext) -> Res Ok(()) } +fn map_active_price( + block: &BlockContext, + ticker_id: (String, String), + aggregated_price: OraclePriceAggregated, + prev_price: OraclePriceActive, +) -> OraclePriceActive { + let next_price = if is_aggregate_valid(&aggregated_price, block) { + Some(aggregated_price.aggregated) + } else { + None + }; + + let active_price = if let Some(next) = prev_price.next { + Some(next) + } else { + prev_price.active + }; + + OraclePriceActive { + id: (ticker_id.0.clone(), ticker_id.1.clone(), block.height), + key: ticker_id, + sort: hex::encode(block.height.to_be_bytes()), + active: active_price.clone(), + next: next_price.clone(), + is_live: is_live(active_price, next_price), + block: block.clone(), + } +} + pub fn perform_active_price_tick( services: &Arc, ticker_id: (String, String), block: &BlockContext, ) -> Result<()> { - let aggregated_prices = services - .oracle_price_aggregated + let repo = &services.oracle_price_aggregated; + let prev_keys = repo .by_key .list(Some(ticker_id.clone()), SortOrder::Descending)? - .map(|item| { - let (_, id) = item?; - let aggregated = services - .oracle_price_aggregated - .by_id - .get(&id)? - .ok_or("Missing oracle previous history index")?; - - Ok(aggregated) - }) - .collect::>>()?; - - log::debug!( - "set_loan_token indexing aggregated_price: {:?}", - aggregated_prices - ); - - if aggregated_prices.is_empty() { + .take(1) + .flatten() // return empty vec if none + .collect::>(); + + if prev_keys.is_empty() { return Ok(()); } - let aggregated_price = aggregated_prices.first().unwrap(); - let previous_prices = services - .oracle_price_active + let Some((_, prev_id)) = prev_keys.first() else { + return Ok(()); + }; + + let aggregated_price = repo.by_id.get(prev_id)?; + + let Some(aggregated_price) = aggregated_price else { + return Ok(()); + }; + + let repo = &services.oracle_price_active; + let prev_keys = repo .by_key .list(Some(ticker_id.clone()), SortOrder::Descending)? .take(1) - .map(|item| { - let (_, id) = item?; - let price = services - .oracle_price_active - .by_id - .get(&id)? - .ok_or("Missing oracle previous history index")?; - Ok(price) - }) - .collect::>>()?; - - let active_price = if previous_prices.first().is_some() { - if previous_prices[0].next.is_some() { - let price = previous_prices[0].next.clone().unwrap(); - Some(OraclePriceActiveActive { - amount: price.amount, - weightage: price.weightage, - oracles: OraclePriceActiveActiveOracles { - active: price.oracles.active, - total: price.oracles.total, - }, - }) - } else if previous_prices[0].active.is_some() { - let price = previous_prices[0].active.clone().unwrap(); - Some(OraclePriceActiveActive { - amount: price.amount, - weightage: price.weightage, - oracles: OraclePriceActiveActiveOracles { - active: price.oracles.active, - total: price.oracles.total, - }, - }) - } else { - None - } - } else { - None - }; + .flatten() + .collect::>(); - let price_active_id = ( - ticker_id.0.clone(), - ticker_id.1.clone(), - aggregated_price.block.height, - ); - - let next_price = if is_aggregate_valid(aggregated_price, block) { - Some(OraclePriceActiveNext { - amount: aggregated_price.aggregated.amount.clone(), - weightage: aggregated_price.aggregated.weightage, - oracles: OraclePriceActiveNextOracles { - active: aggregated_price.aggregated.oracles.active, - total: aggregated_price.aggregated.oracles.total, - }, - }) - } else { - None + if prev_keys.is_empty() { + return Ok(()); + } + + let Some((_, prev_id)) = prev_keys.first() else { + return Ok(()); }; - let oracle_price_active = OraclePriceActive { - id: price_active_id.clone(), - key: ticker_id, - sort: hex::encode(block.height.to_be_bytes()), - active: active_price.clone(), - next: next_price.clone(), - is_live: is_live(active_price, next_price), - block: block.clone(), + let prev_price = repo.by_id.get(prev_id)?; + + let Some(prev_price) = prev_price else { + return Ok(()); }; - services - .oracle_price_active - .by_id - .put(&price_active_id, &oracle_price_active)?; + let active_price = map_active_price(block, ticker_id, aggregated_price, prev_price); - services - .oracle_price_active - .by_key - .put(&oracle_price_active.key, &oracle_price_active.id)?; + repo.by_id.put(&active_price.id, &active_price)?; - log::debug!( - "set_loan_token indexing oracle_price_active: {:?}", - oracle_price_active - ); + repo.by_key.put(&active_price.key, &active_price.id)?; Ok(()) } diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index 1556b8b4464..c0c2a3652d4 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -13,11 +13,10 @@ use rust_decimal_macros::dec; use crate::{ indexer::{Context, Index, Result}, model::{ - BlockContext, Oracle, OracleHistory, OracleIntervalSeconds, OraclePriceAggregated, - OraclePriceAggregatedAggregated, OraclePriceAggregatedAggregatedOracles, - OraclePriceAggregatedInterval, OraclePriceAggregatedIntervalAggregated, - OraclePriceAggregatedIntervalAggregatedOracles, OraclePriceFeed, OracleTokenCurrency, - PriceFeedsItem, PriceTicker, + BlockContext, Oracle, OracleHistory, OracleIntervalSeconds, OraclePriceActiveNext, + OraclePriceActiveNextOracles, OraclePriceAggregated, OraclePriceAggregatedInterval, + OraclePriceAggregatedIntervalAggregated, OraclePriceAggregatedIntervalAggregatedOracles, + OraclePriceFeed, OracleTokenCurrency, PriceFeedsItem, PriceTicker, }, repository::RepositoryOps, storage::SortOrder, @@ -472,10 +471,10 @@ fn map_price_aggregated( ), token, currency, - aggregated: OraclePriceAggregatedAggregated { + aggregated: OraclePriceActiveNext { amount: format!("{:.8}", aggregated_amount), weightage: aggregated_weightage, - oracles: OraclePriceAggregatedAggregatedOracles { + oracles: OraclePriceActiveNextOracles { active: aggregated_count, total: oracles_len as i32, }, @@ -504,7 +503,7 @@ fn index_set_oracle_data( price_aggregated.currency.clone(), ); let id = (key.0.clone(), key.1.clone(), price_aggregated.block.height); - // oracle_repo.by_key.put(&key, &id)?; + oracle_repo.by_key.put(&key, &id)?; oracle_repo.by_id.put(&id, &price_aggregated)?; let id = ( diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 4667b4b633f..0635c85bcb3 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -19,7 +19,7 @@ use repository::{ OracleHistoryRepository, OracleHistoryRepositoryKey, OraclePriceActiveKeyRepository, OraclePriceActiveRepository, OraclePriceAggregatedIntervalKeyRepository, OraclePriceAggregatedIntervalRepository, OraclePriceAggregatedRepository, - OraclePriceAggregatedRepositorykey, OraclePriceFeedKeyRepository, OraclePriceFeedRepository, + OraclePriceAggregatedRepositoryKey, OraclePriceFeedKeyRepository, OraclePriceFeedRepository, OracleRepository, OracleTokenCurrencyKeyRepository, OracleTokenCurrencyRepository, PoolPairByHeightRepository, PoolPairRepository, PoolSwapAggregatedKeyRepository, PoolSwapAggregatedRepository, PoolSwapRepository, PriceTickerKeyRepository, @@ -102,7 +102,7 @@ pub struct OraclePriceAggregatedIntervalService { by_id: OraclePriceAggregatedIntervalRepository, } pub struct OraclePriceAggregatedService { - by_key: OraclePriceAggregatedRepositorykey, + by_key: OraclePriceAggregatedRepositoryKey, by_id: OraclePriceAggregatedRepository, } @@ -217,7 +217,7 @@ impl Services { by_id: OraclePriceAggregatedIntervalRepository::new(Arc::clone(&store)), }, oracle_price_aggregated: OraclePriceAggregatedService { - by_key: OraclePriceAggregatedRepositorykey::new(Arc::clone(&store)), + by_key: OraclePriceAggregatedRepositoryKey::new(Arc::clone(&store)), by_id: OraclePriceAggregatedRepository::new(Arc::clone(&store)), }, oracle_token_currency: OracleTokenCurrencyService { diff --git a/lib/ain-ocean/src/model/oracle_price_active.rs b/lib/ain-ocean/src/model/oracle_price_active.rs index 6f3953e256f..3037bf29dc9 100644 --- a/lib/ain-ocean/src/model/oracle_price_active.rs +++ b/lib/ain-ocean/src/model/oracle_price_active.rs @@ -10,20 +10,12 @@ pub struct OraclePriceActive { pub id: OraclePriceActiveId, pub key: OraclePriceActiveKey, pub sort: String, //height - pub active: Option, + pub active: Option, pub next: Option, pub is_live: bool, pub block: BlockContext, } -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct OraclePriceActiveActive { - pub amount: String, - pub weightage: u8, - pub oracles: OraclePriceActiveActiveOracles, -} - #[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct OraclePriceActiveNext { @@ -32,13 +24,6 @@ pub struct OraclePriceActiveNext { pub oracles: OraclePriceActiveNextOracles, } -#[derive(Serialize, Deserialize, Debug, Clone, Default)] -#[serde(rename_all = "camelCase")] -pub struct OraclePriceActiveActiveOracles { - pub active: i32, - pub total: i32, -} - #[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct OraclePriceActiveNextOracles { diff --git a/lib/ain-ocean/src/model/oracle_price_aggregated.rs b/lib/ain-ocean/src/model/oracle_price_aggregated.rs index 21070ef3145..6bacb3c78b2 100644 --- a/lib/ain-ocean/src/model/oracle_price_aggregated.rs +++ b/lib/ain-ocean/src/model/oracle_price_aggregated.rs @@ -1,8 +1,10 @@ use serde::{Deserialize, Serialize}; -use super::BlockContext; +use super::{BlockContext, OraclePriceActiveNext}; + pub type OraclePriceAggregatedId = (String, String, u32); //token-currency-height pub type OraclePriceAggregatedKey = (String, String); //token-currency + #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregated { @@ -11,25 +13,10 @@ pub struct OraclePriceAggregated { pub sort: String, pub token: String, pub currency: String, - pub aggregated: OraclePriceAggregatedAggregated, + pub aggregated: OraclePriceActiveNext, pub block: BlockContext, } -#[derive(Serialize, Deserialize, Debug, Clone, Default)] -#[serde(rename_all = "camelCase")] -pub struct OraclePriceAggregatedAggregated { - pub amount: String, - pub weightage: u8, - pub oracles: OraclePriceAggregatedAggregatedOracles, -} - -#[derive(Serialize, Deserialize, Debug, Clone, Default)] -#[serde(rename_all = "camelCase")] -pub struct OraclePriceAggregatedAggregatedOracles { - pub active: i32, - pub total: i32, -} - #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct OraclePriceAggregatedApi { @@ -38,6 +25,6 @@ pub struct OraclePriceAggregatedApi { pub sort: String, pub token: String, pub currency: String, - pub aggregated: OraclePriceAggregatedAggregated, + pub aggregated: OraclePriceActiveNext, pub block: BlockContext, } diff --git a/lib/ain-ocean/src/repository/oracle_price_aggregated.rs b/lib/ain-ocean/src/repository/oracle_price_aggregated.rs index ba957faffe1..2f36f4d4e2f 100644 --- a/lib/ain-ocean/src/repository/oracle_price_aggregated.rs +++ b/lib/ain-ocean/src/repository/oracle_price_aggregated.rs @@ -19,7 +19,7 @@ pub struct OraclePriceAggregatedRepository { #[derive(Repository)] #[repository(K = "OraclePriceAggregatedKey", V = "OraclePriceAggregatedId")] -pub struct OraclePriceAggregatedRepositorykey { +pub struct OraclePriceAggregatedRepositoryKey { pub store: Arc, col: LedgerColumn, } From 8feb418911b7c3d9392586933aed6e113577179d Mon Sep 17 00:00:00 2001 From: canonbrother Date: Tue, 20 Aug 2024 16:19:23 +0800 Subject: [PATCH 133/185] Ocean: CollateralToken.active_price + typing amount: decimal (#2990) * add active_price on CollateralToken * fix serde * fix type * fmt_rs --- lib/ain-ocean/src/api/loan.rs | 40 +++++- lib/ain-ocean/src/api/prices.rs | 115 ++++++++++-------- lib/ain-ocean/src/indexer/loan_token.rs | 8 +- lib/ain-ocean/src/indexer/oracle.rs | 8 +- .../src/model/oracle_price_active.rs | 4 +- .../src/model/oracle_price_aggregated.rs | 12 -- lib/ain-ocean/src/model/price_ticker.rs | 10 +- 7 files changed, 109 insertions(+), 88 deletions(-) diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index 8bf2a1af0b3..fc9a1cd0caa 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -30,6 +30,7 @@ use super::{ AppContext, }; use crate::{ + api::prices::PriceTickerResponse, error::{ApiError, Error}, model::{OraclePriceActive, VaultAuctionBatchHistory}, repository::{RepositoryOps, SecondaryIndex}, @@ -96,22 +97,49 @@ pub struct CollateralToken { factor: String, activate_after_block: u32, fixed_interval_price_id: String, - // TODO when indexing price - // activePrice?: ActivePrice + active_price: Option, } impl CollateralToken { - fn from_with_id(id: String, detail: CollateralTokenDetail, info: TokenInfo) -> Self { + fn from_with_id( + id: String, + detail: CollateralTokenDetail, + info: TokenInfo, + active_price: Option, + ) -> Self { Self { token_id: detail.token_id, factor: format!("{}", detail.factor), activate_after_block: 0, fixed_interval_price_id: detail.fixed_interval_price_id, token: TokenData::from_with_id(id, info), + active_price, } } } +async fn get_active_price( + ctx: &Arc, + fixed_interval_price_id: String, +) -> Result> { + let mut parts = fixed_interval_price_id.split('/'); + let token = parts + .next() + .context("Invalid fixed interval price id structure")? + .to_string(); + let currency = parts + .next() + .context("Invalid fixed interval price id structure")? + .to_string(); + let price = ctx.services.price_ticker.by_id.get(&(token, currency))?; + + let Some(active_price) = price else { + return Ok(None); + }; + + Ok(Some(PriceTickerResponse::from(active_price))) +} + #[ocean_endpoint] async fn list_collateral_token( Query(query): Query, @@ -131,7 +159,8 @@ async fn list_collateral_token( let (id, info) = get_token_cached(&ctx, &v.token_id) .await? .context("None is not valid")?; - Ok::(CollateralToken::from_with_id(id, v, info)) + let active_price = get_active_price(&ctx, v.fixed_interval_price_id.clone()).await?; + Ok::(CollateralToken::from_with_id(id, v, info, active_price)) }) .collect::>(); @@ -151,11 +180,14 @@ async fn get_collateral_token( let (id, info) = get_token_cached(&ctx, &collateral_token.token_id) .await? .context("None is not valid")?; + let active_price = + get_active_price(&ctx, collateral_token.fixed_interval_price_id.clone()).await?; Ok(Response::new(CollateralToken::from_with_id( id, collateral_token, info, + active_price, ))) } diff --git a/lib/ain-ocean/src/api/prices.rs b/lib/ain-ocean/src/api/prices.rs index f203eb50c0d..50b2ebaeaf4 100644 --- a/lib/ain-ocean/src/api/prices.rs +++ b/lib/ain-ocean/src/api/prices.rs @@ -1,4 +1,4 @@ -use std::{str::FromStr, sync::Arc}; +use std::sync::Arc; use ain_dftx::COIN; use ain_macros::ocean_endpoint; @@ -10,6 +10,7 @@ use axum::{ }; use indexmap::IndexSet; use rust_decimal::Decimal; +use serde::{Deserialize, Serialize}; use super::{ common::split_key, @@ -20,21 +21,74 @@ use super::{ use crate::{ error::{ApiError, Error, NotFoundKind}, model::{ - ApiResponseOraclePriceFeed, OracleIntervalSeconds, OraclePriceActive, - OraclePriceActiveNext, OraclePriceAggregated, OraclePriceAggregatedApi, - OraclePriceAggregatedInterval, OraclePriceAggregatedIntervalAggregated, - OracleTokenCurrency, PriceOracles, PriceTickerApi, + ApiResponseOraclePriceFeed, BlockContext, OracleIntervalSeconds, OraclePriceActive, + OraclePriceActiveNextOracles, OraclePriceAggregated, OraclePriceAggregatedInterval, + OraclePriceAggregatedIntervalAggregated, OracleTokenCurrency, PriceOracles, PriceTicker, }, repository::RepositoryOps, storage::SortOrder, Result, }; +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceAggregatedResponse { + pub id: String, + pub key: String, + pub sort: String, + pub token: String, + pub currency: String, + pub aggregated: OraclePriceAggregatedAggregatedResponse, + pub block: BlockContext, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceAggregatedAggregatedResponse { + pub amount: String, + pub weightage: u8, + pub oracles: OraclePriceActiveNextOracles, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PriceTickerResponse { + pub id: String, //token-currency + pub sort: String, //count-height-token-currency + pub price: OraclePriceAggregatedResponse, +} + +impl From for PriceTickerResponse { + fn from(price_ticker: PriceTicker) -> Self { + let amount = price_ticker.price.aggregated.amount / Decimal::from(COIN); + Self { + id: format!("{}-{}", price_ticker.id.0, price_ticker.id.1), + sort: price_ticker.sort, + price: OraclePriceAggregatedResponse { + id: format!( + "{}-{}-{}", + price_ticker.price.id.0, price_ticker.price.id.1, price_ticker.price.id.2 + ), + key: format!("{}-{}", price_ticker.price.key.0, price_ticker.price.key.1), + sort: price_ticker.price.sort, + token: price_ticker.price.token, + currency: price_ticker.price.currency, + aggregated: OraclePriceAggregatedAggregatedResponse { + amount: format!("{:.8}", amount), + weightage: price_ticker.price.aggregated.weightage, + oracles: price_ticker.price.aggregated.oracles, + }, + block: price_ticker.price.block, + }, + } + } +} + #[ocean_endpoint] async fn list_prices( Query(query): Query, Extension(ctx): Extension>, -) -> Result> { +) -> Result> { let sorted_ids = ctx .services .price_ticker @@ -63,28 +117,7 @@ async fn list_prices( .get(&id)? .context("Missing price ticker index")?; - let amount = - Decimal::from_str(&price_ticker.price.aggregated.amount)? / Decimal::from(COIN); - Ok(PriceTickerApi { - id: format!("{}-{}", price_ticker.id.0, price_ticker.id.1), - sort: price_ticker.sort, - price: OraclePriceAggregatedApi { - id: format!( - "{}-{}-{}", - price_ticker.price.id.0, price_ticker.price.id.1, price_ticker.price.id.2 - ), - key: format!("{}-{}", price_ticker.price.key.0, price_ticker.price.key.1), - sort: price_ticker.price.sort, - token: price_ticker.price.token, - currency: price_ticker.price.currency, - aggregated: OraclePriceActiveNext { - amount: amount.to_string(), - weightage: price_ticker.price.aggregated.weightage, - oracles: price_ticker.price.aggregated.oracles, - }, - block: price_ticker.price.block, - }, - }) + Ok(PriceTickerResponse::from(price_ticker)) }) .collect::>>()?; @@ -96,7 +129,7 @@ async fn list_prices( async fn get_price( Path(key): Path, Extension(ctx): Extension>, -) -> Result> { +) -> Result> { let (token, currency) = match split_key(&key) { Ok((t, c)) => (t, c), Err(e) => return Err(Error::Other(anyhow!("Failed to split key: {}", e))), @@ -106,29 +139,7 @@ async fn get_price( if price_ticker.price.token.eq(&price_ticker_id.0) && price_ticker.price.currency.eq(&price_ticker_id.1) { - let amount = - Decimal::from_str(&price_ticker.price.aggregated.amount)? / Decimal::from(COIN); - let ticker = PriceTickerApi { - id: format!("{}-{}", price_ticker.id.0, price_ticker.id.1), - sort: price_ticker.sort, - price: OraclePriceAggregatedApi { - id: format!( - "{}-{}-{}", - price_ticker.price.id.0, price_ticker.price.id.1, price_ticker.price.id.2 - ), - key: format!("{}-{}", price_ticker.price.key.0, price_ticker.price.key.1), - sort: price_ticker.price.sort, - token: price_ticker.price.token, - currency: price_ticker.price.currency, - aggregated: OraclePriceActiveNext { - amount: amount.to_string(), - weightage: price_ticker.price.aggregated.weightage, - oracles: price_ticker.price.aggregated.oracles, - }, - block: price_ticker.price.block, - }, - }; - Ok(Response::new(ticker)) + Ok(Response::new(PriceTickerResponse::from(price_ticker))) } else { Err(Error::NotFound(NotFoundKind::Oracle)) } diff --git a/lib/ain-ocean/src/indexer/loan_token.rs b/lib/ain-ocean/src/indexer/loan_token.rs index b5c2489fddc..01613e81b9f 100644 --- a/lib/ain-ocean/src/indexer/loan_token.rs +++ b/lib/ain-ocean/src/indexer/loan_token.rs @@ -61,13 +61,9 @@ fn is_live(active: Option, next: Option Date: Tue, 20 Aug 2024 16:19:52 +0800 Subject: [PATCH 134/185] Ocean: cache list pool pairs api (#3000) * support size * cache listpoolpairs api * fmt * support next * fmt --- lib/ain-ocean/src/api/cache.rs | 14 ++++++---- lib/ain-ocean/src/api/pool_pair/mod.rs | 37 ++++++++++++++----------- lib/ain-ocean/src/api/pool_pair/path.rs | 2 +- lib/ain-ocean/src/api/stats/cache.rs | 2 +- 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/lib/ain-ocean/src/api/cache.rs b/lib/ain-ocean/src/api/cache.rs index 2b5689c4caa..c0e5da89e4e 100644 --- a/lib/ain-ocean/src/api/cache.rs +++ b/lib/ain-ocean/src/api/cache.rs @@ -114,16 +114,20 @@ pub async fn get_pool_pair_cached( result = true, time = 600, key = "String", - convert = r#"{ format!("listpoolpairs") }"# + convert = r#"{ format!("listpoolpairs{limit:?}{next:?}") }"# )] -pub async fn list_pool_pairs_cached(ctx: &Arc) -> Result { +pub async fn list_pool_pairs_cached( + ctx: &Arc, + limit: Option, + next: Option, +) -> Result { let pool_pairs = ctx .client .list_pool_pairs( Some(PoolPairPagination { - start: 0, - including_start: true, - limit: 1000, + start: next.unwrap_or_default(), + including_start: next.is_none(), + limit: limit.unwrap_or(1000), }), Some(true), ) diff --git a/lib/ain-ocean/src/api/pool_pair/mod.rs b/lib/ain-ocean/src/api/pool_pair/mod.rs index e06dc0bb886..6b74769cc0c 100644 --- a/lib/ain-ocean/src/api/pool_pair/mod.rs +++ b/lib/ain-ocean/src/api/pool_pair/mod.rs @@ -7,10 +7,7 @@ use ain_macros::ocean_endpoint; use anyhow::Context; use axum::{routing::get, Extension, Router}; use defichain_rpc::{ - json::{ - poolpair::{PoolPairInfo, PoolPairsResult}, - token::TokenInfo, - }, + json::{poolpair::PoolPairInfo, token::TokenInfo}, RpcApi, }; use futures::future::try_join_all; @@ -30,7 +27,7 @@ use service::{ }; use super::{ - cache::{get_pool_pair_cached, get_token_cached}, + cache::{get_pool_pair_cached, get_token_cached, list_pool_pairs_cached}, common::parse_dat_symbol, path::Path, query::{PaginationQuery, Query}, @@ -279,17 +276,25 @@ async fn list_pool_pairs( Query(query): Query, Extension(ctx): Extension>, ) -> Result> { - let pools: PoolPairsResult = ctx.client.call( - "listpoolpairs", - &[ - json!({ - "limit": query.size, - "start": query.next.as_ref().and_then(|n| n.parse::().ok()).unwrap_or_default(), - "including_start": query.next.is_none() - }), - true.into(), - ], - ).await?; + let next = query.next.map(|n| n.parse::()).transpose()?; + + let mut pools = list_pool_pairs_cached(&ctx, Some(query.size as u64), next).await?; + if pools.0.is_empty() { + pools = ctx + .client + .call( + "listpoolpairs", + &[ + json!({ + "limit": query.size, + "start": next.unwrap_or_default(), + "including_start": next.is_none() + }), + true.into(), + ], + ) + .await?; + } let fut = pools .0 diff --git a/lib/ain-ocean/src/api/pool_pair/path.rs b/lib/ain-ocean/src/api/pool_pair/path.rs index 3bbdb8727b7..d4fcd898820 100644 --- a/lib/ain-ocean/src/api/pool_pair/path.rs +++ b/lib/ain-ocean/src/api/pool_pair/path.rs @@ -488,7 +488,7 @@ pub async fn sync_token_graph(ctx: &Arc) -> Result<()> { let mut interval = tokio::time::interval(Duration::from_secs(120)); loop { - let pools = list_pool_pairs_cached(ctx).await?; + let pools = list_pool_pairs_cached(ctx, None, None).await?; // addTokensAndConnectionsToGraph for (k, v) in pools.0 { diff --git a/lib/ain-ocean/src/api/stats/cache.rs b/lib/ain-ocean/src/api/stats/cache.rs index ecf4bdefba1..8006e38f267 100644 --- a/lib/ain-ocean/src/api/stats/cache.rs +++ b/lib/ain-ocean/src/api/stats/cache.rs @@ -307,7 +307,7 @@ pub struct Tvl { pub async fn get_tvl(ctx: &Arc) -> Result { // dex let mut dex = dec!(0); - let pools = list_pool_pairs_cached(ctx).await?.0; + let pools = list_pool_pairs_cached(ctx, None, None).await?.0; for (_, info) in pools { let total_liquidity_usd = get_total_liquidity_usd(ctx, &info).await?; dex += total_liquidity_usd; From 347f6325f49ae8e572f785654abe00db96c30646 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Wed, 21 Aug 2024 18:10:09 +0800 Subject: [PATCH 135/185] check_evm_tx within vin loop (#3004) --- lib/ain-ocean/src/indexer/mod.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 015da6fd35a..9459aced9ca 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -167,11 +167,13 @@ fn find_tx_vout( fn index_script_activity(services: &Arc, block: &Block) -> Result<()> { for tx in block.tx.iter() { - if check_if_evm_tx(tx) { - continue; - } + let is_evm_tx = check_if_evm_tx(tx); for vin in tx.vin.iter() { + if is_evm_tx { + continue; + } + let Some(vin) = get_vin_standard(vin) else { continue; }; @@ -316,11 +318,13 @@ fn index_script_aggregation(services: &Arc, block: &Block } for tx in block.tx.iter() { - if check_if_evm_tx(tx) { - continue; - } + let is_evm_tx = check_if_evm_tx(tx); for vin in tx.vin.iter() { + if is_evm_tx { + continue; + } + let Some(vin) = get_vin_standard(vin) else { continue; }; @@ -396,11 +400,13 @@ fn index_script_aggregation(services: &Arc, block: &Block fn index_script_unspent(services: &Arc, block: &Block) -> Result<()> { for tx in block.tx.iter() { - if check_if_evm_tx(tx) { - continue; - } + let is_evm_tx = check_if_evm_tx(tx); for vin in tx.vin.iter() { + if is_evm_tx { + continue; + } + let Some(vin) = get_vin_standard(vin) else { continue; }; From 6cd02420ffa0c217a5134bbad3746bab9de75044 Mon Sep 17 00:00:00 2001 From: Jouzo <15011228+Jouzo@users.noreply.github.com> Date: Thu, 29 Aug 2024 12:18:54 +0100 Subject: [PATCH 136/185] Ocean: refactor tables (#3014) * Refactor columns and repository * Lint * Cargo fix * Clippy * Lint * Custom key for PoolSwapAggregatedKey --- lib/ain-ocean/src/api/address.rs | 26 +- lib/ain-ocean/src/api/block.rs | 15 +- lib/ain-ocean/src/api/common.rs | 6 +- lib/ain-ocean/src/api/loan.rs | 3 +- lib/ain-ocean/src/api/masternode/mod.rs | 5 +- lib/ain-ocean/src/api/oracle.rs | 3 +- lib/ain-ocean/src/api/pool_pair/mod.rs | 5 +- lib/ain-ocean/src/api/pool_pair/service.rs | 3 +- lib/ain-ocean/src/api/prices.rs | 3 +- lib/ain-ocean/src/api/stats/cache.rs | 3 +- lib/ain-ocean/src/api/transactions.rs | 7 +- lib/ain-ocean/src/indexer/auction.rs | 2 +- lib/ain-ocean/src/indexer/loan_token.rs | 3 +- lib/ain-ocean/src/indexer/masternode.rs | 2 +- lib/ain-ocean/src/indexer/mod.rs | 3 +- lib/ain-ocean/src/indexer/oracle.rs | 3 +- lib/ain-ocean/src/indexer/oracle_test.rs | 15 +- lib/ain-ocean/src/indexer/poolpair.rs | 2 +- lib/ain-ocean/src/indexer/poolswap.rs | 3 +- lib/ain-ocean/src/indexer/transaction.rs | 2 +- lib/ain-ocean/src/indexer/tx_result.rs | 2 +- lib/ain-ocean/src/lib.rs | 168 +++--- lib/ain-ocean/src/model/masternode.rs | 2 +- lib/ain-ocean/src/model/script_activity.rs | 3 +- lib/ain-ocean/src/model/script_unspent.rs | 3 +- lib/ain-ocean/src/repository/block.rs | 52 -- lib/ain-ocean/src/repository/masternode.rs | 39 -- .../src/repository/masternode_stats.rs | 28 - lib/ain-ocean/src/repository/mod.rs | 71 --- lib/ain-ocean/src/repository/oracle.rs | 19 - .../src/repository/oracle_history.rs | 26 - .../src/repository/oracle_price_active.rs | 38 -- .../src/repository/oracle_price_aggregated.rs | 25 - .../oracle_price_aggregated_interval.rs | 34 -- .../src/repository/oracle_price_feed.rs | 25 - .../src/repository/oracle_token_currency.rs | 25 - lib/ain-ocean/src/repository/pool_swap.rs | 25 - .../src/repository/pool_swap_aggregated.rs | 40 -- lib/ain-ocean/src/repository/poolpair.rs | 29 - lib/ain-ocean/src/repository/price_ticker.rs | 43 -- lib/ain-ocean/src/repository/raw_block.rs | 18 - .../src/repository/script_activity.rs | 18 - .../src/repository/script_aggregation.rs | 18 - .../src/repository/script_unspent.rs | 38 -- .../src/repository/test/block_test.rs | 219 -------- .../src/repository/test/masternode_test.rs | 85 --- lib/ain-ocean/src/repository/test/mod.rs | 4 - .../src/repository/test/oracle_test.rs | 73 --- .../src/repository/test/transaction_test.rs | 119 ---- lib/ain-ocean/src/repository/transaction.rs | 45 -- .../src/repository/transaction_vin.rs | 30 - .../src/repository/transaction_vout.rs | 18 - lib/ain-ocean/src/repository/tx_result.rs | 19 - .../repository/vault_auction_batch_history.rs | 38 -- lib/ain-ocean/src/storage/columns/block.rs | 49 -- .../src/storage/columns/masternode.rs | 35 -- .../src/storage/columns/masternode_stats.rs | 32 -- lib/ain-ocean/src/storage/columns/mod.rs | 88 --- lib/ain-ocean/src/storage/columns/oracle.rs | 19 - .../src/storage/columns/oracle_history.rs | 33 -- .../storage/columns/oracle_price_active.rs | 33 -- .../columns/oracle_price_aggregated.rs | 32 -- .../oracle_price_aggregated_interval.rs | 33 -- .../src/storage/columns/oracle_price_feed.rs | 33 -- .../storage/columns/oracle_token_currency.rs | 31 -- .../src/storage/columns/pool_swap.rs | 18 - .../storage/columns/pool_swap_aggregated.rs | 101 ---- lib/ain-ocean/src/storage/columns/poolpair.rs | 31 -- .../src/storage/columns/price_ticker.rs | 65 --- .../src/storage/columns/raw_block.rs | 17 - .../src/storage/columns/script_activity.rs | 17 - .../src/storage/columns/script_aggregation.rs | 17 - .../src/storage/columns/script_unspent.rs | 32 -- .../src/storage/columns/transaction.rs | 54 -- .../src/storage/columns/transaction_vin.rs | 18 - .../src/storage/columns/transaction_vout.rs | 40 -- .../src/storage/columns/tx_result.rs | 19 - .../storage/columns/vault_auction_history.rs | 34 -- lib/ain-ocean/src/storage/macros.rs | 109 ++++ lib/ain-ocean/src/storage/mod.rs | 513 +++++++++++++++++- lib/ain-ocean/src/storage/ocean_store.rs | 2 +- 81 files changed, 753 insertions(+), 2305 deletions(-) delete mode 100644 lib/ain-ocean/src/repository/block.rs delete mode 100644 lib/ain-ocean/src/repository/masternode.rs delete mode 100644 lib/ain-ocean/src/repository/masternode_stats.rs delete mode 100644 lib/ain-ocean/src/repository/mod.rs delete mode 100644 lib/ain-ocean/src/repository/oracle.rs delete mode 100644 lib/ain-ocean/src/repository/oracle_history.rs delete mode 100644 lib/ain-ocean/src/repository/oracle_price_active.rs delete mode 100644 lib/ain-ocean/src/repository/oracle_price_aggregated.rs delete mode 100644 lib/ain-ocean/src/repository/oracle_price_aggregated_interval.rs delete mode 100644 lib/ain-ocean/src/repository/oracle_price_feed.rs delete mode 100644 lib/ain-ocean/src/repository/oracle_token_currency.rs delete mode 100644 lib/ain-ocean/src/repository/pool_swap.rs delete mode 100644 lib/ain-ocean/src/repository/pool_swap_aggregated.rs delete mode 100644 lib/ain-ocean/src/repository/poolpair.rs delete mode 100644 lib/ain-ocean/src/repository/price_ticker.rs delete mode 100644 lib/ain-ocean/src/repository/raw_block.rs delete mode 100644 lib/ain-ocean/src/repository/script_activity.rs delete mode 100644 lib/ain-ocean/src/repository/script_aggregation.rs delete mode 100644 lib/ain-ocean/src/repository/script_unspent.rs delete mode 100644 lib/ain-ocean/src/repository/test/block_test.rs delete mode 100644 lib/ain-ocean/src/repository/test/masternode_test.rs delete mode 100644 lib/ain-ocean/src/repository/test/mod.rs delete mode 100644 lib/ain-ocean/src/repository/test/oracle_test.rs delete mode 100644 lib/ain-ocean/src/repository/test/transaction_test.rs delete mode 100644 lib/ain-ocean/src/repository/transaction.rs delete mode 100644 lib/ain-ocean/src/repository/transaction_vin.rs delete mode 100644 lib/ain-ocean/src/repository/transaction_vout.rs delete mode 100644 lib/ain-ocean/src/repository/tx_result.rs delete mode 100644 lib/ain-ocean/src/repository/vault_auction_batch_history.rs delete mode 100644 lib/ain-ocean/src/storage/columns/block.rs delete mode 100644 lib/ain-ocean/src/storage/columns/masternode.rs delete mode 100644 lib/ain-ocean/src/storage/columns/masternode_stats.rs delete mode 100644 lib/ain-ocean/src/storage/columns/mod.rs delete mode 100644 lib/ain-ocean/src/storage/columns/oracle.rs delete mode 100644 lib/ain-ocean/src/storage/columns/oracle_history.rs delete mode 100644 lib/ain-ocean/src/storage/columns/oracle_price_active.rs delete mode 100644 lib/ain-ocean/src/storage/columns/oracle_price_aggregated.rs delete mode 100644 lib/ain-ocean/src/storage/columns/oracle_price_aggregated_interval.rs delete mode 100644 lib/ain-ocean/src/storage/columns/oracle_price_feed.rs delete mode 100644 lib/ain-ocean/src/storage/columns/oracle_token_currency.rs delete mode 100644 lib/ain-ocean/src/storage/columns/pool_swap.rs delete mode 100644 lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs delete mode 100644 lib/ain-ocean/src/storage/columns/poolpair.rs delete mode 100644 lib/ain-ocean/src/storage/columns/price_ticker.rs delete mode 100644 lib/ain-ocean/src/storage/columns/raw_block.rs delete mode 100644 lib/ain-ocean/src/storage/columns/script_activity.rs delete mode 100644 lib/ain-ocean/src/storage/columns/script_aggregation.rs delete mode 100644 lib/ain-ocean/src/storage/columns/script_unspent.rs delete mode 100644 lib/ain-ocean/src/storage/columns/transaction.rs delete mode 100644 lib/ain-ocean/src/storage/columns/transaction_vin.rs delete mode 100644 lib/ain-ocean/src/storage/columns/transaction_vout.rs delete mode 100644 lib/ain-ocean/src/storage/columns/tx_result.rs delete mode 100644 lib/ain-ocean/src/storage/columns/vault_auction_history.rs create mode 100644 lib/ain-ocean/src/storage/macros.rs diff --git a/lib/ain-ocean/src/api/address.rs b/lib/ain-ocean/src/api/address.rs index 24bc4b82aeb..68aa8f27b10 100644 --- a/lib/ain-ocean/src/api/address.rs +++ b/lib/ain-ocean/src/api/address.rs @@ -1,5 +1,17 @@ use std::{collections::BTreeMap, str::FromStr, sync::Arc}; +use ain_macros::ocean_endpoint; +use anyhow::Context; +use axum::{routing::get, Extension, Router}; +use bitcoin::{hashes::Hash, hex::DisplayHex, BlockHash, Txid}; +use defichain_rpc::{ + json::{account::AccountHistory, vault::ListVaultOptions}, + AccountRPC, RpcApi, +}; +use serde::{Deserialize, Serialize}; +use serde_json::json; +use serde_with::skip_serializing_none; + use super::{ cache::get_token_cached, common::{address_to_hid, parse_display_symbol}, @@ -14,21 +26,9 @@ use crate::{ model::{ BlockContext, ScriptActivity, ScriptActivityTypeHex, ScriptAggregation, ScriptUnspent, }, - repository::RepositoryOps, - storage::SortOrder, + storage::{RepositoryOps, SortOrder}, Error, Result, }; -use ain_macros::ocean_endpoint; -use anyhow::Context; -use axum::{routing::get, Extension, Router}; -use bitcoin::{hashes::Hash, hex::DisplayHex, BlockHash, Txid}; -use defichain_rpc::{ - json::{account::AccountHistory, vault::ListVaultOptions}, - AccountRPC, RpcApi, -}; -use serde::{Deserialize, Serialize}; -use serde_json::json; -use serde_with::skip_serializing_none; #[derive(Deserialize)] struct Address { diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 419bf896eaa..927985425e8 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -18,10 +18,9 @@ use crate::{ api::common::Paginate, error::{ApiError, Error}, model::{Block, BlockContext, Transaction}, - repository::{ - InitialKeyProvider, RepositoryOps, SecondaryIndex, TransactionByBlockHashRepository, + storage::{ + InitialKeyProvider, RepositoryOps, SecondaryIndex, SortOrder, TransactionByBlockHash, }, - storage::SortOrder, Result, }; @@ -137,13 +136,13 @@ async fn get_transactions( ) -> Result> { let repository = &ctx.services.transaction.by_block_hash; - let next = query.next.as_ref().map_or( - Ok(TransactionByBlockHashRepository::initial_key(hash)), - |q| { + let next = query + .next + .as_ref() + .map_or(Ok(TransactionByBlockHash::initial_key(hash)), |q| { let height = q.parse::().context("Invalid height")?; Ok::<(BlockHash, usize), Error>((hash, height)) - }, - )?; + })?; let txs = repository .list(Some(next), SortOrder::Ascending)? diff --git a/lib/ain-ocean/src/api/common.rs b/lib/ain-ocean/src/api/common.rs index b7636680104..5d06eecf7cd 100644 --- a/lib/ain-ocean/src/api/common.rs +++ b/lib/ain-ocean/src/api/common.rs @@ -1,13 +1,13 @@ +use std::str::FromStr; + use anyhow::Context; use bitcoin::{Address, Network, ScriptBuf}; use defichain_rpc::json::token::TokenInfo; use rust_decimal::Decimal; use rust_decimal_macros::dec; -use std::str::FromStr; - -use crate::hex_encoder::as_sha256; use super::query::PaginationQuery; +use crate::hex_encoder::as_sha256; pub fn parse_display_symbol(token_info: &TokenInfo) -> String { if token_info.is_lps { diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index fc9a1cd0caa..6f97bb90b28 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -33,8 +33,7 @@ use crate::{ api::prices::PriceTickerResponse, error::{ApiError, Error}, model::{OraclePriceActive, VaultAuctionBatchHistory}, - repository::{RepositoryOps, SecondaryIndex}, - storage::SortOrder, + storage::{RepositoryOps, SecondaryIndex, SortOrder}, Result, }; diff --git a/lib/ain-ocean/src/api/masternode/mod.rs b/lib/ain-ocean/src/api/masternode/mod.rs index 4716fe28277..fc0509dded2 100644 --- a/lib/ain-ocean/src/api/masternode/mod.rs +++ b/lib/ain-ocean/src/api/masternode/mod.rs @@ -22,9 +22,8 @@ use crate::{ api::common::Paginate, error::{ApiError, Error, NotFoundKind}, model::Masternode, - repository::{RepositoryOps, SecondaryIndex}, - storage::SortOrder, - Result, + storage::{RepositoryOps, SortOrder}, + Result, SecondaryIndex, }; #[derive(Serialize, Deserialize, Debug, Clone)] diff --git a/lib/ain-ocean/src/api/oracle.rs b/lib/ain-ocean/src/api/oracle.rs index 0fe62f74153..6c9524f41e4 100644 --- a/lib/ain-ocean/src/api/oracle.rs +++ b/lib/ain-ocean/src/api/oracle.rs @@ -21,8 +21,7 @@ use crate::{ api::common::Paginate, error::{ApiError, Error, NotFoundKind}, model::{ApiResponseOraclePriceFeed, Oracle}, - repository::RepositoryOps, - storage::SortOrder, + storage::{RepositoryOps, SortOrder}, Result, }; diff --git a/lib/ain-ocean/src/api/pool_pair/mod.rs b/lib/ain-ocean/src/api/pool_pair/mod.rs index 6b74769cc0c..fd7f1778341 100644 --- a/lib/ain-ocean/src/api/pool_pair/mod.rs +++ b/lib/ain-ocean/src/api/pool_pair/mod.rs @@ -37,9 +37,8 @@ use super::{ use crate::{ error::{ApiError, Error, NotFoundKind}, model::{BlockContext, PoolSwap, PoolSwapAggregated}, - repository::{InitialKeyProvider, PoolSwapRepository, RepositoryOps, SecondaryIndex}, - storage::SortOrder, - Result, TokenIdentifier, + storage::{InitialKeyProvider, RepositoryOps, SecondaryIndex, SortOrder}, + PoolSwap as PoolSwapRepository, Result, TokenIdentifier, }; pub mod path; diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index 6bdcd3fe110..c7202083a5f 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -18,8 +18,7 @@ use crate::{ error::{Error, NotFoundKind}, indexer::PoolSwapAggregatedInterval, model::{BlockContext, PoolSwapAggregatedAggregated}, - repository::{RepositoryOps, SecondaryIndex}, - storage::SortOrder, + storage::{RepositoryOps, SecondaryIndex, SortOrder}, Result, }; diff --git a/lib/ain-ocean/src/api/prices.rs b/lib/ain-ocean/src/api/prices.rs index 50b2ebaeaf4..0143e8be700 100644 --- a/lib/ain-ocean/src/api/prices.rs +++ b/lib/ain-ocean/src/api/prices.rs @@ -25,8 +25,7 @@ use crate::{ OraclePriceActiveNextOracles, OraclePriceAggregated, OraclePriceAggregatedInterval, OraclePriceAggregatedIntervalAggregated, OracleTokenCurrency, PriceOracles, PriceTicker, }, - repository::RepositoryOps, - storage::SortOrder, + storage::{RepositoryOps, SortOrder}, Result, }; diff --git a/lib/ain-ocean/src/api/stats/cache.rs b/lib/ain-ocean/src/api/stats/cache.rs index 8006e38f267..01181154c44 100644 --- a/lib/ain-ocean/src/api/stats/cache.rs +++ b/lib/ain-ocean/src/api/stats/cache.rs @@ -23,8 +23,7 @@ use crate::{ AppContext, }, model::MasternodeStatsData, - repository::RepositoryOps, - storage::SortOrder, + storage::{RepositoryOps, SortOrder}, Error, Result, }; diff --git a/lib/ain-ocean/src/api/transactions.rs b/lib/ain-ocean/src/api/transactions.rs index 262c75c8240..f79d0b9327f 100644 --- a/lib/ain-ocean/src/api/transactions.rs +++ b/lib/ain-ocean/src/api/transactions.rs @@ -10,8 +10,9 @@ use crate::{ api::{common::Paginate, response::Response}, error::ApiError, model::{Transaction, TransactionVin, TransactionVout}, - repository::{InitialKeyProvider, RepositoryOps, TransactionVinRepository}, - storage::SortOrder, + storage::{ + InitialKeyProvider, RepositoryOps, SortOrder, TransactionVin as TransactionVinStorage, + }, Result, }; @@ -39,7 +40,7 @@ async fn get_vins( let next = query .next .clone() - .unwrap_or(TransactionVinRepository::initial_key(id)); + .unwrap_or(TransactionVinStorage::initial_key(id)); let list = ctx .services diff --git a/lib/ain-ocean/src/indexer/auction.rs b/lib/ain-ocean/src/indexer/auction.rs index 5c8683764c2..c95b612519d 100644 --- a/lib/ain-ocean/src/indexer/auction.rs +++ b/lib/ain-ocean/src/indexer/auction.rs @@ -7,7 +7,7 @@ use super::Context; use crate::{ indexer::{Index, Result}, model::VaultAuctionBatchHistory, - repository::RepositoryOps, + storage::RepositoryOps, Services, }; diff --git a/lib/ain-ocean/src/indexer/loan_token.rs b/lib/ain-ocean/src/indexer/loan_token.rs index 01613e81b9f..e2a809e6d72 100644 --- a/lib/ain-ocean/src/indexer/loan_token.rs +++ b/lib/ain-ocean/src/indexer/loan_token.rs @@ -8,8 +8,7 @@ use crate::{ indexer::{Context, Index, Result}, model::{BlockContext, OraclePriceActive, OraclePriceActiveNext, OraclePriceAggregated}, network::Network, - repository::RepositoryOps, - storage::SortOrder, + storage::{RepositoryOps, SortOrder}, Services, }; diff --git a/lib/ain-ocean/src/indexer/masternode.rs b/lib/ain-ocean/src/indexer/masternode.rs index eadaae81f80..2ca314c88d7 100644 --- a/lib/ain-ocean/src/indexer/masternode.rs +++ b/lib/ain-ocean/src/indexer/masternode.rs @@ -10,7 +10,7 @@ use crate::{ error::Error, indexer::{Index, Result}, model::{HistoryItem, Masternode, MasternodeStats, MasternodeStatsData, TimelockStats}, - repository::RepositoryOps, + storage::RepositoryOps, Services, }; diff --git a/lib/ain-ocean/src/indexer/mod.rs b/lib/ain-ocean/src/indexer/mod.rs index 9459aced9ca..8729be39277 100644 --- a/lib/ain-ocean/src/indexer/mod.rs +++ b/lib/ain-ocean/src/indexer/mod.rs @@ -30,8 +30,7 @@ use crate::{ ScriptAggregationScript, ScriptAggregationStatistic, ScriptUnspent, ScriptUnspentScript, ScriptUnspentVout, TransactionVout, TransactionVoutScript, }, - repository::{RepositoryOps, SecondaryIndex}, - storage::SortOrder, + storage::{RepositoryOps, SecondaryIndex, SortOrder}, Error, Result, Services, }; diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index 4f38baa43f4..79f99be2317 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -18,8 +18,7 @@ use crate::{ OraclePriceAggregatedIntervalAggregated, OraclePriceAggregatedIntervalAggregatedOracles, OraclePriceFeed, OracleTokenCurrency, PriceFeedsItem, PriceTicker, }, - repository::RepositoryOps, - storage::SortOrder, + storage::{RepositoryOps, SortOrder}, Error, Services, }; diff --git a/lib/ain-ocean/src/indexer/oracle_test.rs b/lib/ain-ocean/src/indexer/oracle_test.rs index 57cf171015d..efdfd118069 100644 --- a/lib/ain-ocean/src/indexer/oracle_test.rs +++ b/lib/ain-ocean/src/indexer/oracle_test.rs @@ -15,8 +15,7 @@ mod tests { use crate::{ indexer::{Context, Index}, model::{BlockContext, Oracle, OraclePriceFeed, OracleTokenCurrency, PriceFeedsItem}, - repository::RepositoryOps, - storage::{ocean_store, SortOrder}, + storage::{OceanStore, RepositoryOps, SortOrder}, Services, }; @@ -25,7 +24,7 @@ mod tests { // Setup the temporary storage for testing let temp_dir = tempdir().expect("Failed to create temporary directory"); let path = temp_dir.path(); - let ocean_store_result = ocean_store::OceanStore::new(path); + let ocean_store_result = OceanStore::new(path); let ocean_store = match ocean_store_result { Ok(store) => Arc::new(store), Err(error) => panic!("Failed to create OceanStore: {}", error), @@ -93,7 +92,7 @@ mod tests { // Setup the temporary storage for testing let temp_dir = tempdir().expect("Failed to create temporary directory"); let path = temp_dir.path(); - let ocean_store_result = ocean_store::OceanStore::new(path); + let ocean_store_result = OceanStore::new(path); let ocean_store = match ocean_store_result { Ok(store) => Arc::new(store), Err(error) => panic!("Failed to create OceanStore: {}", error), @@ -206,7 +205,7 @@ mod tests { // Setup the temporary storage for testing let temp_dir = tempdir().expect("Failed to create temporary directory"); let path = temp_dir.path(); - let ocean_store_result = ocean_store::OceanStore::new(path); + let ocean_store_result = OceanStore::new(path); let ocean_store = match ocean_store_result { Ok(store) => Arc::new(store), Err(error) => panic!("Failed to create OceanStore: {}", error), @@ -426,7 +425,7 @@ mod tests { // Setup the temporary storage for testing let temp_dir = tempdir().expect("Failed to create temporary directory"); let path = temp_dir.path(); - let ocean_store_result = ocean_store::OceanStore::new(path); + let ocean_store_result = OceanStore::new(path); let ocean_store = match ocean_store_result { Ok(store) => Arc::new(store), Err(error) => panic!("Failed to create OceanStore: {}", error), @@ -645,7 +644,7 @@ mod tests { fn test_index_set_oracle_oracle() { let temp_dir = tempdir().expect("Failed to create temporary directory"); let path = temp_dir.path(); - let ocean_store_result = ocean_store::OceanStore::new(path); + let ocean_store_result = OceanStore::new(path); let ocean_store = match ocean_store_result { Ok(ocean_store) => Arc::new(ocean_store), Err(error) => { @@ -1002,7 +1001,7 @@ mod tests { fn test_index_appoint_oracle() { let temp_dir = tempdir().expect("Failed to create temporary directory"); let path = temp_dir.path(); - let ocean_store_result = ocean_store::OceanStore::new(path); + let ocean_store_result = OceanStore::new(path); let ocean_store = match ocean_store_result { Ok(ocean_store) => Arc::new(ocean_store), Err(error) => { diff --git a/lib/ain-ocean/src/indexer/poolpair.rs b/lib/ain-ocean/src/indexer/poolpair.rs index eea4d65d151..5620870ff1a 100644 --- a/lib/ain-ocean/src/indexer/poolpair.rs +++ b/lib/ain-ocean/src/indexer/poolpair.rs @@ -6,7 +6,7 @@ use log::debug; use crate::{ indexer::{Context, Index, Result}, model::TxResult, - repository::RepositoryOps, + storage::RepositoryOps, Services, }; diff --git a/lib/ain-ocean/src/indexer/poolswap.rs b/lib/ain-ocean/src/indexer/poolswap.rs index e2007458096..369ea747ed6 100644 --- a/lib/ain-ocean/src/indexer/poolswap.rs +++ b/lib/ain-ocean/src/indexer/poolswap.rs @@ -12,8 +12,7 @@ use super::Context; use crate::{ indexer::{tx_result, Index, Result}, model::{self, PoolSwapResult, TxResult}, - repository::{RepositoryOps, SecondaryIndex}, - storage::SortOrder, + storage::{RepositoryOps, SecondaryIndex, SortOrder}, Error, Services, }; diff --git a/lib/ain-ocean/src/indexer/transaction.rs b/lib/ain-ocean/src/indexer/transaction.rs index 42cb4f19c86..dcd84c6dccd 100644 --- a/lib/ain-ocean/src/indexer/transaction.rs +++ b/lib/ain-ocean/src/indexer/transaction.rs @@ -13,7 +13,7 @@ use crate::{ model::{ Transaction as TransactionMapper, TransactionVin, TransactionVout, TransactionVoutScript, }, - repository::RepositoryOps, + storage::RepositoryOps, Services, }; diff --git a/lib/ain-ocean/src/indexer/tx_result.rs b/lib/ain-ocean/src/indexer/tx_result.rs index 2b3b3e5711f..2cdfc4d157c 100644 --- a/lib/ain-ocean/src/indexer/tx_result.rs +++ b/lib/ain-ocean/src/indexer/tx_result.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use bitcoin::{hashes::Hash, Txid}; -use crate::{model::TxResult, repository::RepositoryOps, Result, Services}; +use crate::{model::TxResult, storage::RepositoryOps, Result, Services}; pub fn index( services: &Arc, diff --git a/lib/ain-ocean/src/lib.rs b/lib/ain-ocean/src/lib.rs index 0635c85bcb3..ab62d026436 100644 --- a/lib/ain-ocean/src/lib.rs +++ b/lib/ain-ocean/src/lib.rs @@ -2,6 +2,7 @@ pub mod error; pub mod hex_encoder; mod indexer; pub mod network; +mod storage; use std::{path::PathBuf, sync::Arc}; @@ -13,28 +14,11 @@ pub use indexer::{ }; use parking_lot::Mutex; use petgraph::graphmap::UnGraphMap; -use repository::{ - AuctionHistoryByHeightRepository, AuctionHistoryRepository, BlockByHeightRepository, - BlockRepository, MasternodeByHeightRepository, MasternodeRepository, MasternodeStatsRepository, - OracleHistoryRepository, OracleHistoryRepositoryKey, OraclePriceActiveKeyRepository, - OraclePriceActiveRepository, OraclePriceAggregatedIntervalKeyRepository, - OraclePriceAggregatedIntervalRepository, OraclePriceAggregatedRepository, - OraclePriceAggregatedRepositoryKey, OraclePriceFeedKeyRepository, OraclePriceFeedRepository, - OracleRepository, OracleTokenCurrencyKeyRepository, OracleTokenCurrencyRepository, - PoolPairByHeightRepository, PoolPairRepository, PoolSwapAggregatedKeyRepository, - PoolSwapAggregatedRepository, PoolSwapRepository, PriceTickerKeyRepository, - PriceTickerRepository, RawBlockRepository, ScriptActivityRepository, - ScriptAggregationRepository, ScriptUnspentKeyRepository, ScriptUnspentRepository, - TransactionByBlockHashRepository, TransactionRepository, TransactionVinRepository, - TransactionVoutRepository, TxResultRepository, -}; use serde::Serialize; pub mod api; mod model; -mod repository; -pub mod storage; -use crate::storage::ocean_store::OceanStore; +use storage::*; pub type Result = std::result::Result; @@ -49,89 +33,89 @@ lazy_static::lazy_static! { } pub struct MasternodeService { - pub by_id: MasternodeRepository, - pub by_height: MasternodeByHeightRepository, - pub stats: MasternodeStatsRepository, + pub by_id: Masternode, + pub by_height: MasternodeByHeight, + pub stats: MasternodeStats, } pub struct BlockService { - pub raw: RawBlockRepository, - pub by_id: BlockRepository, - pub by_height: BlockByHeightRepository, + pub raw: RawBlock, + pub by_id: Block, + pub by_height: BlockByHeight, } pub struct AuctionService { - by_id: AuctionHistoryRepository, - by_height: AuctionHistoryByHeightRepository, + by_id: VaultAuctionHistory, + by_height: VaultAuctionHistoryByHeight, } pub struct PoolService { - by_id: PoolSwapRepository, + by_id: PoolSwap, } pub struct PoolPairService { - by_height: PoolPairByHeightRepository, - by_id: PoolPairRepository, + by_height: PoolPairByHeight, + by_id: PoolPair, } pub struct PoolSwapAggregatedService { - by_id: PoolSwapAggregatedRepository, - by_key: PoolSwapAggregatedKeyRepository, + by_id: PoolSwapAggregated, + by_key: PoolSwapAggregatedKey, } pub struct TransactionService { - by_id: TransactionRepository, - by_block_hash: TransactionByBlockHashRepository, - vin_by_id: TransactionVinRepository, - vout_by_id: TransactionVoutRepository, + by_id: Transaction, + by_block_hash: TransactionByBlockHash, + vin_by_id: TransactionVin, + vout_by_id: TransactionVout, } pub struct OracleService { - by_id: OracleRepository, + by_id: Oracle, } pub struct OraclePriceFeedService { - by_key: OraclePriceFeedKeyRepository, - by_id: OraclePriceFeedRepository, + by_key: OraclePriceFeedKey, + by_id: OraclePriceFeed, } pub struct OraclePriceActiveService { - by_key: OraclePriceActiveKeyRepository, - by_id: OraclePriceActiveRepository, + by_key: OraclePriceActiveKey, + by_id: OraclePriceActive, } pub struct OraclePriceAggregatedIntervalService { - by_key: OraclePriceAggregatedIntervalKeyRepository, - by_id: OraclePriceAggregatedIntervalRepository, + by_key: OraclePriceAggregatedIntervalKey, + by_id: OraclePriceAggregatedInterval, } pub struct OraclePriceAggregatedService { - by_key: OraclePriceAggregatedRepositoryKey, - by_id: OraclePriceAggregatedRepository, + by_key: OraclePriceAggregatedKey, + by_id: OraclePriceAggregated, } pub struct OracleTokenCurrencyService { - by_key: OracleTokenCurrencyKeyRepository, - by_id: OracleTokenCurrencyRepository, + by_key: OracleTokenCurrencyKey, + by_id: OracleTokenCurrency, } pub struct OracleHistoryService { - by_id: OracleHistoryRepository, - by_key: OracleHistoryRepositoryKey, + by_id: OracleHistory, + by_key: OracleHistoryOracleIdSort, } pub struct PriceTickerService { - by_id: PriceTickerRepository, - by_key: PriceTickerKeyRepository, + by_id: PriceTicker, + by_key: PriceTickerKey, } pub struct ScriptActivityService { - by_id: ScriptActivityRepository, + by_id: ScriptActivity, } pub struct ScriptAggregationService { - by_id: ScriptAggregationRepository, + by_id: ScriptAggregation, } pub struct ScriptUnspentService { - by_id: ScriptUnspentRepository, - by_key: ScriptUnspentKeyRepository, + by_id: ScriptUnspent, + by_key: ScriptUnspentKey, } #[derive(Clone, Debug, Serialize, Eq, PartialEq, Hash)] @@ -147,7 +131,7 @@ pub struct Services { pub masternode: MasternodeService, pub block: BlockService, pub auction: AuctionService, - pub result: TxResultRepository, + pub result: TxResult, pub pool: PoolService, pub poolpair: PoolPairService, pub pool_swap_aggregated: PoolSwapAggregatedService, @@ -170,77 +154,77 @@ impl Services { pub fn new(store: Arc) -> Self { Self { masternode: MasternodeService { - by_id: MasternodeRepository::new(Arc::clone(&store)), - by_height: MasternodeByHeightRepository::new(Arc::clone(&store)), - stats: MasternodeStatsRepository::new(Arc::clone(&store)), + by_id: Masternode::new(Arc::clone(&store)), + by_height: MasternodeByHeight::new(Arc::clone(&store)), + stats: MasternodeStats::new(Arc::clone(&store)), }, block: BlockService { - raw: RawBlockRepository::new(Arc::clone(&store)), - by_id: BlockRepository::new(Arc::clone(&store)), - by_height: BlockByHeightRepository::new(Arc::clone(&store)), + raw: RawBlock::new(Arc::clone(&store)), + by_id: Block::new(Arc::clone(&store)), + by_height: BlockByHeight::new(Arc::clone(&store)), }, auction: AuctionService { - by_id: AuctionHistoryRepository::new(Arc::clone(&store)), - by_height: AuctionHistoryByHeightRepository::new(Arc::clone(&store)), + by_id: VaultAuctionHistory::new(Arc::clone(&store)), + by_height: VaultAuctionHistoryByHeight::new(Arc::clone(&store)), }, - result: TxResultRepository::new(Arc::clone(&store)), + result: TxResult::new(Arc::clone(&store)), poolpair: PoolPairService { - by_height: PoolPairByHeightRepository::new(Arc::clone(&store)), - by_id: PoolPairRepository::new(Arc::clone(&store)), + by_height: PoolPairByHeight::new(Arc::clone(&store)), + by_id: PoolPair::new(Arc::clone(&store)), }, pool: PoolService { - by_id: PoolSwapRepository::new(Arc::clone(&store)), + by_id: PoolSwap::new(Arc::clone(&store)), }, pool_swap_aggregated: PoolSwapAggregatedService { - by_id: PoolSwapAggregatedRepository::new(Arc::clone(&store)), - by_key: PoolSwapAggregatedKeyRepository::new(Arc::clone(&store)), + by_id: PoolSwapAggregated::new(Arc::clone(&store)), + by_key: PoolSwapAggregatedKey::new(Arc::clone(&store)), }, transaction: TransactionService { - by_id: TransactionRepository::new(Arc::clone(&store)), - by_block_hash: TransactionByBlockHashRepository::new(Arc::clone(&store)), - vin_by_id: TransactionVinRepository::new(Arc::clone(&store)), - vout_by_id: TransactionVoutRepository::new(Arc::clone(&store)), + by_id: Transaction::new(Arc::clone(&store)), + by_block_hash: TransactionByBlockHash::new(Arc::clone(&store)), + vin_by_id: TransactionVin::new(Arc::clone(&store)), + vout_by_id: TransactionVout::new(Arc::clone(&store)), }, oracle: OracleService { - by_id: OracleRepository::new(Arc::clone(&store)), + by_id: Oracle::new(Arc::clone(&store)), }, oracle_price_feed: OraclePriceFeedService { - by_key: OraclePriceFeedKeyRepository::new(Arc::clone(&store)), - by_id: OraclePriceFeedRepository::new(Arc::clone(&store)), + by_key: OraclePriceFeedKey::new(Arc::clone(&store)), + by_id: OraclePriceFeed::new(Arc::clone(&store)), }, oracle_price_active: OraclePriceActiveService { - by_key: OraclePriceActiveKeyRepository::new(Arc::clone(&store)), - by_id: OraclePriceActiveRepository::new(Arc::clone(&store)), + by_key: OraclePriceActiveKey::new(Arc::clone(&store)), + by_id: OraclePriceActive::new(Arc::clone(&store)), }, oracle_price_aggregated_interval: OraclePriceAggregatedIntervalService { - by_key: OraclePriceAggregatedIntervalKeyRepository::new(Arc::clone(&store)), - by_id: OraclePriceAggregatedIntervalRepository::new(Arc::clone(&store)), + by_key: OraclePriceAggregatedIntervalKey::new(Arc::clone(&store)), + by_id: OraclePriceAggregatedInterval::new(Arc::clone(&store)), }, oracle_price_aggregated: OraclePriceAggregatedService { - by_key: OraclePriceAggregatedRepositoryKey::new(Arc::clone(&store)), - by_id: OraclePriceAggregatedRepository::new(Arc::clone(&store)), + by_key: OraclePriceAggregatedKey::new(Arc::clone(&store)), + by_id: OraclePriceAggregated::new(Arc::clone(&store)), }, oracle_token_currency: OracleTokenCurrencyService { - by_key: OracleTokenCurrencyKeyRepository::new(Arc::clone(&store)), - by_id: OracleTokenCurrencyRepository::new(Arc::clone(&store)), + by_key: OracleTokenCurrencyKey::new(Arc::clone(&store)), + by_id: OracleTokenCurrency::new(Arc::clone(&store)), }, oracle_history: OracleHistoryService { - by_id: OracleHistoryRepository::new(Arc::clone(&store)), - by_key: OracleHistoryRepositoryKey::new(Arc::clone(&store)), + by_id: OracleHistory::new(Arc::clone(&store)), + by_key: OracleHistoryOracleIdSort::new(Arc::clone(&store)), }, price_ticker: PriceTickerService { - by_id: PriceTickerRepository::new_id(Arc::clone(&store)), - by_key: PriceTickerKeyRepository::new_key(Arc::clone(&store)), + by_id: PriceTicker::new(Arc::clone(&store)), + by_key: PriceTickerKey::new(Arc::clone(&store)), }, script_activity: ScriptActivityService { - by_id: ScriptActivityRepository::new(Arc::clone(&store)), + by_id: ScriptActivity::new(Arc::clone(&store)), }, script_aggregation: ScriptAggregationService { - by_id: ScriptAggregationRepository::new(Arc::clone(&store)), + by_id: ScriptAggregation::new(Arc::clone(&store)), }, script_unspent: ScriptUnspentService { - by_id: ScriptUnspentRepository::new(Arc::clone(&store)), - by_key: ScriptUnspentKeyRepository::new(Arc::clone(&store)), + by_id: ScriptUnspent::new(Arc::clone(&store)), + by_key: ScriptUnspentKey::new(Arc::clone(&store)), }, token_graph: Arc::new(Mutex::new(UnGraphMap::new())), } diff --git a/lib/ain-ocean/src/model/masternode.rs b/lib/ain-ocean/src/model/masternode.rs index a16f9c10f1c..bc4ffad00fe 100644 --- a/lib/ain-ocean/src/model/masternode.rs +++ b/lib/ain-ocean/src/model/masternode.rs @@ -6,7 +6,7 @@ use super::BlockContext; #[derive(Debug, Serialize, Deserialize)] pub struct Masternode { - pub id: Txid, // Keep for backward compatibility + pub id: Txid, pub owner_address: String, pub operator_address: String, pub creation_height: u32, diff --git a/lib/ain-ocean/src/model/script_activity.rs b/lib/ain-ocean/src/model/script_activity.rs index e8dbb75ebdb..a0bfb435d9e 100644 --- a/lib/ain-ocean/src/model/script_activity.rs +++ b/lib/ain-ocean/src/model/script_activity.rs @@ -1,6 +1,7 @@ +use std::fmt; + use bitcoin::Txid; use serde::{Deserialize, Serialize}; -use std::fmt; use super::BlockContext; #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)] diff --git a/lib/ain-ocean/src/model/script_unspent.rs b/lib/ain-ocean/src/model/script_unspent.rs index a5d7c934f2d..53422d0f8cc 100644 --- a/lib/ain-ocean/src/model/script_unspent.rs +++ b/lib/ain-ocean/src/model/script_unspent.rs @@ -1,7 +1,8 @@ -use super::BlockContext; use bitcoin::Txid; use serde::{Deserialize, Serialize}; +use super::BlockContext; + pub type ScriptUnspentId = (String, String, Txid, String); // hid + hex::encode(block.height) + txid + hex::encode(vout_index) pub type ScriptUnspentKey = (u32, Txid, usize); // block.height + txid + vout_index diff --git a/lib/ain-ocean/src/repository/block.rs b/lib/ain-ocean/src/repository/block.rs deleted file mode 100644 index 691632795e5..00000000000 --- a/lib/ain-ocean/src/repository/block.rs +++ /dev/null @@ -1,52 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; -use bitcoin::BlockHash; - -use super::{RepositoryOps, SecondaryIndex}; -use crate::{ - model::Block, - storage::{columns, ocean_store::OceanStore, SortOrder}, - Error, Result, -}; - -#[derive(Repository)] -#[repository(K = "BlockHash", V = "Block")] -pub struct BlockRepository { - pub store: Arc, - col: LedgerColumn, -} - -#[derive(Repository)] -#[repository(K = "u32", V = "BlockHash")] -pub struct BlockByHeightRepository { - pub store: Arc, - col: LedgerColumn, -} - -impl BlockByHeightRepository { - pub fn get_highest(&self) -> Result> { - match self.col.iter(None, SortOrder::Descending.into())?.next() { - None => Ok(None), - Some(Ok((_, id))) => { - let col = self.store.column::(); - Ok(col.get(&id)?) - } - Some(Err(e)) => Err(e.into()), - } - } -} - -impl SecondaryIndex for BlockByHeightRepository { - type Value = Block; - - fn retrieve_primary_value(&self, el: Self::ListItem) -> Result { - let (_, id) = el?; - - let col = self.store.column::(); - let tx = col.get(&id)?.ok_or(Error::SecondaryIndex)?; - - Ok(tx) - } -} diff --git a/lib/ain-ocean/src/repository/masternode.rs b/lib/ain-ocean/src/repository/masternode.rs deleted file mode 100644 index 1f8ce1a72e0..00000000000 --- a/lib/ain-ocean/src/repository/masternode.rs +++ /dev/null @@ -1,39 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; -use bitcoin::Txid; - -use super::{RepositoryOps, SecondaryIndex}; -use crate::{ - model::Masternode, - storage::{columns, ocean_store::OceanStore}, - Error, Result, -}; - -#[derive(Repository)] -#[repository(K = "Txid", V = "Masternode")] -pub struct MasternodeRepository { - pub store: Arc, - col: LedgerColumn, -} - -type MasternodeByHeightKey = (u32, Txid); - -#[derive(Repository)] -#[repository(K = "MasternodeByHeightKey", V = "u8")] -pub struct MasternodeByHeightRepository { - pub store: Arc, - col: LedgerColumn, -} - -impl SecondaryIndex for MasternodeByHeightRepository { - type Value = Masternode; - - fn retrieve_primary_value(&self, el: Self::ListItem) -> Result { - let ((_, id), _) = el?; - let col = self.store.column::(); - let tx = col.get(&id)?.ok_or(Error::SecondaryIndex)?; - Ok(tx) - } -} diff --git a/lib/ain-ocean/src/repository/masternode_stats.rs b/lib/ain-ocean/src/repository/masternode_stats.rs deleted file mode 100644 index 3605b3f1471..00000000000 --- a/lib/ain-ocean/src/repository/masternode_stats.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; - -use super::RepositoryOps; -use crate::{ - model::MasternodeStats, - storage::{columns, ocean_store::OceanStore, SortOrder}, - Result, -}; - -#[derive(Repository)] -#[repository(K = "u32", V = "MasternodeStats")] -pub struct MasternodeStatsRepository { - pub store: Arc, - col: LedgerColumn, -} - -impl MasternodeStatsRepository { - pub fn get_latest(&self) -> Result> { - match self.col.iter(None, SortOrder::Descending.into())?.next() { - None => Ok(None), - Some(Ok((_, id))) => Ok(Some(id)), - Some(Err(e)) => Err(e.into()), - } - } -} diff --git a/lib/ain-ocean/src/repository/mod.rs b/lib/ain-ocean/src/repository/mod.rs deleted file mode 100644 index e4a80035ad9..00000000000 --- a/lib/ain-ocean/src/repository/mod.rs +++ /dev/null @@ -1,71 +0,0 @@ -use crate::{storage::SortOrder, Result}; - -mod block; -mod masternode; -mod masternode_stats; -mod oracle; -mod oracle_history; -mod oracle_price_active; -mod oracle_price_aggregated; -mod oracle_price_aggregated_interval; -mod oracle_price_feed; -mod oracle_token_currency; -mod pool_swap; -mod pool_swap_aggregated; -mod poolpair; -mod price_ticker; -mod raw_block; -mod script_activity; -mod script_aggregation; -mod script_unspent; -mod transaction; -mod transaction_vin; -mod transaction_vout; -mod tx_result; -mod vault_auction_batch_history; - -pub use block::*; -pub use masternode::*; -pub use masternode_stats::*; -pub use oracle::*; -pub use oracle_history::*; -pub use oracle_price_active::*; -pub use oracle_price_aggregated::*; -pub use oracle_price_aggregated_interval::*; -pub use oracle_price_feed::*; -pub use oracle_token_currency::*; -pub use pool_swap::*; -pub use pool_swap_aggregated::*; -pub use poolpair::*; -pub use price_ticker::*; -pub use raw_block::*; -pub use script_activity::*; -pub use script_aggregation::*; -pub use script_unspent::*; -pub use transaction::*; -pub use transaction_vin::*; -pub use transaction_vout::*; -pub use tx_result::*; -pub use vault_auction_batch_history::*; - -pub trait RepositoryOps { - type ListItem; - fn get(&self, key: &K) -> Result>; - fn put(&self, key: &K, value: &V) -> Result<()>; - fn delete(&self, key: &K) -> Result<()>; - fn list<'a>( - &'a self, - from: Option, - direction: SortOrder, - ) -> Result + 'a>>; -} - -pub trait InitialKeyProvider: RepositoryOps { - type PartialKey; - fn initial_key(pk: Self::PartialKey) -> K; -} - -pub trait SecondaryIndex: RepositoryOps { - type Value; - fn retrieve_primary_value(&self, el: Self::ListItem) -> Result; -} diff --git a/lib/ain-ocean/src/repository/oracle.rs b/lib/ain-ocean/src/repository/oracle.rs deleted file mode 100644 index eb1bf65eeca..00000000000 --- a/lib/ain-ocean/src/repository/oracle.rs +++ /dev/null @@ -1,19 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; -use bitcoin::Txid; - -use super::RepositoryOps; -use crate::{ - model::Oracle, - storage::{columns, ocean_store::OceanStore}, - Result, -}; - -#[derive(Repository)] -#[repository(K = "Txid", V = "Oracle")] -pub struct OracleRepository { - pub store: Arc, - col: LedgerColumn, -} diff --git a/lib/ain-ocean/src/repository/oracle_history.rs b/lib/ain-ocean/src/repository/oracle_history.rs deleted file mode 100644 index 6f355dd5817..00000000000 --- a/lib/ain-ocean/src/repository/oracle_history.rs +++ /dev/null @@ -1,26 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; -use bitcoin::Txid; - -use super::RepositoryOps; -use crate::{ - model::{OracleHistory, OracleHistoryId}, - storage::{columns, ocean_store::OceanStore}, - Result, -}; - -#[derive(Repository)] -#[repository(K = "OracleHistoryId", V = "OracleHistory")] -pub struct OracleHistoryRepository { - pub store: Arc, - col: LedgerColumn, -} - -#[derive(Repository)] -#[repository(K = "Txid", V = "OracleHistoryId")] -pub struct OracleHistoryRepositoryKey { - pub store: Arc, - col: LedgerColumn, -} diff --git a/lib/ain-ocean/src/repository/oracle_price_active.rs b/lib/ain-ocean/src/repository/oracle_price_active.rs deleted file mode 100644 index 172ad0c2013..00000000000 --- a/lib/ain-ocean/src/repository/oracle_price_active.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; - -use super::{RepositoryOps, SecondaryIndex}; -use crate::{ - model::{OraclePriceActive, OraclePriceActiveId, OraclePriceActiveKey}, - storage::{columns, ocean_store::OceanStore}, - Error, Result, -}; - -#[derive(Repository)] -#[repository(K = "OraclePriceActiveId", V = "OraclePriceActive")] -pub struct OraclePriceActiveRepository { - pub store: Arc, - col: LedgerColumn, -} - -#[derive(Repository)] -#[repository(K = "OraclePriceActiveKey", V = "OraclePriceActiveId")] -pub struct OraclePriceActiveKeyRepository { - pub store: Arc, - col: LedgerColumn, -} - -impl SecondaryIndex for OraclePriceActiveKeyRepository { - type Value = OraclePriceActive; - - fn retrieve_primary_value(&self, el: Self::ListItem) -> Result { - let (_, id) = el?; - - let col = self.store.column::(); - let res = col.get(&id)?.ok_or(Error::SecondaryIndex)?; - - Ok(res) - } -} diff --git a/lib/ain-ocean/src/repository/oracle_price_aggregated.rs b/lib/ain-ocean/src/repository/oracle_price_aggregated.rs deleted file mode 100644 index 2f36f4d4e2f..00000000000 --- a/lib/ain-ocean/src/repository/oracle_price_aggregated.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; - -use super::RepositoryOps; -use crate::{ - model::{OraclePriceAggregated, OraclePriceAggregatedId, OraclePriceAggregatedKey}, - storage::{columns, ocean_store::OceanStore}, - Result, -}; - -#[derive(Repository)] -#[repository(K = "OraclePriceAggregatedId", V = "OraclePriceAggregated")] -pub struct OraclePriceAggregatedRepository { - pub store: Arc, - col: LedgerColumn, -} - -#[derive(Repository)] -#[repository(K = "OraclePriceAggregatedKey", V = "OraclePriceAggregatedId")] -pub struct OraclePriceAggregatedRepositoryKey { - pub store: Arc, - col: LedgerColumn, -} diff --git a/lib/ain-ocean/src/repository/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/repository/oracle_price_aggregated_interval.rs deleted file mode 100644 index cba9367f540..00000000000 --- a/lib/ain-ocean/src/repository/oracle_price_aggregated_interval.rs +++ /dev/null @@ -1,34 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; - -use super::RepositoryOps; -use crate::{ - model::{ - OraclePriceAggregatedInterval, OraclePriceAggregatedIntervalId, - OraclePriceAggregatedIntervalKey, - }, - storage::{columns, ocean_store::OceanStore}, - Result, -}; - -#[derive(Repository)] -#[repository( - K = "OraclePriceAggregatedIntervalId", - V = "OraclePriceAggregatedInterval" -)] -pub struct OraclePriceAggregatedIntervalRepository { - pub store: Arc, - col: LedgerColumn, -} - -#[derive(Repository)] -#[repository( - K = "OraclePriceAggregatedIntervalKey", - V = "OraclePriceAggregatedIntervalId" -)] -pub struct OraclePriceAggregatedIntervalKeyRepository { - pub store: Arc, - col: LedgerColumn, -} diff --git a/lib/ain-ocean/src/repository/oracle_price_feed.rs b/lib/ain-ocean/src/repository/oracle_price_feed.rs deleted file mode 100644 index 875e162cdc1..00000000000 --- a/lib/ain-ocean/src/repository/oracle_price_feed.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; - -use super::RepositoryOps; -use crate::{ - model::{OraclePriceFeed, OraclePriceFeedId, OraclePriceFeedkey}, - storage::{columns, ocean_store::OceanStore}, - Result, -}; - -#[derive(Repository)] -#[repository(K = "OraclePriceFeedId", V = "OraclePriceFeed")] -pub struct OraclePriceFeedRepository { - pub store: Arc, - col: LedgerColumn, -} - -#[derive(Repository)] -#[repository(K = "OraclePriceFeedkey", V = "OraclePriceFeedId")] -pub struct OraclePriceFeedKeyRepository { - pub store: Arc, - col: LedgerColumn, -} diff --git a/lib/ain-ocean/src/repository/oracle_token_currency.rs b/lib/ain-ocean/src/repository/oracle_token_currency.rs deleted file mode 100644 index 7d5a755840a..00000000000 --- a/lib/ain-ocean/src/repository/oracle_token_currency.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; - -use super::RepositoryOps; -use crate::{ - model::{OracleTokenCurrency, OracleTokenCurrencyId, OracleTokenCurrencyKey}, - storage::{columns, ocean_store::OceanStore}, - Result, -}; - -#[derive(Repository)] -#[repository(K = "OracleTokenCurrencyId", V = "OracleTokenCurrency")] -pub struct OracleTokenCurrencyRepository { - pub store: Arc, - col: LedgerColumn, -} - -#[derive(Repository)] -#[repository(K = "OracleTokenCurrencyKey", V = "OracleTokenCurrencyId")] -pub struct OracleTokenCurrencyKeyRepository { - pub store: Arc, - col: LedgerColumn, -} diff --git a/lib/ain-ocean/src/repository/pool_swap.rs b/lib/ain-ocean/src/repository/pool_swap.rs deleted file mode 100644 index 5e93c9d34c7..00000000000 --- a/lib/ain-ocean/src/repository/pool_swap.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; - -use super::{InitialKeyProvider, RepositoryOps}; -use crate::{ - model::{PoolSwap, PoolSwapKey}, - storage::{columns, ocean_store::OceanStore}, - Result, -}; - -#[derive(Repository)] -#[repository(K = "PoolSwapKey", V = "PoolSwap")] -pub struct PoolSwapRepository { - pub store: Arc, - col: LedgerColumn, -} - -impl InitialKeyProvider for PoolSwapRepository { - type PartialKey = u32; - fn initial_key(pk: Self::PartialKey) -> PoolSwapKey { - (pk, u32::MAX, usize::MAX) - } -} diff --git a/lib/ain-ocean/src/repository/pool_swap_aggregated.rs b/lib/ain-ocean/src/repository/pool_swap_aggregated.rs deleted file mode 100644 index 1360bda61d1..00000000000 --- a/lib/ain-ocean/src/repository/pool_swap_aggregated.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; - -use super::{RepositoryOps, SecondaryIndex}; -use crate::{ - model::{PoolSwapAggregated, PoolSwapAggregatedId, PoolSwapAggregatedKey}, - storage::{columns, ocean_store::OceanStore}, - Error, Result, -}; - -#[derive(Repository)] -#[repository(K = "PoolSwapAggregatedId", V = "PoolSwapAggregated")] -pub struct PoolSwapAggregatedRepository { - pub store: Arc, - col: LedgerColumn, -} - -#[derive(Repository)] -#[repository(K = "PoolSwapAggregatedKey", V = "PoolSwapAggregatedId")] -pub struct PoolSwapAggregatedKeyRepository { - pub store: Arc, - col: LedgerColumn, -} - -impl SecondaryIndex - for PoolSwapAggregatedKeyRepository -{ - type Value = PoolSwapAggregated; - - fn retrieve_primary_value(&self, el: Self::ListItem) -> Result { - let (_, id) = el?; - - let col = self.store.column::(); - let res = col.get(&id)?.ok_or(Error::SecondaryIndex)?; - - Ok(res) - } -} diff --git a/lib/ain-ocean/src/repository/poolpair.rs b/lib/ain-ocean/src/repository/poolpair.rs deleted file mode 100644 index 31bc421dc2e..00000000000 --- a/lib/ain-ocean/src/repository/poolpair.rs +++ /dev/null @@ -1,29 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; - -use super::RepositoryOps; -use crate::{ - storage::{columns, ocean_store::OceanStore}, - Result, -}; - -type PoolPairByHeightKey = (u32, usize); // block_height, tx_idx -type PoolPairValue = (u32, u32, u32); // pool_id, id_token_a, id_token_b - -#[derive(Repository)] -#[repository(K = "PoolPairByHeightKey", V = "PoolPairValue")] -pub struct PoolPairByHeightRepository { - pub store: Arc, - col: LedgerColumn, -} - -type PoolPairId = (u32, u32); - -#[derive(Repository)] -#[repository(K = "PoolPairId", V = "u32")] -pub struct PoolPairRepository { - pub store: Arc, - col: LedgerColumn, -} diff --git a/lib/ain-ocean/src/repository/price_ticker.rs b/lib/ain-ocean/src/repository/price_ticker.rs deleted file mode 100644 index 97eef7b2989..00000000000 --- a/lib/ain-ocean/src/repository/price_ticker.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; - -use super::RepositoryOps; -use crate::{ - model::{PriceTicker, PriceTickerId, PriceTickerKey}, - storage::{columns, ocean_store::OceanStore}, - Result, -}; - -#[derive(Repository)] -#[repository(K = "PriceTickerId", V = "PriceTicker")] -pub struct PriceTickerRepository { - pub store: Arc, - col: LedgerColumn, -} - -impl PriceTickerRepository { - pub fn new_id(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} - -#[derive(Repository)] -#[repository(K = "PriceTickerKey", V = "PriceTickerId")] -pub struct PriceTickerKeyRepository { - pub store: Arc, - col: LedgerColumn, -} - -impl PriceTickerKeyRepository { - pub fn new_key(store: Arc) -> Self { - Self { - col: store.column(), - store, - } - } -} diff --git a/lib/ain-ocean/src/repository/raw_block.rs b/lib/ain-ocean/src/repository/raw_block.rs deleted file mode 100644 index 81f2d248c8f..00000000000 --- a/lib/ain-ocean/src/repository/raw_block.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; -use bitcoin::BlockHash; - -use super::RepositoryOps; -use crate::{ - storage::{columns, ocean_store::OceanStore}, - Result, -}; - -#[derive(Repository)] -#[repository(K = "BlockHash", V = "String")] -pub struct RawBlockRepository { - pub store: Arc, - col: LedgerColumn, -} diff --git a/lib/ain-ocean/src/repository/script_activity.rs b/lib/ain-ocean/src/repository/script_activity.rs deleted file mode 100644 index f0448499726..00000000000 --- a/lib/ain-ocean/src/repository/script_activity.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; - -use super::RepositoryOps; -use crate::{ - model::{ScriptActivity, ScriptActivityId}, - storage::{columns, ocean_store::OceanStore}, - Result, -}; - -#[derive(Repository)] -#[repository(K = "ScriptActivityId", V = "ScriptActivity")] -pub struct ScriptActivityRepository { - pub store: Arc, - col: LedgerColumn, -} diff --git a/lib/ain-ocean/src/repository/script_aggregation.rs b/lib/ain-ocean/src/repository/script_aggregation.rs deleted file mode 100644 index feeaec54e3c..00000000000 --- a/lib/ain-ocean/src/repository/script_aggregation.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; - -use super::RepositoryOps; -use crate::{ - model::{ScriptAggregation, ScriptAggregationId}, - storage::{columns, ocean_store::OceanStore}, - Result, -}; - -#[derive(Repository)] -#[repository(K = "ScriptAggregationId", V = "ScriptAggregation")] -pub struct ScriptAggregationRepository { - pub store: Arc, - col: LedgerColumn, -} diff --git a/lib/ain-ocean/src/repository/script_unspent.rs b/lib/ain-ocean/src/repository/script_unspent.rs deleted file mode 100644 index 29c9668f2ca..00000000000 --- a/lib/ain-ocean/src/repository/script_unspent.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; - -use super::{RepositoryOps, SecondaryIndex}; -use crate::{ - model::{ScriptUnspent, ScriptUnspentId, ScriptUnspentKey}, - storage::{columns, ocean_store::OceanStore}, - Error, Result, -}; - -#[derive(Repository)] -#[repository(K = "ScriptUnspentId", V = "ScriptUnspent")] -pub struct ScriptUnspentRepository { - pub store: Arc, - col: LedgerColumn, -} - -#[derive(Repository)] -#[repository(K = "ScriptUnspentKey", V = "ScriptUnspentId")] -pub struct ScriptUnspentKeyRepository { - pub store: Arc, - col: LedgerColumn, -} - -impl SecondaryIndex for ScriptUnspentKeyRepository { - type Value = ScriptUnspent; - - fn retrieve_primary_value(&self, el: Self::ListItem) -> Result { - let (_, id) = el?; - - let col = self.store.column::(); - let res = col.get(&id)?.ok_or(Error::SecondaryIndex)?; - - Ok(res) - } -} diff --git a/lib/ain-ocean/src/repository/test/block_test.rs b/lib/ain-ocean/src/repository/test/block_test.rs deleted file mode 100644 index 461ca515b39..00000000000 --- a/lib/ain-ocean/src/repository/test/block_test.rs +++ /dev/null @@ -1,219 +0,0 @@ -#[cfg(test_off)] -mod tests { - use tempdir::TempDir; - - use super::*; - use crate::{ - data_acces::block::BlockDb, - database::db_manager::{ColumnFamilyOperations, RocksDB, SortOrder}, - model::block::Block, - }; - - pub fn create_dummy_block(height: i32) -> Block { - Block { - id: "1".to_string(), - hash: "block_hash_1".to_string(), - previous_hash: "previous_block_hash".to_string(), - height: height, - version: 1, - time: 1634054400, // Replace with an actual timestamp - median_time: 1634054400, // Replace with an actual timestamp - transaction_count: 10, - difficulty: 12345, - masternode: "masternode_address".to_string(), - minter: "minter_address".to_string(), - minter_block_count: 5, - reward: "10.0".to_string(), - stake_modifier: "stake_modifier_value".to_string(), - merkleroot: "merkleroot_value".to_string(), - size: 2000, - size_stripped: 1800, - weight: 1900, - } - } - - #[tokio::test] - async fn test_put_get_by_hash_and_height() { - // Create a temporary RocksDB instance for testing - let temp_dir = TempDir::new("test_rocksdb").expect("Failed to create temp directory"); - let rocksdb = RocksDB::new(temp_dir.path().to_str().unwrap()) - .expect("Failed to create RocksDB instance"); - let block_db = BlockDb { db: rocksdb }; - - // Create a dummy block for testing - let dummy_block = create_dummy_block(1); - - // Test the put_block method - block_db.put_block(dummy_block.clone()).await.unwrap(); - - // Test the get_by_hash method - let result_by_hash = block_db - .get_by_hash(dummy_block.hash.clone()) - .await - .unwrap(); - assert_eq!(result_by_hash.unwrap(), dummy_block.clone()); - - // Test the get_by_height method - let result_by_height = block_db.get_by_height(dummy_block.height).await.unwrap(); - assert_eq!(result_by_height.unwrap(), dummy_block); - } - - #[tokio::test] - async fn test_get_nonexistent_block_by_hash() { - let temp_dir = TempDir::new("test_rocksdb").expect("Failed to create temp directory"); - let rocksdb = RocksDB::new(temp_dir.path().to_str().unwrap()) - .expect("Failed to create RocksDB instance"); - let block_db = BlockDb { db: rocksdb }; - - // Attempt to get a block using a hash that doesn't exist - let result = block_db - .get_by_hash("nonexistent_hash".to_string()) - .await - .unwrap(); - assert_eq!(result, None); - } - - #[tokio::test] - async fn test_get_nonexistent_block_by_height() { - let temp_dir = TempDir::new("test_rocksdb").expect("Failed to create temp directory"); - let rocksdb = RocksDB::new(temp_dir.path().to_str().unwrap()) - .expect("Failed to create RocksDB instance"); - let block_db = BlockDb { db: rocksdb }; - - // Attempt to get a block using a height that doesn't exist - let result = block_db.get_by_height(999).await.unwrap(); - assert_eq!(result, None); - } - - #[tokio::test] - async fn test_delete_block() { - let temp_dir = TempDir::new("test_rocksdb").expect("Failed to create temp directory"); - let rocksdb = RocksDB::new(temp_dir.path().to_str().unwrap()) - .expect("Failed to create RocksDB instance"); - let block_db = BlockDb { db: rocksdb }; - - // Create a dummy block for testing - let dummy_block = create_dummy_block(1); - - // Put the block - block_db.put_block(dummy_block.clone()).await.unwrap(); - - // Delete the block - block_db - .delete_block(dummy_block.hash.clone()) - .await - .unwrap(); - - // Attempt to get the block after deletion - let result_by_hash = block_db - .get_by_hash(dummy_block.hash.clone()) - .await - .unwrap(); - - assert!(result_by_hash.is_none()); - } - - #[tokio::test] - async fn test_query_by_height_descending() { - // Create a temporary RocksDB instance for testing - let temp_dir = TempDir::new("test_rocksdb").expect("Failed to create temp directory"); - let rocksdb = RocksDB::new(temp_dir.path().to_str().unwrap()) - .expect("Failed to create RocksDB instance"); - let block_db = BlockDb { db: rocksdb }; - - // Create dummy blocks with heights 1 to 5 and insert them into the database - for height in 1..=10 { - let dummy_block = create_dummy_block(height); - block_db.put_block(dummy_block.clone()).await.unwrap(); - } - - // Test the query_by_height method - let result_blocks = block_db - .query_by_height(3, 4, SortOrder::Descending) - .await - .unwrap(); - // Verify that the result contains the expected blocks - assert_eq!(result_blocks.len(), 3); - assert_eq!(result_blocks[0].height, 3); - assert_eq!(result_blocks[1].height, 2); - } - - #[tokio::test] - async fn test_query_by_height_ascending() { - // Create a temporary RocksDB instance for testing - let temp_dir = TempDir::new("test_rocksdb").expect("Failed to create temp directory"); - let rocksdb = RocksDB::new(temp_dir.path().to_str().unwrap()) - .expect("Failed to create RocksDB instance"); - let block_db = BlockDb { db: rocksdb }; - - // Create dummy blocks with heights 1 to 5 and insert them into the database - for height in 1..=10 { - let dummy_block = create_dummy_block(height); - block_db.put_block(dummy_block.clone()).await.unwrap(); - } - - // Test the query_by_height method - let result_blocks = block_db - .query_by_height(5, 6, SortOrder::Ascending) - .await - .unwrap(); - // Verify that the result contains the expected blocks - assert_eq!(result_blocks.len(), 5); - assert_eq!(result_blocks[0].height, 1); - assert_eq!(result_blocks[1].height, 2); - } - - #[tokio::test] - async fn test_put_block_updates_latest_height() { - // Setup test environment - let temp_dir = TempDir::new("test_rocksdb").expect("Failed to create temp directory"); - let rocksdb = RocksDB::new(temp_dir.path().to_str().unwrap()) - .expect("Failed to create RocksDB instance"); - let block_db = BlockDb { db: rocksdb }; - - // Create and insert sample blocks - for height in 1..=10 { - let dummy_block = create_dummy_block(height); - block_db.put_block(dummy_block).await.unwrap(); - } - - // Retrieve latest block height - let latest_height_bytes = block_db - .db - .get("latest_block_height", b"latest_block_height") - .expect("Failed to retrieve latest block height") - .expect("Latest block height not found"); - let latest_height = i32::from_be_bytes( - latest_height_bytes - .as_slice() - .try_into() - .expect("Byte length mismatch"), - ); - - // Assert correctness - assert_eq!(latest_height, 10); // Assert that latest height is 10 - } - - #[tokio::test] - async fn test_get_highest_retrieves_correct_block() -> Result<(), Box> { - // Setup test environment - let temp_dir = TempDir::new("test_rocksdb").expect("Failed to create temp directory"); - let rocksdb = RocksDB::new(temp_dir.path().to_str().unwrap()) - .expect("Failed to create RocksDB instance"); - let block_db = BlockDb { db: rocksdb }; - - // Insert sample blocks - for height in 1..=5 { - let dummy_block = create_dummy_block(height); - block_db.put_block(dummy_block).await.unwrap(); - } - - // Call get_highest - let highest_block = block_db.get_highest().await.unwrap().unwrap(); - - // Assert that the highest block is the one with height 5 - assert_eq!(highest_block.height, 5); - - Ok(()) - } -} diff --git a/lib/ain-ocean/src/repository/test/masternode_test.rs b/lib/ain-ocean/src/repository/test/masternode_test.rs deleted file mode 100644 index f85f1e86307..00000000000 --- a/lib/ain-ocean/src/repository/test/masternode_test.rs +++ /dev/null @@ -1,85 +0,0 @@ -#[cfg(test_off)] -mod tests { - use chrono::Utc; - use tempfile::tempdir; - - use super::*; - use crate::{ - data_acces::masternode::MasterNodeDB, - database::db_manager::{RocksDB, SortOrder}, - model::masternode::{HistoryItem, Masternode, MasternodeBlock}, - }; - - fn setup_test_db() -> MasterNodeDB { - let temp_dir = tempdir().unwrap(); - let db = RocksDB::new(temp_dir.path().to_str().unwrap()).unwrap(); // Adjust this according to your RocksDB struct - MasterNodeDB { db } - } - fn create_dummy_masternode(id: &str) -> Masternode { - Masternode { - id: id.to_string(), - sort: Some("dummy_sort".to_string()), - owner_address: "dummy_owner_address".to_string(), - operator_address: "dummy_operator_address".to_string(), - creation_height: 100, - resign_height: 200, - resign_tx: Some("dummy_resign_tx".to_string()), - minted_blocks: 50, - timelock: 10, - collateral: "dummy_collateral".to_string(), - block: create_dummy_masternode_block(), - history: Some(vec![create_dummy_history_item()]), - } - } - - fn create_dummy_masternode_block() -> MasternodeBlock { - MasternodeBlock { - hash: "dummy_hash".to_string(), - height: 100, - time: Utc::now().timestamp() as u64, - median_time: Utc::now().timestamp() as u64, - } - } - - fn create_dummy_history_item() -> HistoryItem { - HistoryItem { - txid: "dummy_txid".to_string(), - owner_address: "dummy_history_owner_address".to_string(), - operator_address: "dummy_history_operator_address".to_string(), - } - } - - #[tokio::test] - async fn test_query_with_dummy_data() { - let master_node = setup_test_db(); - let request = create_dummy_masternode("1"); - let result = master_node.store(request).await; - assert!(result.is_ok()); - } - - #[tokio::test] - async fn test_store_and_query_dummy_data() { - let master_node = setup_test_db(); - let dummy_data = vec![ - create_dummy_masternode("1"), - create_dummy_masternode("2"), - create_dummy_masternode("3"), - create_dummy_masternode("4"), - create_dummy_masternode("5"), - create_dummy_masternode("6"), - create_dummy_masternode("7"), - create_dummy_masternode("8"), - create_dummy_masternode("9"), - create_dummy_masternode("10"), - ]; - - for masternode in dummy_data { - let result = master_node.store(masternode).await; - assert!(result.is_ok()); - } - // let query_result = master_node.query(5, 8, SortOrder::Ascending).await; - // assert!(query_result.is_err()); - // let queried_masternodes = query_result.unwrap(); - // assert_eq!(queried_masternodes.len(), 5); - } -} diff --git a/lib/ain-ocean/src/repository/test/mod.rs b/lib/ain-ocean/src/repository/test/mod.rs deleted file mode 100644 index 350db04c962..00000000000 --- a/lib/ain-ocean/src/repository/test/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod block_test; -mod masternode_test; -mod oracle_test; -mod transaction_test; diff --git a/lib/ain-ocean/src/repository/test/oracle_test.rs b/lib/ain-ocean/src/repository/test/oracle_test.rs deleted file mode 100644 index c55e5154611..00000000000 --- a/lib/ain-ocean/src/repository/test/oracle_test.rs +++ /dev/null @@ -1,73 +0,0 @@ -#[cfg(test_off)] -mod tests { - use tempfile::tempdir; - use tokio::task; - - use crate::{ - data_acces::oracle::OracleDb, - database::db_manager::{ColumnFamilyOperations, RocksDB}, - model::oracle::{Oracle, OracleBlock, PriceFeedsItem}, - }; - - // Function to set up a test database environment - fn setup_test_db() -> OracleDb { - let temp_dir = tempdir().unwrap(); - let db = RocksDB::new(temp_dir.path().to_str().unwrap()).unwrap(); // Adjust this according to your RocksDB struct - OracleDb { db } - } - - // Function to create a dummy Oracle instance for testing - fn create_dummy_oracle(id: &str) -> Oracle { - Oracle { - id: id.to_string(), - owner_address: "owner_address_example".to_string(), - weightage: 10, - price_feeds: vec![PriceFeedsItem { - token: "token_example".to_string(), - currency: "currency_example".to_string(), - }], - block: OracleBlock { - hash: "hash_example".to_string(), - height: 1, - time: 100000, - median_time: 100000, - }, - } - } - - #[tokio::test] - async fn test_store() { - let oracle_db = setup_test_db(); - let oracle = create_dummy_oracle("test_id_1"); - - let result = oracle_db.store(oracle).await; - assert!(result.is_ok()); - } - - #[tokio::test] - async fn test_get() { - let oracle_db = setup_test_db(); - let oracle = create_dummy_oracle("test_id_2"); - oracle_db.store(oracle.clone()).await.unwrap(); - - let result = oracle_db.get(oracle.id.clone()).await.unwrap(); - assert!(result.is_some()); - assert_eq!(result.unwrap(), oracle); - } - - #[tokio::test] - async fn test_delete() { - let oracle_db = setup_test_db(); - let oracle = create_dummy_oracle("test_id_3"); - oracle_db.store(oracle.clone()).await.unwrap(); - - let delete_result = oracle_db.delete(oracle.id.clone()).await; - assert!(delete_result.is_ok()); - - let get_result = oracle_db.get(oracle.id).await; - assert!(get_result.is_ok()); - assert!(get_result.unwrap().is_none()); - } - - // Additional tests for `query` and other edge cases can be added similarly -} diff --git a/lib/ain-ocean/src/repository/test/transaction_test.rs b/lib/ain-ocean/src/repository/test/transaction_test.rs deleted file mode 100644 index 00459f4f34f..00000000000 --- a/lib/ain-ocean/src/repository/test/transaction_test.rs +++ /dev/null @@ -1,119 +0,0 @@ -#[cfg(test_off)] -mod tests { - use tempfile::tempdir; - use tokio::task; - - use crate::{ - data_acces::{transaction::TransactionVinDb, transaction_vout::TransactionVoutDb}, - database::db_manager::{ColumnFamilyOperations, RocksDB}, - model::{ - transaction::{Transaction, TransactionBlock}, - transaction_vout::{TransactionVout, TransactionVoutScript}, - }, - }; - - fn setup_test_db() -> TransactionVinDb { - let temp_dir = tempdir().unwrap(); - let db = RocksDB::new(temp_dir.path().to_str().unwrap()).unwrap(); - TransactionVinDb { db } - } - - // Sample transaction for testing - fn sample_transaction(id: &str) -> Transaction { - Transaction { - id: id.to_string(), - order: 1, - block: TransactionBlock { - hash: "sample_hash".to_string(), - height: 123, - time: 1000, - median_time: 1000, - }, - txid: id.to_string(), - hash: "sample_transaction_hash".to_string(), - version: 1, - size: 200, - v_size: 200, - weight: 300, - total_vout_value: "1000".to_string(), - lock_time: 0, - vin_count: 2, - vout_count: 2, - } - } - - fn sample_transaction_Vout() { - // Instantiate a sample TransactionVoutScript - let sample_script = TransactionVoutScript { - hex: "76a91488ac".to_string(), // Sample hex string - r#type: "pubkeyhash".to_string(), // Sample type - }; - - // Instantiate a sample TransactionVout - let sample_vout = TransactionVout { - id: "vout1".to_string(), // Sample ID - txid: "tx12345".to_string(), // Sample transaction ID - n: 0, // Sample index - value: "0.0001".to_string(), // Sample value in BTC or similar currency - token_id: 123, // Sample token ID - script: sample_script, // Use the sample script created above - }; - } - - #[tokio::test] - async fn test_store_transaction() { - let txn_vin_db = setup_test_db(); - - let test_transaction = sample_transaction("tx1"); - - let result = txn_vin_db.store(test_transaction).await; - assert!(result.is_ok()); - } - - #[tokio::test] - async fn test_store_get_transaction() { - let txn_vin_db = setup_test_db(); - - let test_transaction = sample_transaction("tx1"); - let trx_id = test_transaction.id.clone(); - - let result = txn_vin_db.store(test_transaction.clone()).await; - assert!(result.is_ok()); - - let result = txn_vin_db.get(trx_id).await.unwrap().unwrap(); - assert_eq!(test_transaction, result); - } - - #[tokio::test] - async fn test_store_get_delete_transaction() { - let txn_vin_db = setup_test_db(); - - let test_transaction = sample_transaction("tx1"); - let trx_id = test_transaction.id.clone(); - - let result = txn_vin_db.store(test_transaction.clone()).await; - assert!(result.is_ok()); - - let result = txn_vin_db.get(trx_id.clone()).await.unwrap().unwrap(); - assert_eq!(test_transaction, result); - - let result = txn_vin_db.delete(trx_id).await; - assert!(result.is_ok()); - } - - #[tokio::test] - async fn test_query_transaction() { - let txn_vin_db = setup_test_db(); - - let test_transaction = sample_transaction("tx1"); - let trx_id = test_transaction.id.clone(); - - let result = txn_vin_db.store(test_transaction.clone()).await; - assert!(result.is_ok()); - - let result = txn_vin_db - .query_by_block_hash(test_transaction.block.hash.to_string(), 10, 0) - .await; - assert!(result.is_ok()); - } -} diff --git a/lib/ain-ocean/src/repository/transaction.rs b/lib/ain-ocean/src/repository/transaction.rs deleted file mode 100644 index 38b725bd4a6..00000000000 --- a/lib/ain-ocean/src/repository/transaction.rs +++ /dev/null @@ -1,45 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; -use bitcoin::{BlockHash, Txid}; - -use super::{InitialKeyProvider, RepositoryOps, SecondaryIndex}; -use crate::{ - model::{Transaction, TransactionByBlockHashKey}, - storage::{columns, ocean_store::OceanStore}, - Error, Result, -}; - -#[derive(Repository)] -#[repository(K = "Txid", V = "Transaction")] -pub struct TransactionRepository { - pub store: Arc, - col: LedgerColumn, -} - -#[derive(Repository)] -#[repository(K = "TransactionByBlockHashKey", V = "Txid")] -pub struct TransactionByBlockHashRepository { - pub store: Arc, - col: LedgerColumn, -} - -impl InitialKeyProvider for TransactionByBlockHashRepository { - type PartialKey = BlockHash; - - fn initial_key(pk: Self::PartialKey) -> TransactionByBlockHashKey { - (pk, 0) - } -} - -impl SecondaryIndex for TransactionByBlockHashRepository { - type Value = Transaction; - - fn retrieve_primary_value(&self, el: Self::ListItem) -> Result { - let (_, id) = el?; - let col = self.store.column::(); - let tx = col.get(&id)?.ok_or(Error::SecondaryIndex)?; - Ok(tx) - } -} diff --git a/lib/ain-ocean/src/repository/transaction_vin.rs b/lib/ain-ocean/src/repository/transaction_vin.rs deleted file mode 100644 index cfd2ce3510e..00000000000 --- a/lib/ain-ocean/src/repository/transaction_vin.rs +++ /dev/null @@ -1,30 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; -use bitcoin::Txid; - -use super::{InitialKeyProvider, RepositoryOps}; -use crate::{ - model::TransactionVin, - storage::{ - columns::{self}, - ocean_store::OceanStore, - }, - Result, -}; - -#[derive(Repository)] -#[repository(K = "String", V = "TransactionVin")] -pub struct TransactionVinRepository { - pub store: Arc, - col: LedgerColumn, -} - -impl InitialKeyProvider for TransactionVinRepository { - type PartialKey = Txid; - - fn initial_key(pk: Self::PartialKey) -> String { - format!("{}00", pk) - } -} diff --git a/lib/ain-ocean/src/repository/transaction_vout.rs b/lib/ain-ocean/src/repository/transaction_vout.rs deleted file mode 100644 index e9e994b3f4f..00000000000 --- a/lib/ain-ocean/src/repository/transaction_vout.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; - -use super::RepositoryOps; -use crate::{ - model::{TransactionVout, TransactionVoutKey}, - storage::{columns, ocean_store::OceanStore}, - Result, -}; - -#[derive(Repository)] -#[repository(K = "TransactionVoutKey", V = "TransactionVout")] -pub struct TransactionVoutRepository { - pub store: Arc, - col: LedgerColumn, -} diff --git a/lib/ain-ocean/src/repository/tx_result.rs b/lib/ain-ocean/src/repository/tx_result.rs deleted file mode 100644 index 126e3acea28..00000000000 --- a/lib/ain-ocean/src/repository/tx_result.rs +++ /dev/null @@ -1,19 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; -use bitcoin::Txid; - -use super::RepositoryOps; -use crate::{ - model::TxResult, - storage::{columns, ocean_store::OceanStore}, - Result, -}; - -#[derive(Repository)] -#[repository(K = "Txid", V = "TxResult")] -pub struct TxResultRepository { - pub store: Arc, - col: LedgerColumn, -} diff --git a/lib/ain-ocean/src/repository/vault_auction_batch_history.rs b/lib/ain-ocean/src/repository/vault_auction_batch_history.rs deleted file mode 100644 index 2a05894bed9..00000000000 --- a/lib/ain-ocean/src/repository/vault_auction_batch_history.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::sync::Arc; - -use ain_db::LedgerColumn; -use ain_macros::Repository; - -use super::RepositoryOps; -use crate::{ - model::{AuctionHistoryByHeightKey, AuctionHistoryKey, VaultAuctionBatchHistory}, - storage::{columns, ocean_store::OceanStore}, - Result, -}; - -#[derive(Repository)] -#[repository(K = "AuctionHistoryKey", V = "VaultAuctionBatchHistory")] -pub struct AuctionHistoryRepository { - pub store: Arc, - col: LedgerColumn, -} - -#[derive(Repository)] -#[repository(K = "AuctionHistoryByHeightKey", V = "AuctionHistoryKey")] -pub struct AuctionHistoryByHeightRepository { - pub store: Arc, - col: LedgerColumn, -} - -impl AuctionHistoryByHeightRepository { - // pub fn get_latest(&self) -> Result> { - // match self.list(None::Descending)?.next() { - // None => Ok(None), - // Some(Ok((_, id))) => { - // let col = self.store.column::(); - // Ok(col.get(&id)?) - // } - // Some(Err(e)) => Err(e.into()), - // } - // } -} diff --git a/lib/ain-ocean/src/storage/columns/block.rs b/lib/ain-ocean/src/storage/columns/block.rs deleted file mode 100644 index 448916c89fc..00000000000 --- a/lib/ain-ocean/src/storage/columns/block.rs +++ /dev/null @@ -1,49 +0,0 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::BlockHash; - -use crate::model; - -#[derive(Debug)] -pub struct Block; - -impl ColumnName for Block { - const NAME: &'static str = "block"; -} - -impl Column for Block { - type Index = BlockHash; -} - -impl TypedColumn for Block { - type Type = model::Block; -} - -// Secondary index by block height -#[derive(Debug)] -pub struct BlockByHeight; - -impl ColumnName for BlockByHeight { - const NAME: &'static str = "block_by_height"; -} - -impl Column for BlockByHeight { - type Index = u32; - - fn key(index: &Self::Index) -> Result, DBError> { - Ok(index.to_be_bytes().to_vec()) - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - if raw_key.len() != 4 { - return Err(format_err!("Length of the slice is not 4").into()); - } - let mut array = [0u8; 4]; - array.copy_from_slice(&raw_key); - Ok(u32::from_be_bytes(array)) - } -} - -impl TypedColumn for BlockByHeight { - type Type = BlockHash; -} diff --git a/lib/ain-ocean/src/storage/columns/masternode.rs b/lib/ain-ocean/src/storage/columns/masternode.rs deleted file mode 100644 index eda0112c568..00000000000 --- a/lib/ain-ocean/src/storage/columns/masternode.rs +++ /dev/null @@ -1,35 +0,0 @@ -use ain_db::{Column, ColumnName, TypedColumn}; -use bitcoin::Txid; - -use crate::model; - -#[derive(Debug)] -pub struct Masternode; - -impl ColumnName for Masternode { - const NAME: &'static str = "masternode"; -} - -impl Column for Masternode { - type Index = Txid; -} - -impl TypedColumn for Masternode { - type Type = model::Masternode; -} - -// Secondary index by block height and txno -#[derive(Debug)] -pub struct MasternodeByHeight; - -impl ColumnName for MasternodeByHeight { - const NAME: &'static str = "masternode_by_height"; -} - -impl Column for MasternodeByHeight { - type Index = (u32, Txid); -} - -impl TypedColumn for MasternodeByHeight { - type Type = u8; -} diff --git a/lib/ain-ocean/src/storage/columns/masternode_stats.rs b/lib/ain-ocean/src/storage/columns/masternode_stats.rs deleted file mode 100644 index 2171c659263..00000000000 --- a/lib/ain-ocean/src/storage/columns/masternode_stats.rs +++ /dev/null @@ -1,32 +0,0 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; - -use crate::model; - -#[derive(Debug)] -pub struct MasternodeStats; - -impl ColumnName for MasternodeStats { - const NAME: &'static str = "masternode_stats"; -} - -impl Column for MasternodeStats { - type Index = u32; - - fn key(index: &Self::Index) -> Result, DBError> { - Ok(index.to_be_bytes().to_vec()) - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - if raw_key.len() != 4 { - return Err(format_err!("Length of the slice is not 4").into()); - } - let mut array = [0u8; 4]; - array.copy_from_slice(&raw_key); - Ok(u32::from_be_bytes(array)) - } -} - -impl TypedColumn for MasternodeStats { - type Type = model::MasternodeStats; -} diff --git a/lib/ain-ocean/src/storage/columns/mod.rs b/lib/ain-ocean/src/storage/columns/mod.rs deleted file mode 100644 index 82cfe929896..00000000000 --- a/lib/ain-ocean/src/storage/columns/mod.rs +++ /dev/null @@ -1,88 +0,0 @@ -mod block; -mod masternode; -mod masternode_stats; -mod oracle; -mod oracle_history; -mod oracle_price_active; -mod oracle_price_aggregated; -mod oracle_price_aggregated_interval; -mod oracle_price_feed; -mod oracle_token_currency; -mod pool_swap; -mod pool_swap_aggregated; -mod poolpair; -mod price_ticker; -mod raw_block; -mod script_activity; -mod script_aggregation; -mod script_unspent; -mod transaction; -mod transaction_vin; -mod transaction_vout; -mod tx_result; -mod vault_auction_history; - -use ain_db::ColumnName; -pub use block::*; -pub use masternode::*; -pub use masternode_stats::*; -pub use oracle::*; -pub use oracle_history::*; -pub use oracle_price_active::*; -pub use oracle_price_aggregated::*; -pub use oracle_price_aggregated_interval::*; -pub use oracle_price_feed::*; -pub use oracle_token_currency::*; -pub use pool_swap::*; -pub use pool_swap_aggregated::*; -pub use poolpair::*; -pub use price_ticker::*; -pub use raw_block::*; -pub use script_activity::*; -pub use script_aggregation::*; -pub use script_unspent::*; -pub use transaction::*; -pub use transaction_vin::*; -pub use transaction_vout::*; -pub use tx_result::*; -pub use vault_auction_history::*; - -pub const COLUMN_NAMES: [&str; 37] = [ - block::Block::NAME, - block::BlockByHeight::NAME, - masternode_stats::MasternodeStats::NAME, - masternode::Masternode::NAME, - masternode::MasternodeByHeight::NAME, - oracle::Oracle::NAME, - oracle_history::OracleHistory::NAME, - oracle_history::OracleHistoryOracleIdSort::NAME, - oracle_price_active::OraclePriceActive::NAME, - oracle_price_active::OraclePriceActiveKey::NAME, - oracle_price_aggregated::OraclePriceAggregated::NAME, - oracle_price_aggregated::OraclePriceAggregatedKey::NAME, - oracle_price_aggregated_interval::OraclePriceAggregatedInterval::NAME, - oracle_price_aggregated_interval::OraclePriceAggregatedIntervalKey::NAME, - oracle_price_feed::OraclePriceFeed::NAME, - oracle_price_feed::OraclePriceFeedKey::NAME, - oracle_token_currency::OracleTokenCurrency::NAME, - oracle_token_currency::OracleTokenCurrencyKey::NAME, - pool_swap_aggregated::PoolSwapAggregated::NAME, - pool_swap_aggregated::PoolSwapAggregatedKey::NAME, - pool_swap::PoolSwap::NAME, - poolpair::PoolPair::NAME, - poolpair::PoolPairByHeight::NAME, - price_ticker::PriceTicker::NAME, - price_ticker::PriceTickerKey::NAME, - raw_block::RawBlock::NAME, - script_activity::ScriptActivity::NAME, - script_aggregation::ScriptAggregation::NAME, - script_unspent::ScriptUnspent::NAME, - script_unspent::ScriptUnspentKey::NAME, - transaction::Transaction::NAME, - transaction::TransactionByBlockHash::NAME, - transaction_vin::TransactionVin::NAME, - transaction_vout::TransactionVout::NAME, - tx_result::TxResult::NAME, - vault_auction_history::VaultAuctionHistory::NAME, - vault_auction_history::VaultAuctionHistoryByHeight::NAME, -]; diff --git a/lib/ain-ocean/src/storage/columns/oracle.rs b/lib/ain-ocean/src/storage/columns/oracle.rs deleted file mode 100644 index f159f0419f1..00000000000 --- a/lib/ain-ocean/src/storage/columns/oracle.rs +++ /dev/null @@ -1,19 +0,0 @@ -use ain_db::{Column, ColumnName, TypedColumn}; -use bitcoin::Txid; - -use crate::model; - -#[derive(Debug)] -pub struct Oracle; - -impl ColumnName for Oracle { - const NAME: &'static str = "oracle"; -} - -impl Column for Oracle { - type Index = Txid; -} - -impl TypedColumn for Oracle { - type Type = model::Oracle; -} diff --git a/lib/ain-ocean/src/storage/columns/oracle_history.rs b/lib/ain-ocean/src/storage/columns/oracle_history.rs deleted file mode 100644 index 672cecb5f12..00000000000 --- a/lib/ain-ocean/src/storage/columns/oracle_history.rs +++ /dev/null @@ -1,33 +0,0 @@ -use ain_db::{Column, ColumnName, TypedColumn}; -use bitcoin::Txid; - -use crate::model; - -#[derive(Debug)] -pub struct OracleHistory; - -impl ColumnName for OracleHistory { - const NAME: &'static str = "oracle_history"; -} - -impl Column for OracleHistory { - type Index = model::OracleHistoryId; -} - -impl TypedColumn for OracleHistory { - type Type = model::OracleHistory; -} - -pub struct OracleHistoryOracleIdSort; - -impl ColumnName for OracleHistoryOracleIdSort { - const NAME: &'static str = "oracle_history_oracle_id_sort"; -} - -impl Column for OracleHistoryOracleIdSort { - type Index = Txid; -} - -impl TypedColumn for OracleHistoryOracleIdSort { - type Type = model::OracleHistoryId; -} diff --git a/lib/ain-ocean/src/storage/columns/oracle_price_active.rs b/lib/ain-ocean/src/storage/columns/oracle_price_active.rs deleted file mode 100644 index a45b807472a..00000000000 --- a/lib/ain-ocean/src/storage/columns/oracle_price_active.rs +++ /dev/null @@ -1,33 +0,0 @@ -use ain_db::{Column, ColumnName, TypedColumn}; - -use crate::model; - -#[derive(Debug)] -pub struct OraclePriceActive; - -impl ColumnName for OraclePriceActive { - const NAME: &'static str = "oracle_price_active"; -} - -impl Column for OraclePriceActive { - type Index = model::OraclePriceActiveId; -} - -impl TypedColumn for OraclePriceActive { - type Type = model::OraclePriceActive; -} - -#[derive(Debug)] -pub struct OraclePriceActiveKey; - -impl ColumnName for OraclePriceActiveKey { - const NAME: &'static str = "oracle_price_active_key"; -} - -impl Column for OraclePriceActiveKey { - type Index = model::OraclePriceActiveKey; -} - -impl TypedColumn for OraclePriceActiveKey { - type Type = model::OraclePriceActiveId; -} diff --git a/lib/ain-ocean/src/storage/columns/oracle_price_aggregated.rs b/lib/ain-ocean/src/storage/columns/oracle_price_aggregated.rs deleted file mode 100644 index fd3d3f94702..00000000000 --- a/lib/ain-ocean/src/storage/columns/oracle_price_aggregated.rs +++ /dev/null @@ -1,32 +0,0 @@ -use ain_db::{Column, ColumnName, TypedColumn}; - -use crate::model; - -#[derive(Debug)] -pub struct OraclePriceAggregated; - -impl ColumnName for OraclePriceAggregated { - const NAME: &'static str = "oracle_price_aggregated"; -} - -impl Column for OraclePriceAggregated { - type Index = model::OraclePriceAggregatedId; -} - -impl TypedColumn for OraclePriceAggregated { - type Type = model::OraclePriceAggregated; -} - -pub struct OraclePriceAggregatedKey; - -impl ColumnName for OraclePriceAggregatedKey { - const NAME: &'static str = "oracle_price_aggregated_key"; -} - -impl Column for OraclePriceAggregatedKey { - type Index = model::OraclePriceAggregatedKey; -} - -impl TypedColumn for OraclePriceAggregatedKey { - type Type = model::OraclePriceAggregatedId; -} diff --git a/lib/ain-ocean/src/storage/columns/oracle_price_aggregated_interval.rs b/lib/ain-ocean/src/storage/columns/oracle_price_aggregated_interval.rs deleted file mode 100644 index 0adca75ae46..00000000000 --- a/lib/ain-ocean/src/storage/columns/oracle_price_aggregated_interval.rs +++ /dev/null @@ -1,33 +0,0 @@ -use ain_db::{Column, ColumnName, TypedColumn}; - -use crate::model; - -#[derive(Debug)] -pub struct OraclePriceAggregatedInterval; - -impl ColumnName for OraclePriceAggregatedInterval { - const NAME: &'static str = "oracle_price_aggregated_interval"; -} - -impl Column for OraclePriceAggregatedInterval { - type Index = model::OraclePriceAggregatedIntervalId; -} - -impl TypedColumn for OraclePriceAggregatedInterval { - type Type = model::OraclePriceAggregatedInterval; -} - -#[derive(Debug)] -pub struct OraclePriceAggregatedIntervalKey; - -impl ColumnName for OraclePriceAggregatedIntervalKey { - const NAME: &'static str = "oracle_price_aggregated_interval_key"; -} - -impl Column for OraclePriceAggregatedIntervalKey { - type Index = model::OraclePriceAggregatedIntervalKey; -} - -impl TypedColumn for OraclePriceAggregatedIntervalKey { - type Type = model::OraclePriceAggregatedIntervalId; -} diff --git a/lib/ain-ocean/src/storage/columns/oracle_price_feed.rs b/lib/ain-ocean/src/storage/columns/oracle_price_feed.rs deleted file mode 100644 index 32e7acedc7e..00000000000 --- a/lib/ain-ocean/src/storage/columns/oracle_price_feed.rs +++ /dev/null @@ -1,33 +0,0 @@ -use ain_db::{Column, ColumnName, TypedColumn}; - -use crate::model::{ - OraclePriceFeed as OraclePriceFeedMapper, OraclePriceFeedId, OraclePriceFeedkey, -}; -#[derive(Debug)] -pub struct OraclePriceFeed; - -impl ColumnName for OraclePriceFeed { - const NAME: &'static str = "oracle_price_feed"; -} - -impl Column for OraclePriceFeed { - type Index = OraclePriceFeedId; -} - -impl TypedColumn for OraclePriceFeed { - type Type = OraclePriceFeedMapper; -} - -pub struct OraclePriceFeedKey; - -impl ColumnName for OraclePriceFeedKey { - const NAME: &'static str = "oracle_price_feed_key"; -} - -impl Column for OraclePriceFeedKey { - type Index = OraclePriceFeedkey; -} - -impl TypedColumn for OraclePriceFeedKey { - type Type = OraclePriceFeedId; -} diff --git a/lib/ain-ocean/src/storage/columns/oracle_token_currency.rs b/lib/ain-ocean/src/storage/columns/oracle_token_currency.rs deleted file mode 100644 index 42eed45f6eb..00000000000 --- a/lib/ain-ocean/src/storage/columns/oracle_token_currency.rs +++ /dev/null @@ -1,31 +0,0 @@ -use ain_db::{Column, ColumnName, TypedColumn}; - -use crate::model; -#[derive(Debug)] -pub struct OracleTokenCurrency; - -impl ColumnName for OracleTokenCurrency { - const NAME: &'static str = "oracle_token_currency"; -} - -impl Column for OracleTokenCurrency { - type Index = model::OracleTokenCurrencyId; -} - -impl TypedColumn for OracleTokenCurrency { - type Type = model::OracleTokenCurrency; -} - -pub struct OracleTokenCurrencyKey; - -impl ColumnName for OracleTokenCurrencyKey { - const NAME: &'static str = "oracle_token_currency_key"; -} - -impl Column for OracleTokenCurrencyKey { - type Index = model::OracleTokenCurrencyKey; -} - -impl TypedColumn for OracleTokenCurrencyKey { - type Type = model::OracleTokenCurrencyId; -} diff --git a/lib/ain-ocean/src/storage/columns/pool_swap.rs b/lib/ain-ocean/src/storage/columns/pool_swap.rs deleted file mode 100644 index db9905dd469..00000000000 --- a/lib/ain-ocean/src/storage/columns/pool_swap.rs +++ /dev/null @@ -1,18 +0,0 @@ -use ain_db::{Column, ColumnName, TypedColumn}; - -use crate::model; - -#[derive(Debug)] -pub struct PoolSwap; - -impl ColumnName for PoolSwap { - const NAME: &'static str = "pool_swap"; -} - -impl Column for PoolSwap { - type Index = model::PoolSwapKey; -} - -impl TypedColumn for PoolSwap { - type Type = model::PoolSwap; -} diff --git a/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs b/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs deleted file mode 100644 index 3924838ea6a..00000000000 --- a/lib/ain-ocean/src/storage/columns/pool_swap_aggregated.rs +++ /dev/null @@ -1,101 +0,0 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, BlockHash}; - -use crate::model; - -#[derive(Debug)] -pub struct PoolSwapAggregated; - -impl ColumnName for PoolSwapAggregated { - const NAME: &'static str = "pool_swap_aggregated"; -} - -impl Column for PoolSwapAggregated { - type Index = model::PoolSwapAggregatedId; - - fn key(index: &Self::Index) -> Result, DBError> { - let (pool_id, interval, block_hash) = index; - let mut vec = Vec::with_capacity(40); - - vec.extend_from_slice(&pool_id.to_be_bytes()); - vec.extend_from_slice(&interval.to_be_bytes()); - vec.extend_from_slice(block_hash.as_byte_array()); - - Ok(vec) - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - if raw_key.len() != 40 { - return Err(format_err!("Length of the slice is not 40").into()); - } - - let pool_id = u32::from_be_bytes( - raw_key[0..4] - .try_into() - .map_err(|_| DBError::WrongKeyLength)?, - ); - let interval = u32::from_be_bytes( - raw_key[4..8] - .try_into() - .map_err(|_| DBError::WrongKeyLength)?, - ); - let block_hash = BlockHash::from_byte_array( - raw_key[8..40] - .try_into() - .map_err(|_| DBError::WrongKeyLength)?, - ); - Ok((pool_id, interval, block_hash)) - } -} - -impl TypedColumn for PoolSwapAggregated { - type Type = model::PoolSwapAggregated; -} - -#[derive(Debug)] -pub struct PoolSwapAggregatedKey; - -impl ColumnName for PoolSwapAggregatedKey { - const NAME: &'static str = "pool_swap_aggregated_key"; -} - -impl Column for PoolSwapAggregatedKey { - type Index = model::PoolSwapAggregatedKey; - - fn key(index: &Self::Index) -> Result, DBError> { - let (pool_id, interval, bucket) = index; - let mut vec = Vec::with_capacity(16); - vec.extend_from_slice(&pool_id.to_be_bytes()); - vec.extend_from_slice(&interval.to_be_bytes()); - vec.extend_from_slice(&bucket.to_be_bytes()); - Ok(vec) - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - if raw_key.len() != 16 { - return Err(format_err!("length of the slice is not 40").into()); - } - let pool_id = u32::from_be_bytes( - raw_key[0..4] - .try_into() - .map_err(|_| DBError::WrongKeyLength)?, - ); - let interval = u32::from_be_bytes( - raw_key[4..8] - .try_into() - .map_err(|_| DBError::WrongKeyLength)?, - ); - let bucket = i64::from_be_bytes( - raw_key[8..16] - .try_into() - .map_err(|_| DBError::WrongKeyLength)?, - ); - - Ok((pool_id, interval, bucket)) - } -} - -impl TypedColumn for PoolSwapAggregatedKey { - type Type = model::PoolSwapAggregatedId; -} diff --git a/lib/ain-ocean/src/storage/columns/poolpair.rs b/lib/ain-ocean/src/storage/columns/poolpair.rs deleted file mode 100644 index 184bb5e7e67..00000000000 --- a/lib/ain-ocean/src/storage/columns/poolpair.rs +++ /dev/null @@ -1,31 +0,0 @@ -use ain_db::{Column, ColumnName, TypedColumn}; - -#[derive(Debug)] -pub struct PoolPairByHeight; - -impl ColumnName for PoolPairByHeight { - const NAME: &'static str = "poolpair_by_height"; -} - -impl Column for PoolPairByHeight { - type Index = (u32, usize); -} - -impl TypedColumn for PoolPairByHeight { - type Type = (u32, u32, u32); -} - -#[derive(Debug)] -pub struct PoolPair; - -impl ColumnName for PoolPair { - const NAME: &'static str = "poolpair"; -} - -impl Column for PoolPair { - type Index = (u32, u32); -} - -impl TypedColumn for PoolPair { - type Type = u32; -} diff --git a/lib/ain-ocean/src/storage/columns/price_ticker.rs b/lib/ain-ocean/src/storage/columns/price_ticker.rs deleted file mode 100644 index bf69e578709..00000000000 --- a/lib/ain-ocean/src/storage/columns/price_ticker.rs +++ /dev/null @@ -1,65 +0,0 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; - -use crate::model; - -#[derive(Debug)] -pub struct PriceTicker; - -impl ColumnName for PriceTicker { - const NAME: &'static str = "price_ticker"; -} - -impl Column for PriceTicker { - type Index = model::PriceTickerId; -} - -impl TypedColumn for PriceTicker { - type Type = model::PriceTicker; -} - -#[derive(Debug)] -pub struct PriceTickerKey; - -impl ColumnName for PriceTickerKey { - const NAME: &'static str = "price_ticker_key"; -} - -impl Column for PriceTickerKey { - type Index = model::PriceTickerKey; - - fn key(index: &Self::Index) -> Result, DBError> { - let (total, height, token, currency) = index; - let mut vec = Vec::new(); - vec.extend_from_slice(&total.to_be_bytes()); - vec.extend_from_slice(&height.to_be_bytes()); - vec.extend_from_slice(token.as_bytes()); - vec.extend_from_slice(currency.as_bytes()); - Ok(vec) - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - let total = i32::from_be_bytes( - raw_key[0..4] - .try_into() - .map_err(|_| DBError::WrongKeyLength)?, - ); - let height = u32::from_be_bytes( - raw_key[4..8] - .try_into() - .map_err(|_| DBError::WrongKeyLength)?, - ); - - let currency_n = raw_key.len() - 3; // 3 letters of currency code - let token = std::str::from_utf8(&raw_key[8..currency_n]) - .map_err(|_| DBError::ParseKey)? - .to_string(); - let currency = std::str::from_utf8(&raw_key[currency_n..]) - .map_err(|_| DBError::ParseKey)? - .to_string(); - Ok((total, height, token, currency)) - } -} - -impl TypedColumn for PriceTickerKey { - type Type = model::PriceTickerId; -} diff --git a/lib/ain-ocean/src/storage/columns/raw_block.rs b/lib/ain-ocean/src/storage/columns/raw_block.rs deleted file mode 100644 index aa9ae79d1a7..00000000000 --- a/lib/ain-ocean/src/storage/columns/raw_block.rs +++ /dev/null @@ -1,17 +0,0 @@ -use ain_db::{Column, ColumnName, TypedColumn}; -use bitcoin::BlockHash; - -#[derive(Debug)] -pub struct RawBlock; - -impl ColumnName for RawBlock { - const NAME: &'static str = "raw_block"; -} - -impl Column for RawBlock { - type Index = BlockHash; -} - -impl TypedColumn for RawBlock { - type Type = String; -} diff --git a/lib/ain-ocean/src/storage/columns/script_activity.rs b/lib/ain-ocean/src/storage/columns/script_activity.rs deleted file mode 100644 index f9b8b9f17a7..00000000000 --- a/lib/ain-ocean/src/storage/columns/script_activity.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::model; -use ain_db::{Column, ColumnName, TypedColumn}; - -#[derive(Debug)] -pub struct ScriptActivity; - -impl ColumnName for ScriptActivity { - const NAME: &'static str = "script_activity"; -} - -impl Column for ScriptActivity { - type Index = model::ScriptActivityId; -} - -impl TypedColumn for ScriptActivity { - type Type = model::ScriptActivity; -} diff --git a/lib/ain-ocean/src/storage/columns/script_aggregation.rs b/lib/ain-ocean/src/storage/columns/script_aggregation.rs deleted file mode 100644 index eecbba4135d..00000000000 --- a/lib/ain-ocean/src/storage/columns/script_aggregation.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::model; -use ain_db::{Column, ColumnName, TypedColumn}; - -#[derive(Debug)] -pub struct ScriptAggregation; - -impl ColumnName for ScriptAggregation { - const NAME: &'static str = "script_aggregation"; -} - -impl Column for ScriptAggregation { - type Index = model::ScriptAggregationId; -} - -impl TypedColumn for ScriptAggregation { - type Type = model::ScriptAggregation; -} diff --git a/lib/ain-ocean/src/storage/columns/script_unspent.rs b/lib/ain-ocean/src/storage/columns/script_unspent.rs deleted file mode 100644 index 52c77205126..00000000000 --- a/lib/ain-ocean/src/storage/columns/script_unspent.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::model; -use ain_db::{Column, ColumnName, TypedColumn}; - -#[derive(Debug)] -pub struct ScriptUnspent; - -impl ColumnName for ScriptUnspent { - const NAME: &'static str = "script_unspent"; -} - -impl Column for ScriptUnspent { - type Index = model::ScriptUnspentId; -} - -impl TypedColumn for ScriptUnspent { - type Type = model::ScriptUnspent; -} - -#[derive(Debug)] -pub struct ScriptUnspentKey; - -impl ColumnName for ScriptUnspentKey { - const NAME: &'static str = "script_unspent_key"; -} - -impl Column for ScriptUnspentKey { - type Index = model::ScriptUnspentKey; -} - -impl TypedColumn for ScriptUnspentKey { - type Type = model::ScriptUnspentId; -} diff --git a/lib/ain-ocean/src/storage/columns/transaction.rs b/lib/ain-ocean/src/storage/columns/transaction.rs deleted file mode 100644 index 3d48b099b5c..00000000000 --- a/lib/ain-ocean/src/storage/columns/transaction.rs +++ /dev/null @@ -1,54 +0,0 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, BlockHash, Txid}; - -use crate::model; -#[derive(Debug)] -pub struct Transaction; - -impl ColumnName for Transaction { - const NAME: &'static str = "transaction"; -} - -impl Column for Transaction { - type Index = Txid; -} - -impl TypedColumn for Transaction { - type Type = model::Transaction; -} - -pub struct TransactionByBlockHash; - -impl ColumnName for TransactionByBlockHash { - const NAME: &'static str = "transaction_by_block_hash"; -} - -impl Column for TransactionByBlockHash { - type Index = model::TransactionByBlockHashKey; - - fn key(index: &Self::Index) -> Result, DBError> { - let (hash, txno) = index; - let mut vec = hash.as_byte_array().to_vec(); - vec.extend_from_slice(&txno.to_be_bytes()); - Ok(vec) - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - if raw_key.len() != 40 { - return Err(format_err!("Length of the slice is not 40").into()); - } - let mut hash_array = [0u8; 32]; - hash_array.copy_from_slice(&raw_key[..32]); - let mut txno_array = [0u8; 8]; - txno_array.copy_from_slice(&raw_key[32..]); - - let hash = BlockHash::from_byte_array(hash_array); - let txno = usize::from_be_bytes(txno_array); - Ok((hash, txno)) - } -} - -impl TypedColumn for TransactionByBlockHash { - type Type = Txid; -} diff --git a/lib/ain-ocean/src/storage/columns/transaction_vin.rs b/lib/ain-ocean/src/storage/columns/transaction_vin.rs deleted file mode 100644 index f8d6116a966..00000000000 --- a/lib/ain-ocean/src/storage/columns/transaction_vin.rs +++ /dev/null @@ -1,18 +0,0 @@ -use ain_db::{Column, ColumnName, TypedColumn}; - -use crate::model; - -#[derive(Debug)] -pub struct TransactionVin; - -impl ColumnName for TransactionVin { - const NAME: &'static str = "transaction_vin"; -} - -impl Column for TransactionVin { - type Index = String; -} - -impl TypedColumn for TransactionVin { - type Type = model::TransactionVin; -} diff --git a/lib/ain-ocean/src/storage/columns/transaction_vout.rs b/lib/ain-ocean/src/storage/columns/transaction_vout.rs deleted file mode 100644 index 741a5d1b19c..00000000000 --- a/lib/ain-ocean/src/storage/columns/transaction_vout.rs +++ /dev/null @@ -1,40 +0,0 @@ -use ain_db::{Column, ColumnName, DBError, TypedColumn}; -use anyhow::format_err; -use bitcoin::{hashes::Hash, Txid}; - -use crate::model; -#[derive(Debug)] -pub struct TransactionVout; - -impl ColumnName for TransactionVout { - const NAME: &'static str = "transaction_vout"; -} - -impl Column for TransactionVout { - type Index = model::TransactionVoutKey; - - fn key(index: &Self::Index) -> Result, DBError> { - let (txid, txno) = index; - let mut vec = txid.as_byte_array().to_vec(); - vec.extend_from_slice(&txno.to_be_bytes()); - Ok(vec) - } - - fn get_key(raw_key: Box<[u8]>) -> Result { - if raw_key.len() != 40 { - return Err(format_err!("length of the slice is not 40").into()); - } - let mut hash_array = [0u8; 32]; - hash_array.copy_from_slice(&raw_key[..32]); - let mut txno_array = [0u8; 8]; - txno_array.copy_from_slice(&raw_key[32..]); - - let txid = Txid::from_byte_array(hash_array); - let txno = usize::from_be_bytes(txno_array); - Ok((txid, txno)) - } -} - -impl TypedColumn for TransactionVout { - type Type = model::TransactionVout; -} diff --git a/lib/ain-ocean/src/storage/columns/tx_result.rs b/lib/ain-ocean/src/storage/columns/tx_result.rs deleted file mode 100644 index 03bbc04f0cc..00000000000 --- a/lib/ain-ocean/src/storage/columns/tx_result.rs +++ /dev/null @@ -1,19 +0,0 @@ -use ain_db::{Column, ColumnName, TypedColumn}; -use bitcoin::Txid; - -use crate::model; - -#[derive(Debug)] -pub struct TxResult; - -impl ColumnName for TxResult { - const NAME: &'static str = "tx_result"; -} - -impl Column for TxResult { - type Index = Txid; -} - -impl TypedColumn for TxResult { - type Type = model::TxResult; -} diff --git a/lib/ain-ocean/src/storage/columns/vault_auction_history.rs b/lib/ain-ocean/src/storage/columns/vault_auction_history.rs deleted file mode 100644 index ebfa2a0b110..00000000000 --- a/lib/ain-ocean/src/storage/columns/vault_auction_history.rs +++ /dev/null @@ -1,34 +0,0 @@ -use ain_db::{Column, ColumnName, TypedColumn}; - -use crate::model; - -#[derive(Debug)] -pub struct VaultAuctionHistory; - -impl ColumnName for VaultAuctionHistory { - const NAME: &'static str = "vault_auction_history"; -} - -impl Column for VaultAuctionHistory { - type Index = model::AuctionHistoryKey; -} - -impl TypedColumn for VaultAuctionHistory { - type Type = model::VaultAuctionBatchHistory; -} - -// Secondary index by block height and txno -#[derive(Debug)] -pub struct VaultAuctionHistoryByHeight; - -impl ColumnName for VaultAuctionHistoryByHeight { - const NAME: &'static str = "vault_auction_history_by_height"; -} - -impl Column for VaultAuctionHistoryByHeight { - type Index = model::AuctionHistoryByHeightKey; -} - -impl TypedColumn for VaultAuctionHistoryByHeight { - type Type = model::AuctionHistoryKey; -} diff --git a/lib/ain-ocean/src/storage/macros.rs b/lib/ain-ocean/src/storage/macros.rs new file mode 100644 index 00000000000..e8e37c9086c --- /dev/null +++ b/lib/ain-ocean/src/storage/macros.rs @@ -0,0 +1,109 @@ +#[macro_export] +macro_rules! define_table { + ( + $(#[$meta:meta])* + $vis:vis struct $name:ident { + key_type = $key_type:ty, + value_type = $value_type:ty, + $(custom_key = { $($custom_key:tt)* },)? + $(custom_value = { $($custom_value:tt)* },)? + } + $(, SecondaryIndex = $primary_column:ty)? + $(, InitialKeyProvider = |$pk:ident: $pk_type:ty| $initial_key_expr:expr)? + ) => { + // Repository definition + $(#[$meta])* + $vis struct $name { + pub store: Arc, + col: LedgerColumn<$name>, + } + + impl ColumnName for $name { + const NAME: &'static str = stringify!($name); + } + + impl Column for $name { + type Index = $key_type; + + $( + $($custom_key)* + )? + } + + impl TypedColumn for $name { + type Type = $value_type; + + $( + $($custom_value)* + )? + } + + + impl $name { + pub fn new(store: Arc) -> Self { + Self { + col: store.column(), + store, + } + } + + $( + #[allow(unused)] + pub fn get_highest(&self) -> Result::Type>> { + match self.col.iter(None, SortOrder::Descending.into())?.next() { + None => Ok(None), + Some(Ok((_, id))) => { + let col = self.store.column::<$primary_column>(); + Ok(col.get(&id)?) + } + Some(Err(e)) => Err(e.into()), + } + } + )? + } + + impl RepositoryOps<$key_type, $value_type> for $name { + type ListItem = std::result::Result<($key_type, $value_type), ain_db::DBError>; + + fn get(&self, id: &$key_type) -> Result> { + Ok(self.col.get(id)?) + } + + fn put(&self, id: &$key_type, item: &$value_type) -> Result<()> { + Ok(self.col.put(id, item)?) + } + + fn delete(&self, id: &$key_type) -> Result<()> { + Ok(self.col.delete(id)?) + } + + fn list<'a>(&'a self, from: Option<$key_type>, dir: $crate::storage::SortOrder) -> Result + 'a>> { + let it = self.col.iter(from, dir.into())?; + Ok(Box::new(it)) + } + } + + $( + impl SecondaryIndex<$key_type, $value_type> for $name { + type Value = <$primary_column as TypedColumn>::Type; + + fn retrieve_primary_value(&self, el: Self::ListItem) -> Result { + let (_, id) = el?; + let col = self.store.column::<$primary_column>(); + let value = col.get(&id)?.ok_or(Error::SecondaryIndex)?; + Ok(value) + } + } + )? + + $( + impl InitialKeyProvider<$key_type, $value_type> for $name { + type PartialKey = $pk_type; + + fn initial_key($pk: Self::PartialKey) -> $key_type { + $initial_key_expr + } + } + )? + }; +} diff --git a/lib/ain-ocean/src/storage/mod.rs b/lib/ain-ocean/src/storage/mod.rs index 25828fe4959..0b8daadcfa9 100644 --- a/lib/ain-ocean/src/storage/mod.rs +++ b/lib/ain-ocean/src/storage/mod.rs @@ -1,7 +1,15 @@ -use rocksdb::Direction; +#[macro_use] +mod macros; + +mod ocean_store; -pub mod columns; -pub mod ocean_store; +use std::sync::Arc; + +use crate::{define_table, model, Error, Result}; +use ain_db::{Column, ColumnName, DBError, LedgerColumn, Result as DBResult, TypedColumn}; +use bitcoin::{hashes::Hash, BlockHash, Txid}; +pub use ocean_store::OceanStore; +use rocksdb::Direction; #[derive(Debug, PartialEq, Clone)] pub enum SortOrder { @@ -17,3 +25,502 @@ impl From for Direction { } } } + +pub trait RepositoryOps { + type ListItem; + fn get(&self, key: &K) -> Result>; + fn put(&self, key: &K, value: &V) -> Result<()>; + fn delete(&self, key: &K) -> Result<()>; + fn list<'a>( + &'a self, + from: Option, + direction: SortOrder, + ) -> Result + 'a>>; +} + +pub trait InitialKeyProvider: RepositoryOps { + type PartialKey; + fn initial_key(pk: Self::PartialKey) -> K; +} + +pub trait SecondaryIndex: RepositoryOps { + type Value; + fn retrieve_primary_value(&self, el: Self::ListItem) -> Result; +} + +define_table! { + #[derive(Debug)] + pub struct Block { + key_type = BlockHash, + value_type = model::Block, + } +} + +define_table! { + #[derive(Debug)] + pub struct BlockByHeight { + key_type = u32, + value_type = BlockHash, + custom_key = { + fn key(index: &Self::Index) -> DBResult> { + Ok(index.to_be_bytes().to_vec()) + } + + fn get_key(raw_key: Box<[u8]>) -> DBResult { + if raw_key.len() != 4 { + return Err(DBError::WrongKeyLength); + } + let mut array = [0u8; 4]; + array.copy_from_slice(&raw_key); + Ok(u32::from_be_bytes(array)) + } + }, + }, + SecondaryIndex = Block +} + +define_table! { + #[derive(Debug)] + pub struct Masternode { + key_type = Txid, + value_type = model::Masternode, + } +} + +define_table! { + #[derive(Debug)] + pub struct MasternodeByHeight { + key_type = (u32, Txid), + value_type = u8, + } +} + +impl SecondaryIndex<(u32, Txid), u8> for MasternodeByHeight { + type Value = model::Masternode; + + fn retrieve_primary_value(&self, el: Self::ListItem) -> Result { + let ((_, id), _) = el?; + let col = self.store.column::(); + let tx = col.get(&id)?.ok_or(Error::SecondaryIndex)?; + Ok(tx) + } +} + +define_table! { + #[derive(Debug)] + pub struct MasternodeStats { + key_type = u32, + value_type = model::MasternodeStats, + custom_key = { + fn key(index: &Self::Index) -> DBResult> { + Ok(index.to_be_bytes().to_vec()) + } + + fn get_key(raw_key: Box<[u8]>) -> DBResult { + if raw_key.len() != 4 { + return Err(DBError::WrongKeyLength); + } + let mut array = [0u8; 4]; + array.copy_from_slice(&raw_key); + Ok(u32::from_be_bytes(array)) + } + }, + } +} + +impl MasternodeStats { + pub fn get_latest(&self) -> Result> { + match self.col.iter(None, SortOrder::Descending.into())?.next() { + None => Ok(None), + Some(Ok((_, id))) => Ok(Some(id)), + Some(Err(e)) => Err(e.into()), + } + } +} + +define_table! { + #[derive(Debug)] + pub struct Oracle { + key_type = Txid, + value_type = model::Oracle, + } +} + +define_table! { + #[derive(Debug)] + pub struct OracleHistory { + key_type = model::OracleHistoryId, + value_type = model::OracleHistory, + } +} + +define_table! { + #[derive(Debug)] + pub struct OracleHistoryOracleIdSort { + key_type = Txid, + value_type = model::OracleHistoryId, + }, + SecondaryIndex = OracleHistory +} + +define_table! { + #[derive(Debug)] + pub struct OraclePriceActive { + key_type = model::OraclePriceActiveId, + value_type = model::OraclePriceActive, + } +} + +define_table! { + #[derive(Debug)] + pub struct OraclePriceActiveKey { + key_type = model::OraclePriceActiveKey, + value_type = model::OraclePriceActiveId, + }, + SecondaryIndex = OraclePriceActive +} + +define_table! { + #[derive(Debug)] + pub struct OraclePriceAggregated { + key_type = model::OraclePriceAggregatedId, + value_type = model::OraclePriceAggregated, + } +} + +define_table! { + #[derive(Debug)] + pub struct OraclePriceAggregatedKey { + key_type = model::OraclePriceAggregatedKey, + value_type = model::OraclePriceAggregatedId, + }, + SecondaryIndex = OraclePriceAggregated +} + +define_table! { + #[derive(Debug)] + pub struct OraclePriceAggregatedInterval { + key_type = model::OraclePriceAggregatedIntervalId, + value_type = model::OraclePriceAggregatedInterval, + } +} + +define_table! { + #[derive(Debug)] + pub struct OraclePriceAggregatedIntervalKey { + key_type = model::OraclePriceAggregatedIntervalKey, + value_type = model::OraclePriceAggregatedIntervalId, + }, + SecondaryIndex = OraclePriceAggregatedInterval +} + +define_table! { + #[derive(Debug)] + pub struct OraclePriceFeed { + key_type = model::OraclePriceFeedId, + value_type = model::OraclePriceFeed, + } +} + +define_table! { + #[derive(Debug)] + pub struct OraclePriceFeedKey { + key_type = model::OraclePriceFeedkey, + value_type = model::OraclePriceFeedId, + }, + SecondaryIndex = OraclePriceFeed +} + +define_table! { + #[derive(Debug)] + pub struct OracleTokenCurrency { + key_type = model::OracleTokenCurrencyId, + value_type = model::OracleTokenCurrency, + } +} + +define_table! { + #[derive(Debug)] + pub struct OracleTokenCurrencyKey { + key_type = model::OracleTokenCurrencyKey, + value_type = model::OracleTokenCurrencyId, + }, + SecondaryIndex = OracleTokenCurrency +} + +define_table! { + #[derive(Debug)] + pub struct PoolSwap { + key_type = model::PoolSwapKey, + value_type = model::PoolSwap, + }, + InitialKeyProvider = |pk: u32| (pk, u32::MAX, usize::MAX) +} + +define_table! { + #[derive(Debug)] + pub struct PoolSwapAggregated { + key_type = model::PoolSwapAggregatedId, + value_type = model::PoolSwapAggregated, + } +} + +define_table! { + #[derive(Debug)] + pub struct PoolSwapAggregatedKey { + key_type = model::PoolSwapAggregatedKey, + value_type = model::PoolSwapAggregatedId, + custom_key = { + fn key(index: &Self::Index) -> DBResult> { + let (pool_id, interval, bucket) = index; + let mut vec = Vec::with_capacity(16); + vec.extend_from_slice(&pool_id.to_be_bytes()); + vec.extend_from_slice(&interval.to_be_bytes()); + vec.extend_from_slice(&bucket.to_be_bytes()); + Ok(vec) + } + + fn get_key(raw_key: Box<[u8]>) -> DBResult { + if raw_key.len() != 16 { + return Err(DBError::WrongKeyLength); + } + let pool_id = u32::from_be_bytes( + raw_key[0..4] + .try_into() + .map_err(|_| DBError::WrongKeyLength)?, + ); + let interval = u32::from_be_bytes( + raw_key[4..8] + .try_into() + .map_err(|_| DBError::WrongKeyLength)?, + ); + let bucket = i64::from_be_bytes( + raw_key[8..16] + .try_into() + .map_err(|_| DBError::WrongKeyLength)?, + ); + + Ok((pool_id, interval, bucket)) + } + }, + }, + SecondaryIndex = PoolSwapAggregated +} + +define_table! { + #[derive(Debug)] + pub struct PoolPair { + key_type = (u32, u32), + value_type = u32, + } +} + +define_table! { + #[derive(Debug)] + pub struct PoolPairByHeight { + key_type = (u32, usize), + value_type = (u32, u32, u32), + } +} + +define_table! { + #[derive(Debug)] + pub struct PriceTicker { + key_type = model::PriceTickerId, + value_type = model::PriceTicker, + } +} + +define_table! { + #[derive(Debug)] + pub struct PriceTickerKey { + key_type = model::PriceTickerKey, + value_type = model::PriceTickerId, + }, + SecondaryIndex = PriceTicker +} + +define_table! { + #[derive(Debug)] + pub struct RawBlock { + key_type = BlockHash, + value_type = String, + } +} + +define_table! { + #[derive(Debug)] + pub struct ScriptActivity { + key_type = model::ScriptActivityId, + value_type = model::ScriptActivity, + } +} + +define_table! { + #[derive(Debug)] + pub struct ScriptAggregation { + key_type = model::ScriptAggregationId, + value_type = model::ScriptAggregation, + } +} + +define_table! { + #[derive(Debug)] + pub struct ScriptUnspent { + key_type = model::ScriptUnspentId, + value_type = model::ScriptUnspent, + } +} + +define_table! { + #[derive(Debug)] + pub struct ScriptUnspentKey { + key_type = model::ScriptUnspentKey, + value_type = model::ScriptUnspentId, + }, + SecondaryIndex = ScriptUnspent +} + +define_table! { + #[derive(Debug)] + pub struct Transaction { + key_type = Txid, + value_type = model::Transaction, + } +} + +define_table! { + #[derive(Debug)] + pub struct TransactionByBlockHash { + key_type = model::TransactionByBlockHashKey, + value_type = Txid, + custom_key = { + fn key(index: &Self::Index) -> DBResult> { + let (hash, txno) = index; + let mut vec = hash.as_byte_array().to_vec(); + vec.extend_from_slice(&txno.to_be_bytes()); + Ok(vec) + } + + fn get_key(raw_key: Box<[u8]>) -> DBResult { + if raw_key.len() != 40 { + return Err(DBError::WrongKeyLength); + } + let mut hash_array = [0u8; 32]; + hash_array.copy_from_slice(&raw_key[..32]); + let mut txno_array = [0u8; 8]; + txno_array.copy_from_slice(&raw_key[32..]); + + let hash = BlockHash::from_byte_array(hash_array); + let txno = usize::from_be_bytes(txno_array); + Ok((hash, txno)) + } + }, + }, + SecondaryIndex = Transaction, + InitialKeyProvider = |pk: BlockHash| (pk, 0) +} + +define_table! { + #[derive(Debug)] + pub struct TransactionVin { + key_type = String, + value_type = model::TransactionVin, + }, + InitialKeyProvider = |pk: Txid| format!("{}00", pk) +} + +define_table! { + #[derive(Debug)] + pub struct TransactionVout { + key_type = model::TransactionVoutKey, + value_type = model::TransactionVout, + custom_key = { + fn key(index: &Self::Index) -> DBResult> { + let (txid, txno) = index; + let mut vec = txid.as_byte_array().to_vec(); + vec.extend_from_slice(&txno.to_be_bytes()); + Ok(vec) + } + + fn get_key(raw_key: Box<[u8]>) -> DBResult { + if raw_key.len() != 40 { + return Err(DBError::WrongKeyLength); + } + let mut hash_array = [0u8; 32]; + hash_array.copy_from_slice(&raw_key[..32]); + let mut txno_array = [0u8; 8]; + txno_array.copy_from_slice(&raw_key[32..]); + + let txid = Txid::from_byte_array(hash_array); + let txno = usize::from_be_bytes(txno_array); + Ok((txid, txno)) + } + }, + } +} + +define_table! { + #[derive(Debug)] + pub struct TxResult { + key_type = Txid, + value_type = model::TxResult, + } +} + +define_table! { + #[derive(Debug)] + pub struct VaultAuctionHistory { + key_type = model::AuctionHistoryKey, + value_type = model::VaultAuctionBatchHistory, + } +} + +define_table! { + #[derive(Debug)] + pub struct VaultAuctionHistoryByHeight { + key_type = model::AuctionHistoryByHeightKey, + value_type = model::AuctionHistoryKey, + }, + SecondaryIndex = VaultAuctionHistory +} + +pub const COLUMN_NAMES: [&str; 37] = [ + Block::NAME, + BlockByHeight::NAME, + MasternodeStats::NAME, + Masternode::NAME, + MasternodeByHeight::NAME, + Oracle::NAME, + OracleHistory::NAME, + OracleHistoryOracleIdSort::NAME, + OraclePriceActive::NAME, + OraclePriceActiveKey::NAME, + OraclePriceAggregated::NAME, + OraclePriceAggregatedKey::NAME, + OraclePriceAggregatedInterval::NAME, + OraclePriceAggregatedIntervalKey::NAME, + OraclePriceFeed::NAME, + OraclePriceFeedKey::NAME, + OracleTokenCurrency::NAME, + OracleTokenCurrencyKey::NAME, + PoolSwapAggregated::NAME, + PoolSwapAggregatedKey::NAME, + PoolSwap::NAME, + PoolPair::NAME, + PoolPairByHeight::NAME, + PriceTicker::NAME, + PriceTickerKey::NAME, + RawBlock::NAME, + ScriptActivity::NAME, + ScriptAggregation::NAME, + ScriptUnspent::NAME, + ScriptUnspentKey::NAME, + Transaction::NAME, + TransactionByBlockHash::NAME, + TransactionVin::NAME, + TransactionVout::NAME, + TxResult::NAME, + VaultAuctionHistory::NAME, + VaultAuctionHistoryByHeight::NAME, +]; diff --git a/lib/ain-ocean/src/storage/ocean_store.rs b/lib/ain-ocean/src/storage/ocean_store.rs index e1f85a287d3..8f99a422dad 100644 --- a/lib/ain-ocean/src/storage/ocean_store.rs +++ b/lib/ain-ocean/src/storage/ocean_store.rs @@ -2,7 +2,7 @@ use std::{fs, marker::PhantomData, path::Path, sync::Arc}; use ain_db::{Column, ColumnName, LedgerColumn, Rocks}; -use super::columns::COLUMN_NAMES; +use super::COLUMN_NAMES; use crate::Result; #[derive(Debug, Clone)] From bb24bd814a5f4f9cd8b437fc91934aa29216ce96 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Thu, 29 Aug 2024 21:52:34 +0800 Subject: [PATCH 137/185] Ocean: fix rm oracle indexer, oracle & price apis (#3013) * rm oracle indexer * br * fix oracle & price apis * fmt * rm split_key * naming * fix prices api 2 * tying * fmt --------- Co-authored-by: Jouzo <15011228+Jouzo@users.noreply.github.com> --- lib/ain-ocean/src/api/common.rs | 12 - lib/ain-ocean/src/api/oracle.rs | 59 ++-- lib/ain-ocean/src/api/prices.rs | 332 +++++++++--------- lib/ain-ocean/src/indexer/oracle.rs | 53 ++- lib/ain-ocean/src/model/oracle.rs | 17 +- lib/ain-ocean/src/model/oracle_price_feed.rs | 17 +- .../src/model/oracle_token_currency.rs | 1 + 7 files changed, 224 insertions(+), 267 deletions(-) diff --git a/lib/ain-ocean/src/api/common.rs b/lib/ain-ocean/src/api/common.rs index 5d06eecf7cd..0d657528739 100644 --- a/lib/ain-ocean/src/api/common.rs +++ b/lib/ain-ocean/src/api/common.rs @@ -182,15 +182,3 @@ where Box::new(self.skip(query.next.is_some() as usize).take(query.size)) } } - -pub fn split_key(key: &str) -> Result<(String, String), String> { - let parts: Vec<&str> = key.split('-').collect(); - if parts.len() == 2 { - Ok((parts[0].to_owned(), parts[1].to_owned())) - } else { - Err(format!( - "Invalid key format: '{}'. Expected format 'token-currency'.", - key - )) - } -} diff --git a/lib/ain-ocean/src/api/oracle.rs b/lib/ain-ocean/src/api/oracle.rs index 6c9524f41e4..efe4fcc2ac9 100644 --- a/lib/ain-ocean/src/api/oracle.rs +++ b/lib/ain-ocean/src/api/oracle.rs @@ -2,7 +2,7 @@ use std::{str::FromStr, sync::Arc}; use ain_dftx::COIN; use ain_macros::ocean_endpoint; -use anyhow::anyhow; +use anyhow::Context; use axum::{ extract::{Path, Query}, routing::get, @@ -10,17 +10,17 @@ use axum::{ }; use bitcoin::Txid; use rust_decimal::Decimal; +use serde::{Deserialize, Serialize}; use super::{ - common::split_key, query::PaginationQuery, response::{ApiPagedResponse, Response}, AppContext, }; use crate::{ api::common::Paginate, - error::{ApiError, Error, NotFoundKind}, - model::{ApiResponseOraclePriceFeed, Oracle}, + error::ApiError, + model::{BlockContext, Oracle}, storage::{RepositoryOps, SortOrder}, Result, }; @@ -49,18 +49,34 @@ async fn list_oracles( })) } +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct OraclePriceFeedResponse { + pub id: String, + pub key: String, + pub sort: String, + pub token: String, + pub currency: String, + pub oracle_id: Txid, + pub txid: Txid, + pub time: i32, + pub amount: String, + pub block: BlockContext, +} + #[ocean_endpoint] async fn get_feed( Path((oracle_id, key)): Path<(String, String)>, Query(query): Query, Extension(ctx): Extension>, -) -> Result> { +) -> Result> { let txid = Txid::from_str(&oracle_id)?; - let (token, currency) = match split_key(&key) { - Ok((t, c)) => (t, c), - Err(e) => return Err(Error::Other(anyhow!("Failed to split key: {}", e))), - }; - let key = (token.clone(), currency.clone(), txid); + + let mut parts = key.split('-'); + let token = parts.next().context("Missing token")?; + let currency = parts.next().context("Missing currency")?; + + let key = (token, currency, txid); let price_feed_list = ctx .services @@ -68,7 +84,7 @@ async fn get_feed( .by_id .list(None, SortOrder::Descending)? .paginate(&query) - .map(|res| res.expect("Error retrieving key")) + .flatten() .collect::>(); let mut oracle_price_feeds = Vec::new(); @@ -77,7 +93,7 @@ async fn get_feed( let (token, currency, oracle_id, _) = &feed.id; if key.0.eq(token) && key.1.eq(currency) && key.2.eq(oracle_id) { let amount = Decimal::from(feed.amount) / Decimal::from(COIN); - oracle_price_feeds.push(ApiResponseOraclePriceFeed { + oracle_price_feeds.push(OraclePriceFeedResponse { id: format!("{}-{}-{}-{}", token, currency, feed.oracle_id, feed.txid), key: format!("{}-{}-{}", token, currency, feed.oracle_id), sort: feed.sort.clone(), @@ -86,7 +102,7 @@ async fn get_feed( oracle_id: feed.oracle_id, txid: feed.txid, time: feed.time, - amount: amount.to_string(), + amount: amount.normalize().to_string(), block: feed.block.clone(), }); } @@ -103,23 +119,24 @@ async fn get_feed( async fn get_oracle_by_address( Path(address): Path, Extension(ctx): Extension>, -) -> Result> { - format!("Oracle details for address {}", address); - let (_, oracle) = ctx +) -> Result>> { + let oracles = ctx .services .oracle .by_id .list(None, SortOrder::Descending)? - .filter_map(|item| { - let (id, oracle) = item.ok()?; + .flatten() + .filter_map(|(_, oracle)| { if oracle.owner_address == address { - Some((id, oracle)) + Some(oracle) } else { None } }) - .next() - .ok_or(Error::NotFound(NotFoundKind::Oracle))?; + .collect::>(); + + let oracle = oracles.first().cloned(); + Ok(Response::new(oracle)) } diff --git a/lib/ain-ocean/src/api/prices.rs b/lib/ain-ocean/src/api/prices.rs index 0143e8be700..eadbe483b52 100644 --- a/lib/ain-ocean/src/api/prices.rs +++ b/lib/ain-ocean/src/api/prices.rs @@ -2,28 +2,28 @@ use std::sync::Arc; use ain_dftx::COIN; use ain_macros::ocean_endpoint; -use anyhow::{anyhow, Context}; +use anyhow::Context; use axum::{ extract::{Path, Query}, routing::get, Extension, Router, }; +use bitcoin::{hashes::Hash, Txid}; use indexmap::IndexSet; use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; use super::{ - common::split_key, + oracle::OraclePriceFeedResponse, query::PaginationQuery, response::{ApiPagedResponse, Response}, AppContext, }; use crate::{ - error::{ApiError, Error, NotFoundKind}, + error::{ApiError, Error}, model::{ - ApiResponseOraclePriceFeed, BlockContext, OracleIntervalSeconds, OraclePriceActive, - OraclePriceActiveNextOracles, OraclePriceAggregated, OraclePriceAggregatedInterval, - OraclePriceAggregatedIntervalAggregated, OracleTokenCurrency, PriceOracles, PriceTicker, + BlockContext, OracleIntervalSeconds, OraclePriceActive, OraclePriceActiveNextOracles, + OraclePriceAggregated, OraclePriceAggregatedInterval, OracleTokenCurrency, PriceTicker, }, storage::{RepositoryOps, SortOrder}, Result, @@ -124,27 +124,29 @@ async fn list_prices( price.sort.to_string() })) } + #[ocean_endpoint] async fn get_price( Path(key): Path, Extension(ctx): Extension>, -) -> Result> { - let (token, currency) = match split_key(&key) { - Ok((t, c)) => (t, c), - Err(e) => return Err(Error::Other(anyhow!("Failed to split key: {}", e))), +) -> Result>> { + let mut parts = key.split('-'); + let token = parts.next().context("Missing token")?; + let currency = parts.next().context("Missing currency")?; + + let price_ticker = ctx + .services + .price_ticker + .by_id + .get(&(token.to_string(), currency.to_string()))?; + + let Some(price_ticker) = price_ticker else { + return Ok(Response::new(None)); }; - let price_ticker_id = (token, currency); - if let Some(price_ticker) = ctx.services.price_ticker.by_id.get(&price_ticker_id)? { - if price_ticker.price.token.eq(&price_ticker_id.0) - && price_ticker.price.currency.eq(&price_ticker_id.1) - { - Ok(Response::new(PriceTickerResponse::from(price_ticker))) - } else { - Err(Error::NotFound(NotFoundKind::Oracle)) - } - } else { - Err(Error::NotFound(NotFoundKind::Oracle)) - } + + let res = PriceTickerResponse::from(price_ticker); + + Ok(Response::new(Some(res))) } #[ocean_endpoint] @@ -153,212 +155,196 @@ async fn get_feed( Query(query): Query, Extension(ctx): Extension>, ) -> Result> { - let (token, currency) = match split_key(&key) { - Ok((t, c)) => (t, c), - Err(e) => return Err(Error::Other(anyhow!("Failed to split key: {}", e))), - }; - let aggregated_key = (token, currency); - let mut oracle_aggrigated = Vec::new(); - let aggregated = ctx - .services - .oracle_price_aggregated + let mut parts = key.split('-'); + let token = parts.next().context("Missing token")?; + let currency = parts.next().context("Missing currency")?; + + let repo = &ctx.services.oracle_price_aggregated; + let id = (token.to_string(), currency.to_string(), u32::MAX); + let oracle_aggregated = repo .by_id - .list(None, SortOrder::Ascending)? + .list(Some(id), SortOrder::Descending)? .take(query.size) + .take_while(|item| match item { + Ok((k, _)) => k.0 == token && k.1 == currency, + _ => true, + }) .map(|item| { - let (_, price_aggrigated) = item?; - Ok(price_aggrigated) + let (_, v) = item?; + Ok(v) }) .collect::>>()?; - for aggre in aggregated { - let (token, currency, _) = &aggre.id; - if aggregated_key.0.eq(token) && aggregated_key.1.eq(currency) { - oracle_aggrigated.push(aggre); - } - } Ok(ApiPagedResponse::of( - oracle_aggrigated, + oracle_aggregated, query.size, - |aggre| aggre.sort.to_string(), + |aggregated| aggregated.sort.to_string(), )) } + #[ocean_endpoint] async fn get_feed_active( Path(key): Path, Query(query): Query, Extension(ctx): Extension>, ) -> Result> { - let (token, currency) = match split_key(&key) { - Ok((t, c)) => (t, c), - Err(e) => return Err(Error::Other(anyhow!("Failed to split key: {}", e))), - }; - let price_active_key = (token, currency); - let mut price_list = Vec::new(); + let mut parts = key.split('-'); + let token = parts.next().context("Missing token")?; + let currency = parts.next().context("Missing currency")?; + + let key = (token.to_string(), currency.to_string()); + let repo = &ctx.services.oracle_price_active; let price_active = ctx .services .oracle_price_active - .by_id - .list(None, SortOrder::Descending)? + .by_key + .list(Some(key), SortOrder::Descending)? .take(query.size) - .map(|item| { - let (_, data) = item?; - Ok(data) + .flat_map(|item| { + let (_, id) = item?; + let item = repo.by_id.get(&id)?; + Ok::, Error>(item) }) - .collect::>>()?; - for active in price_active { - let (token, currency, _) = &active.id; - if price_active_key.0.eq(token) && price_active_key.1.eq(currency) { - price_list.push(active); - } - } + .flatten() + .collect::>(); - Ok(ApiPagedResponse::of( - price_list, - query.size, - |price_active| price_active.sort.to_string(), - )) + Ok(ApiPagedResponse::of(price_active, query.size, |price| { + price.sort.to_string() + })) } + #[ocean_endpoint] async fn get_feed_with_interval( Path((key, interval)): Path<(String, String)>, Query(query): Query, Extension(ctx): Extension>, ) -> Result> { - println!("the value {:?} {:?}", key, interval); - let (token, currency) = match split_key(&key) { - Ok((t, c)) => (t, c), - Err(e) => return Err(Error::Other(anyhow!("Failed to split key: {}", e))), - }; + let mut parts = key.split('-'); + let token = parts.next().context("Missing token")?; + let currency = parts.next().context("Missing currency")?; + let interval = match interval.as_str() { "900" => OracleIntervalSeconds::FifteenMinutes, "3600" => OracleIntervalSeconds::OneHour, "86400" => OracleIntervalSeconds::OneDay, _ => return Err(From::from("Invalid interval")), }; - let mut feed_intervals = Vec::new(); - let price_aggregated_interval = (&token, ¤cy, interval.clone()); - let items = ctx - .services - .oracle_price_aggregated_interval - .by_id - .list(None, SortOrder::Descending)? + let key = (token.to_string(), currency.to_string(), interval.clone()); + let repo = &ctx.services.oracle_price_aggregated_interval; + let prices = repo + .by_key + .list(Some(key), SortOrder::Descending)? .take(query.size) - .map(|item| { - let (_, data) = item?; - Ok(data) + .flat_map(|item| { + let (_, id) = item?; + let item = repo.by_id.get(&id)?; + Ok::, Error>(item) }) - .collect::>>()?; - - for oracle_intervals in items { - let (token, currency, _) = &oracle_intervals.key; - if price_aggregated_interval.0.eq(token) && price_aggregated_interval.1.eq(currency) { - feed_intervals.push(OraclePriceAggregatedInterval { - id: oracle_intervals.id, - key: oracle_intervals.key, - sort: oracle_intervals.sort, - token: oracle_intervals.token, - currency: oracle_intervals.currency, - aggregated: OraclePriceAggregatedIntervalAggregated { - amount: oracle_intervals.aggregated.amount, - weightage: oracle_intervals.aggregated.weightage, - count: oracle_intervals.aggregated.count, - oracles: oracle_intervals.aggregated.oracles, - }, - block: oracle_intervals.block, - }); - } - } + .flatten() + .collect::>(); - Ok(ApiPagedResponse::of(feed_intervals, query.size, |item| { + Ok(ApiPagedResponse::of(prices, query.size, |item| { item.sort.clone() })) } +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PriceOracleResponse { + pub id: String, + pub key: String, + pub token: String, + pub currency: String, + pub oracle_id: String, + pub weightage: u8, + pub feed: Option, + pub block: BlockContext, +} + #[ocean_endpoint] async fn get_oracles( Path(key): Path, Query(query): Query, Extension(ctx): Extension>, -) -> Result> { - let (token, currency) = match split_key(&key) { - Ok((t, c)) => (t, c), - Err(e) => return Err(Error::Other(anyhow!("Failed to split key: {}", e))), - }; - let mut oracles_feed = Vec::new(); - let oracle_token_currency_key = (token, currency); - let token_currency: Vec = ctx +) -> Result> { + let mut parts = key.split('-'); + let token = parts.next().context("Missing token")?; + let currency = parts.next().context("Missing currency")?; + + let id = ( + token.to_string(), + currency.to_string(), + Txid::from_byte_array([0xffu8; 32]), + ); + let oracles = ctx .services .oracle_token_currency .by_id - .list(None, SortOrder::Ascending)? + .list(Some(id.clone()), SortOrder::Descending)? .take(query.size) - .map(|item| { - let (_, data) = item?; - Ok(data) + .take_while(|item| match item { + Ok((k, _)) => k.0 == id.0 && k.1 == id.1, + _ => true, }) - .collect::>>()?; - - let price_feed = ctx - .services - .oracle_price_feed - .by_id - .list(None, SortOrder::Ascending)? - .take(query.size) - .map(|item| { - let (_, data) = item?; - Ok(data) + .flat_map(|item| { + let (_, oracle) = item?; + Ok::(oracle) }) - .collect::>>()?; + .collect::>(); - for item in token_currency { - let (token, currency, _) = &item.id; - if oracle_token_currency_key.clone().0.eq(token) - && oracle_token_currency_key.clone().1.eq(currency) - { - let mut oracleprice = None; - for pricefeed in &price_feed { - let (token, currency, _, _) = &pricefeed.id; - if oracle_token_currency_key.clone().0.eq(token) - && oracle_token_currency_key.clone().1.eq(currency) - { - oracleprice = Some(ApiResponseOraclePriceFeed { - id: format!( - "{}{}{}{}", - pricefeed.token, - pricefeed.currency, - pricefeed.oracle_id, - pricefeed.txid - ), - key: format!( - "{}{}{}", - pricefeed.token, pricefeed.currency, pricefeed.oracle_id - ), - sort: pricefeed.sort.clone(), - token: pricefeed.token.clone(), - currency: pricefeed.currency.clone(), - oracle_id: item.oracle_id, - txid: pricefeed.txid, - time: pricefeed.time, - amount: pricefeed.amount.to_string(), - block: pricefeed.block.clone(), - }); - } - } - oracles_feed.push(PriceOracles { - id: format!("{}-{}-{}", item.id.0, item.id.1, item.id.2), - key: format!("{}-{}", item.key.0, item.key.1), - token: item.token, - currency: item.currency, - oracle_id: item.oracle_id.to_string(), - feed: oracleprice, - block: item.block, - weightage: item.weightage, - }); - } + let mut prices = Vec::new(); + for oracle in oracles { + let feeds = ctx + .services + .oracle_price_feed + .by_id + .list( + Some(( + token.to_string(), + currency.to_string(), + oracle.oracle_id, + Txid::from_byte_array([0xffu8; 32]), + )), + SortOrder::Descending, + )? + .take(1) + .take_while(|item| match item { + Ok((k, _)) => k.0 == token && k.1 == currency && k.2 == oracle.oracle_id, + _ => true, + }) + .map(|item| { + let (_, data) = item?; + Ok(data) + }) + .collect::>>()?; + + let feed = feeds.first().cloned(); + + prices.push(PriceOracleResponse { + id: format!("{}-{}-{}", oracle.id.0, oracle.id.1, oracle.id.2), + key: format!("{}-{}", oracle.key.0, oracle.key.1), + token: oracle.token, + currency: oracle.currency, + oracle_id: oracle.oracle_id.to_string(), + weightage: oracle.weightage, + block: oracle.block, + feed: feed.map(|f| OraclePriceFeedResponse { + id: format!("{}-{}-{}-{}", token, currency, f.oracle_id, f.txid), + key: format!("{}-{}-{}", token, currency, f.oracle_id), + sort: f.sort.clone(), + token: f.token.clone(), + currency: f.currency.clone(), + oracle_id: f.oracle_id, + txid: f.txid, + time: f.time, + amount: f.amount.to_string(), + block: f.block.clone(), + }), + }) } - Ok(ApiPagedResponse::of(oracles_feed, query.size, |item| { - item.oracle_id.to_string() + + Ok(ApiPagedResponse::of(prices, query.size, |price| { + price.oracle_id.to_string() })) } diff --git a/lib/ain-ocean/src/indexer/oracle.rs b/lib/ain-ocean/src/indexer/oracle.rs index 79f99be2317..883887e6456 100644 --- a/lib/ain-ocean/src/indexer/oracle.rs +++ b/lib/ain-ocean/src/indexer/oracle.rs @@ -1,7 +1,7 @@ use std::{collections::HashSet, str::FromStr, sync::Arc, vec}; use ain_dftx::oracles::*; -use anyhow::{anyhow, Context as _}; +use anyhow::Context as _; use bitcoin::Txid; use log::debug; use rust_decimal::{ @@ -141,39 +141,33 @@ impl Index for RemoveOracle { fn index(self, services: &Arc, ctx: &Context) -> Result<()> { let oracle_id = ctx.tx.txid; services.oracle.by_id.delete(&oracle_id)?; - let previous_hsitory = get_previous_oracle_history_list(services, oracle_id); - match previous_hsitory { - Ok(previous_oracle) => { - for oracle_history in &previous_oracle { - for price_feed_item in &oracle_history.price_feeds { - let deletion_id = ( - price_feed_item.token.to_owned(), - price_feed_item.currency.to_owned(), - oracle_history.oracle_id, - ); - let deletion_key = ( - price_feed_item.token.to_owned(), - price_feed_item.currency.to_owned(), - oracle_history.block.height, - ); - services.oracle_token_currency.by_id.delete(&deletion_id)?; - services - .oracle_token_currency - .by_key - .delete(&deletion_key)?; - } - } - } - Err(err) => { - return Err(Error::Other(anyhow!("remove oracle : {}", err))); + let previous_oracle = get_previous_oracle_history_list(services, oracle_id)?; + for oracle_history in &previous_oracle { + for price_feed_item in &oracle_history.price_feeds { + let deletion_id = ( + price_feed_item.token.to_owned(), + price_feed_item.currency.to_owned(), + oracle_history.oracle_id, + ); + let deletion_key = ( + price_feed_item.token.to_owned(), + price_feed_item.currency.to_owned(), + oracle_history.block.height, + ); + services.oracle_token_currency.by_id.delete(&deletion_id)?; + services + .oracle_token_currency + .by_key + .delete(&deletion_key)?; } } + Ok(()) } + fn invalidate(&self, services: &Arc, context: &Context) -> Result<()> { let oracle_id = context.tx.txid; - let previous_oracle_history_result = get_previous_oracle_history_list(services, oracle_id); - let previous_oracle_history = previous_oracle_history_result?; + let previous_oracle_history = get_previous_oracle_history_list(services, oracle_id)?; for previous_oracle in previous_oracle_history { let oracle = Oracle { @@ -242,8 +236,7 @@ impl Index for UpdateOracle { //save oracle services.oracle.by_id.put(&oracle.id, &oracle)?; - let previous_oracle_history_result = get_previous_oracle_history_list(services, oracle_id); - let previous_oracle = previous_oracle_history_result?; + let previous_oracle = get_previous_oracle_history_list(services, oracle_id)?; for oracle in previous_oracle { for price_feed_item in &oracle.price_feeds { diff --git a/lib/ain-ocean/src/model/oracle.rs b/lib/ain-ocean/src/model/oracle.rs index 40fb7b19099..ab269273030 100644 --- a/lib/ain-ocean/src/model/oracle.rs +++ b/lib/ain-ocean/src/model/oracle.rs @@ -1,9 +1,9 @@ use bitcoin::Txid; use serde::{Deserialize, Serialize}; -use super::{ApiResponseOraclePriceFeed, BlockContext}; +use super::BlockContext; -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct Oracle { pub id: Txid, @@ -19,16 +19,3 @@ pub struct PriceFeedsItem { pub token: String, pub currency: String, } - -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct PriceOracles { - pub id: String, - pub key: String, - pub token: String, - pub currency: String, - pub oracle_id: String, - pub weightage: u8, - pub feed: Option, - pub block: BlockContext, -} diff --git a/lib/ain-ocean/src/model/oracle_price_feed.rs b/lib/ain-ocean/src/model/oracle_price_feed.rs index 69901ed96d9..73b685b5f12 100644 --- a/lib/ain-ocean/src/model/oracle_price_feed.rs +++ b/lib/ain-ocean/src/model/oracle_price_feed.rs @@ -5,7 +5,7 @@ use super::BlockContext; pub type OraclePriceFeedId = (String, String, Txid, Txid); // token-currency-oracle_id-txid pub type OraclePriceFeedkey = (String, String, Txid); // token-currency-oracle_id -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct OraclePriceFeed { pub id: OraclePriceFeedId, @@ -19,18 +19,3 @@ pub struct OraclePriceFeed { pub amount: i64, pub block: BlockContext, } - -#[derive(Serialize, Deserialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct ApiResponseOraclePriceFeed { - pub id: String, - pub key: String, - pub sort: String, - pub token: String, - pub currency: String, - pub oracle_id: Txid, - pub txid: Txid, - pub time: i32, - pub amount: String, - pub block: BlockContext, -} diff --git a/lib/ain-ocean/src/model/oracle_token_currency.rs b/lib/ain-ocean/src/model/oracle_token_currency.rs index 2fe9c8acbf9..bd69e3abfe9 100644 --- a/lib/ain-ocean/src/model/oracle_token_currency.rs +++ b/lib/ain-ocean/src/model/oracle_token_currency.rs @@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize}; use super::BlockContext; pub type OracleTokenCurrencyId = (String, String, Txid); //token-currency-oracleId pub type OracleTokenCurrencyKey = (String, String, u32); //token-currency-height + #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct OracleTokenCurrency { From fb42f7e20fb55819295675d3c7eff55fc82c55f4 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Wed, 4 Sep 2024 15:40:11 +0800 Subject: [PATCH 138/185] Ocean: feat Snafu (#3017) * wip * wip * rough snafu * rm unuse * rm unuse * pub type Token, Currency, Weightage * parse_token_currency, parse_pool_pair_symbol * parse_amount * fmt * parse_fixed_interval_price * parse_query_height_txno * rm unuse * NotFoundKindToken(id) * refactor dup * rm unuse * track over underflow location * fmt * ToPrimitiveError * track location at invalid format errors * rm unuse * snafu display correction * rm anyhow & thiserror deps ocean * replace .ok_or by .context * refine notfound err * apply alias on Token, Currency and Weightage * fmt * fix notfound token with id * remap rpc error * rm unuse * fix vault not found * typo * rust_decimal::serde::str * fix notfound errmsg * rm skip if none on tokendata.col_addr * fmt * fix burn token err msg * fix collateral token errmsg * fix burn not tradeable errmsg * invaliddefiaddress errmsg * fix getacchis errmsg * fmt * fix getloantoken errmsg * fix gettoken errmsg * set context false for `?` underlying error * rm string debug fmt --- lib/Cargo.lock | 24 +- lib/ain-dftx/src/types/mod.rs | 4 + lib/ain-ocean/Cargo.toml | 3 +- lib/ain-ocean/src/api/address.rs | 5 +- lib/ain-ocean/src/api/block.rs | 5 +- lib/ain-ocean/src/api/common.rs | 90 +++++- lib/ain-ocean/src/api/governance.rs | 14 +- lib/ain-ocean/src/api/loan.rs | 111 ++++--- lib/ain-ocean/src/api/masternode/mod.rs | 12 +- lib/ain-ocean/src/api/oracle.rs | 12 +- lib/ain-ocean/src/api/pool_pair/mod.rs | 153 ++++----- lib/ain-ocean/src/api/pool_pair/path.rs | 62 ++-- lib/ain-ocean/src/api/pool_pair/price.rs | 18 +- lib/ain-ocean/src/api/pool_pair/service.rs | 159 +++++---- lib/ain-ocean/src/api/prices.rs | 43 ++- lib/ain-ocean/src/api/rawtx.rs | 37 ++- lib/ain-ocean/src/api/stats/cache.rs | 38 +-- lib/ain-ocean/src/api/stats/mod.rs | 7 +- lib/ain-ocean/src/api/tokens.rs | 14 +- lib/ain-ocean/src/error.rs | 306 ++++++++++++------ lib/ain-ocean/src/indexer/masternode.rs | 6 +- lib/ain-ocean/src/indexer/mod.rs | 7 +- lib/ain-ocean/src/indexer/oracle.rs | 45 +-- lib/ain-ocean/src/indexer/poolswap.rs | 16 +- lib/ain-ocean/src/indexer/transaction.rs | 5 +- lib/ain-ocean/src/model/oracle.rs | 7 +- lib/ain-ocean/src/model/oracle_history.rs | 3 +- .../src/model/oracle_price_active.rs | 3 +- .../src/model/oracle_price_aggregated.rs | 5 +- .../model/oracle_price_aggregated_interval.rs | 7 +- lib/ain-ocean/src/model/oracle_price_feed.rs | 5 +- .../src/model/oracle_token_currency.rs | 7 +- 32 files changed, 726 insertions(+), 507 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 7f1c521147d..15072d2abd8 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -245,7 +245,6 @@ dependencies = [ "ain-db", "ain-dftx", "ain-macros", - "anyhow", "axum 0.7.5", "bincode", "bitcoin", @@ -275,9 +274,9 @@ dependencies = [ "serde_urlencoded", "serde_with", "sha2 0.10.8", + "snafu", "tempdir", "tempfile", - "thiserror", "tokio", ] @@ -5339,6 +5338,27 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "snafu" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b835cb902660db3415a672d862905e791e54d306c6e8189168c7f3d9ae1c79d" +dependencies = [ + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d1e02fca405f6280643174a50c942219f0bbf4dbf7d480f1dd864d6f211ae5" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "socket2" version = "0.5.7" diff --git a/lib/ain-dftx/src/types/mod.rs b/lib/ain-dftx/src/types/mod.rs index 2174cd36ce6..69d09799eba 100644 --- a/lib/ain-dftx/src/types/mod.rs +++ b/lib/ain-dftx/src/types/mod.rs @@ -24,6 +24,10 @@ use self::{ }; use crate::custom_tx::CustomTxType; +pub type Token = String; +pub type Currency = String; +pub type Weightage = u8; + #[derive(Debug, PartialEq, Eq)] pub enum DfTx { AccountToAccount(AccountToAccount), diff --git a/lib/ain-ocean/Cargo.toml b/lib/ain-ocean/Cargo.toml index 2743abd2a91..9e105e2428c 100644 --- a/lib/ain-ocean/Cargo.toml +++ b/lib/ain-ocean/Cargo.toml @@ -22,7 +22,6 @@ keccak-hash.workspace = true log.workspace = true serde.workspace = true serde_with.workspace = true -thiserror.workspace = true hex.workspace = true ain-dftx.workspace = true bitcoin = { workspace = true, features = ["serde"] } @@ -32,7 +31,6 @@ json = "0.12.4" futures = "0.3.29" jsonrpsee.workspace = true rocksdb.workspace = true -anyhow.workspace = true cached.workspace = true lazy_static.workspace = true bincode.workspace = true @@ -48,6 +46,7 @@ petgraph = { version = "0.6.4", features = ["serde-1"] } parking_lot.workspace = true indexmap.workspace = true sha2.workspace = true +snafu = { version = "0.8.4" } [dev-dependencies] tempdir.workspace = true diff --git a/lib/ain-ocean/src/api/address.rs b/lib/ain-ocean/src/api/address.rs index 68aa8f27b10..2e3840c8d55 100644 --- a/lib/ain-ocean/src/api/address.rs +++ b/lib/ain-ocean/src/api/address.rs @@ -1,7 +1,6 @@ use std::{collections::BTreeMap, str::FromStr, sync::Arc}; use ain_macros::ocean_endpoint; -use anyhow::Context; use axum::{routing::get, Extension, Router}; use bitcoin::{hashes::Hash, hex::DisplayHex, BlockHash, Txid}; use defichain_rpc::{ @@ -90,7 +89,9 @@ async fn get_account_history( .client .get_account_history(&address, height, txno) .await - .context("Record not found")?; + .map_err(|_| Error::Other { + msg: "Record not found".to_string(), + })?; Ok(Response::new(res.into())) } diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 927985425e8..468e3decad8 100644 --- a/lib/ain-ocean/src/api/block.rs +++ b/lib/ain-ocean/src/api/block.rs @@ -1,7 +1,6 @@ use std::sync::Arc; use ain_macros::ocean_endpoint; -use anyhow::Context; use axum::{routing::get, Extension, Router}; use bitcoin::{BlockHash, Txid}; use rust_decimal::Decimal; @@ -94,7 +93,7 @@ async fn list_blocks( .next .as_ref() .map(|q| { - let height = q.parse::().context("Invalid height")?; + let height = q.parse::()?; Ok::(height) }) .transpose()?; @@ -140,7 +139,7 @@ async fn get_transactions( .next .as_ref() .map_or(Ok(TransactionByBlockHash::initial_key(hash)), |q| { - let height = q.parse::().context("Invalid height")?; + let height: usize = q.parse::()?; Ok::<(BlockHash, usize), Error>((hash, height)) })?; diff --git a/lib/ain-ocean/src/api/common.rs b/lib/ain-ocean/src/api/common.rs index 0d657528739..6b3d1449342 100644 --- a/lib/ain-ocean/src/api/common.rs +++ b/lib/ain-ocean/src/api/common.rs @@ -1,13 +1,20 @@ -use std::str::FromStr; - -use anyhow::Context; +use ain_dftx::{Currency, Token}; use bitcoin::{Address, Network, ScriptBuf}; use defichain_rpc::json::token::TokenInfo; use rust_decimal::Decimal; use rust_decimal_macros::dec; +use snafu::OptionExt; +use std::str::FromStr; use super::query::PaginationQuery; -use crate::hex_encoder::as_sha256; +use crate::{ + error::{ + InvalidAmountSnafu, InvalidFixedIntervalPriceSnafu, InvalidPoolPairSymbolSnafu, + InvalidTokenCurrencySnafu, + }, + hex_encoder::as_sha256, + Result, +}; pub fn parse_display_symbol(token_info: &TokenInfo) -> String { if token_info.is_lps { @@ -36,6 +43,73 @@ pub fn parse_dat_symbol(symbol: &str) -> String { } } +pub fn parse_pool_pair_symbol(item: &str) -> Result<(String, String)> { + let mut parts = item.split('-'); + let a = parts + .next() + .context(InvalidPoolPairSymbolSnafu { item })? + .to_string(); + let b = parts + .next() + .context(InvalidPoolPairSymbolSnafu { item })? + .to_string(); + + Ok((a, b)) +} + +pub fn parse_token_currency(item: &str) -> Result<(Token, Currency)> { + let mut parts = item.split('-'); + let token = parts + .next() + .context(InvalidTokenCurrencySnafu { item })? + .to_string(); + let currency = parts + .next() + .context(InvalidTokenCurrencySnafu { item })? + .to_string(); + + Ok((token, currency)) +} + +pub fn parse_fixed_interval_price(item: &str) -> Result<(Token, Currency)> { + let mut parts = item.split('/'); + let token = parts + .next() + .context(InvalidFixedIntervalPriceSnafu { item })? + .to_string(); + let currency = parts + .next() + .context(InvalidFixedIntervalPriceSnafu { item })? + .to_string(); + + Ok((token, currency)) +} + +pub fn parse_amount(item: &str) -> Result<(String, String)> { + let mut parts = item.split('@'); + let amount = parts + .next() + .context(InvalidAmountSnafu { item })? + .to_string(); + let symbol = parts + .next() + .context(InvalidAmountSnafu { item })? + .to_string(); + + Ok((amount, symbol)) +} + +pub fn parse_query_height_txno(item: &str) -> Result<(u32, usize)> { + let mut parts = item.split('-'); + let height = parts.next().context(InvalidAmountSnafu { item })?; + let txno = parts.next().context(InvalidAmountSnafu { item })?; + + let height = height.parse::()?; + let txno = txno.parse::()?; + + Ok((height, txno)) +} + pub fn format_number(v: Decimal) -> String { if v == dec!(0) { "0".to_string() @@ -44,19 +118,19 @@ pub fn format_number(v: Decimal) -> String { } } -pub fn from_script(script: ScriptBuf, network: Network) -> crate::Result { +pub fn from_script(script: ScriptBuf, network: Network) -> Result { let script = script.as_script(); let address = Address::from_script(script, network)?.to_string(); Ok(address) } -pub fn to_script(address: &str, network: Network) -> crate::Result { +pub fn to_script(address: &str, network: Network) -> Result { let addr = Address::from_str(address)?.require_network(network)?; Ok(ScriptBuf::from(addr)) } -pub fn address_to_hid(address: &str, network: Network) -> crate::Result { - let script = to_script(address, network).context("InvalidDefiAddress")?; +pub fn address_to_hid(address: &str, network: Network) -> Result { + let script = to_script(address, network)?; let bytes = script.to_bytes(); Ok(as_sha256(bytes)) } diff --git a/lib/ain-ocean/src/api/governance.rs b/lib/ain-ocean/src/api/governance.rs index 069c108339b..0529b69c8fc 100644 --- a/lib/ain-ocean/src/api/governance.rs +++ b/lib/ain-ocean/src/api/governance.rs @@ -12,11 +12,7 @@ use super::{ response::{ApiPagedResponse, Response}, AppContext, }; -use crate::{ - error::{ApiError, Error, NotFoundKind}, - model::ApiProposalInfo, - Result, -}; +use crate::{error::ApiError, model::ApiProposalInfo, Result}; #[derive(Deserialize, Default)] pub struct GovernanceQuery { @@ -65,9 +61,7 @@ async fn get_gov_proposal( Extension(ctx): Extension>, Path(proposal_id): Path, ) -> Result> { - let txid: Txid = proposal_id - .parse() - .map_err(|_| Error::NotFound(NotFoundKind::Proposal))?; + let txid: Txid = proposal_id.parse()?; let proposal = ctx.client.get_gov_proposal(txid).await?; Ok(Response::new(proposal.into())) @@ -79,9 +73,7 @@ async fn list_gov_proposal_votes( Query(query): Query, Extension(ctx): Extension>, ) -> Result> { - let proposal_id: Txid = proposal_id - .parse() - .map_err(|_| Error::NotFound(NotFoundKind::Proposal))?; + let proposal_id: Txid = proposal_id.parse()?; let size = match query.all { Some(true) => 0, diff --git a/lib/ain-ocean/src/api/loan.rs b/lib/ain-ocean/src/api/loan.rs index 6f97bb90b28..22673f5c106 100644 --- a/lib/ain-ocean/src/api/loan.rs +++ b/lib/ain-ocean/src/api/loan.rs @@ -1,7 +1,6 @@ use std::{str::FromStr, sync::Arc}; use ain_macros::ocean_endpoint; -use anyhow::{format_err, Context}; use axum::{routing::get, Extension, Router}; use bitcoin::{hashes::Hash, Txid}; use defichain_rpc::{ @@ -19,10 +18,14 @@ use defichain_rpc::{ use futures::future::try_join_all; use log::debug; use serde::{Serialize, Serializer}; +use snafu::OptionExt; use super::{ cache::{get_loan_scheme_cached, get_token_cached}, - common::{from_script, parse_display_symbol, Paginate}, + common::{ + from_script, parse_amount, parse_display_symbol, parse_fixed_interval_price, + parse_query_height_txno, Paginate, + }, path::Path, query::{PaginationQuery, Query}, response::{ApiPagedResponse, Response}, @@ -31,7 +34,7 @@ use super::{ }; use crate::{ api::prices::PriceTickerResponse, - error::{ApiError, Error}, + error::{ApiError, Error, NotFoundKind, NotFoundSnafu}, model::{OraclePriceActive, VaultAuctionBatchHistory}, storage::{RepositoryOps, SecondaryIndex, SortOrder}, Result, @@ -83,9 +86,14 @@ async fn get_scheme( Path(scheme_id): Path, Extension(ctx): Extension>, ) -> Result> { - Ok(Response::new( - ctx.client.get_loan_scheme(scheme_id).await?.into(), - )) + let scheme = ctx + .client + .get_loan_scheme(scheme_id) + .await + .map_err(|_| Error::NotFound { + kind: NotFoundKind::Scheme, + })?; + Ok(Response::new(scheme.into())) } #[derive(Serialize)] @@ -121,15 +129,7 @@ async fn get_active_price( ctx: &Arc, fixed_interval_price_id: String, ) -> Result> { - let mut parts = fixed_interval_price_id.split('/'); - let token = parts - .next() - .context("Invalid fixed interval price id structure")? - .to_string(); - let currency = parts - .next() - .context("Invalid fixed interval price id structure")? - .to_string(); + let (token, currency) = parse_fixed_interval_price(&fixed_interval_price_id)?; let price = ctx.services.price_ticker.by_id.get(&(token, currency))?; let Some(active_price) = price else { @@ -157,7 +157,11 @@ async fn list_collateral_token( .map(|v| async { let (id, info) = get_token_cached(&ctx, &v.token_id) .await? - .context("None is not valid")?; + .context(NotFoundSnafu { + kind: NotFoundKind::Token { + id: v.token_id.clone(), + }, + })?; let active_price = get_active_price(&ctx, v.fixed_interval_price_id.clone()).await?; Ok::(CollateralToken::from_with_id(id, v, info, active_price)) }) @@ -175,10 +179,20 @@ async fn get_collateral_token( Path(token_id): Path, Extension(ctx): Extension>, ) -> Result> { - let collateral_token = ctx.client.get_collateral_token(token_id).await?; + let collateral_token = ctx + .client + .get_collateral_token(token_id) + .await + .map_err(|_| Error::NotFound { + kind: NotFoundKind::CollateralToken, + })?; let (id, info) = get_token_cached(&ctx, &collateral_token.token_id) .await? - .context("None is not valid")?; + .context(NotFoundSnafu { + kind: NotFoundKind::Token { + id: collateral_token.token_id.clone(), + }, + })?; let active_price = get_active_price(&ctx, collateral_token.fixed_interval_price_id.clone()).await?; @@ -234,14 +248,7 @@ async fn list_loan_token( }) .map(|flatten_token| { let fixed_interval_price_id = flatten_token.fixed_interval_price_id.clone(); - let mut parts = fixed_interval_price_id.split('/'); - - let token = parts - .next() - .context("Invalid fixed interval price id structure")?; - let currency = parts - .next() - .context("Invalid fixed interval price id structure")?; + let (token, currency) = parse_fixed_interval_price(&fixed_interval_price_id)?; let repo = &ctx.services.oracle_price_active; let key = repo @@ -274,7 +281,13 @@ async fn get_loan_token( Path(token_id): Path, Extension(ctx): Extension>, ) -> Result> { - let loan_token_result = ctx.client.get_loan_token(token_id.clone()).await?; + let loan_token_result = ctx + .client + .get_loan_token(token_id.clone()) + .await + .map_err(|_| Error::NotFound { + kind: NotFoundKind::LoanToken, + })?; let Some(token) = loan_token_result .token .0 @@ -282,13 +295,7 @@ async fn get_loan_token( .next() .map(|(id, info)| { let fixed_interval_price_id = loan_token_result.fixed_interval_price_id.clone(); - let mut parts = fixed_interval_price_id.split('/'); - let token = parts - .next() - .context("Invalid fixed interval price id structure")?; - let currency = parts - .next() - .context("Invalid fixed interval price id structure")?; + let (token, currency) = parse_fixed_interval_price(&fixed_interval_price_id)?; let repo = &ctx.services.oracle_price_active; let key = repo @@ -310,7 +317,9 @@ async fn get_loan_token( }) .transpose()? else { - return Err(format_err!("Token {:?} does not exist!", token_id).into()); + return Err(Error::NotFound { + kind: NotFoundKind::LoanToken, + }); }; Ok(Response::new(token)) @@ -461,7 +470,13 @@ async fn get_vault( Path(vault_id): Path, Extension(ctx): Extension>, ) -> Result> { - let vault = ctx.client.get_vault(vault_id, Some(false)).await?; + let vault = ctx + .client + .get_vault(vault_id, Some(false)) + .await + .map_err(|_| Error::NotFound { + kind: NotFoundKind::Vault, + })?; let res = match vault { VaultResult::VaultActive(vault) => { VaultResponse::Active(map_vault_active(&ctx, vault).await?) @@ -487,21 +502,12 @@ async fn list_vault_auction_history( let next = query .next .map(|q| { - let parts: Vec<&str> = q.split('-').collect(); - if parts.len() != 2 { - return Err("Invalid query format"); - } - - let height = parts[0].parse::().map_err(|_| "Invalid height")?; - let txno = parts[1].parse::().map_err(|_| "Invalid txno")?; - - Ok((height, txno)) + let (height, txno) = parse_query_height_txno(&q)?; + Ok::<(u32, usize), Error>((height, txno)) }) .transpose()? .unwrap_or_default(); - debug!("next : {:?}", next); - let size = if query.size > 0 { query.size } else { 20 }; let auctions = ctx @@ -525,7 +531,9 @@ async fn list_vault_auction_history( .auction .by_id .get(&id)? - .context("Missing auction index")?; + .context(NotFoundSnafu { + kind: NotFoundKind::Auction, + })?; Ok(auction) }) @@ -643,11 +651,8 @@ async fn map_token_amounts( .into_iter() .map(|amount| { let amount = amount.to_owned(); - let mut parts = amount.split('@'); - - let amount = parts.next().context("Invalid amount structure")?; - let token_symbol = parts.next().context("Invalid amount structure")?; - Ok::<[String; 2], Error>([amount.to_string(), token_symbol.to_string()]) + let (amount, token_symbol) = parse_amount(&amount)?; + Ok::<[String; 2], Error>([amount, token_symbol]) }) .collect::>>()?; diff --git a/lib/ain-ocean/src/api/masternode/mod.rs b/lib/ain-ocean/src/api/masternode/mod.rs index fc0509dded2..d5e15414d2f 100644 --- a/lib/ain-ocean/src/api/masternode/mod.rs +++ b/lib/ain-ocean/src/api/masternode/mod.rs @@ -3,7 +3,6 @@ use std::sync::Arc; mod state; use ain_macros::ocean_endpoint; -use anyhow::Context; use axum::{ extract::{Path, Query}, routing::get, @@ -11,6 +10,7 @@ use axum::{ }; use bitcoin::Txid; use serde::{Deserialize, Serialize}; +use snafu::OptionExt; use self::state::{MasternodeService, MasternodeState}; use super::{ @@ -20,7 +20,7 @@ use super::{ }; use crate::{ api::common::Paginate, - error::{ApiError, Error, NotFoundKind}, + error::{ApiError, Error, NotFoundKind, NotFoundSnafu}, model::Masternode, storage::{RepositoryOps, SortOrder}, Result, SecondaryIndex, @@ -99,8 +99,8 @@ async fn list_masternodes( .next .as_ref() .map(|q| { - let height = q[0..8].parse::().context("Invalid height")?; - let txid = q[8..].parse::().context("Invalid txid")?; + let height = q[0..8].parse::()?; + let txid = q[8..].parse::()?; Ok::<(u32, bitcoin::Txid), Error>((height, txid)) }) @@ -152,7 +152,9 @@ async fn get_masternode( let state = MasternodeService::new(ctx.network).get_masternode_state(&mn, height); MasternodeData::from_with_state(mn, state) }) - .ok_or(Error::NotFound(NotFoundKind::Masternode))?; + .context(NotFoundSnafu { + kind: NotFoundKind::Masternode, + })?; Ok(Response::new(mn)) } diff --git a/lib/ain-ocean/src/api/oracle.rs b/lib/ain-ocean/src/api/oracle.rs index efe4fcc2ac9..793346d607f 100644 --- a/lib/ain-ocean/src/api/oracle.rs +++ b/lib/ain-ocean/src/api/oracle.rs @@ -1,8 +1,7 @@ use std::{str::FromStr, sync::Arc}; -use ain_dftx::COIN; +use ain_dftx::{Currency, Token, COIN}; use ain_macros::ocean_endpoint; -use anyhow::Context; use axum::{ extract::{Path, Query}, routing::get, @@ -13,6 +12,7 @@ use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; use super::{ + common::parse_token_currency, query::PaginationQuery, response::{ApiPagedResponse, Response}, AppContext, @@ -55,8 +55,8 @@ pub struct OraclePriceFeedResponse { pub id: String, pub key: String, pub sort: String, - pub token: String, - pub currency: String, + pub token: Token, + pub currency: Currency, pub oracle_id: Txid, pub txid: Txid, pub time: i32, @@ -72,9 +72,7 @@ async fn get_feed( ) -> Result> { let txid = Txid::from_str(&oracle_id)?; - let mut parts = key.split('-'); - let token = parts.next().context("Missing token")?; - let currency = parts.next().context("Missing currency")?; + let (token, currency) = parse_token_currency(&key)?; let key = (token, currency, txid); diff --git a/lib/ain-ocean/src/api/pool_pair/mod.rs b/lib/ain-ocean/src/api/pool_pair/mod.rs index fd7f1778341..e5fbf011907 100644 --- a/lib/ain-ocean/src/api/pool_pair/mod.rs +++ b/lib/ain-ocean/src/api/pool_pair/mod.rs @@ -4,7 +4,6 @@ use std::{ }; use ain_macros::ocean_endpoint; -use anyhow::Context; use axum::{routing::get, Extension, Router}; use defichain_rpc::{ json::{poolpair::PoolPairInfo, token::TokenInfo}, @@ -25,17 +24,18 @@ use service::{ check_swap_type, find_swap_from, find_swap_to, get_aggregated_in_usd, get_apr, get_total_liquidity_usd, get_usd_volume, PoolPairVolumeResponse, PoolSwapFromToData, SwapType, }; +use snafu::OptionExt; use super::{ cache::{get_pool_pair_cached, get_token_cached, list_pool_pairs_cached}, - common::parse_dat_symbol, + common::{parse_dat_symbol, parse_pool_pair_symbol, parse_query_height_txno}, path::Path, query::{PaginationQuery, Query}, response::{ApiPagedResponse, Response}, AppContext, }; use crate::{ - error::{ApiError, Error, NotFoundKind}, + error::{ApiError, Error, NotFoundKind, NotFoundSnafu}, model::{BlockContext, PoolSwap, PoolSwapAggregated}, storage::{InitialKeyProvider, RepositoryOps, SecondaryIndex, SortOrder}, PoolSwap as PoolSwapRepository, Result, TokenIdentifier, @@ -45,11 +45,6 @@ pub mod path; pub mod price; pub mod service; -// #[derive(Deserialize)] -// struct PoolPair { -// id: String, -// } - #[derive(Deserialize)] struct SwapAggregate { id: String, @@ -207,12 +202,9 @@ impl PoolPairResponse { apr: PoolPairAprResponse, volume: PoolPairVolumeResponse, ) -> Result { - let mut parts = p.symbol.split('-'); - let a = parts.next().context("Missing symbol a")?; - let b = parts.next().context("Missing symbol b")?; - - let a_parsed = parse_dat_symbol(a); - let b_parsed = parse_dat_symbol(b); + let (a, b) = parse_pool_pair_symbol(&p.symbol)?; + let a_parsed = parse_dat_symbol(&a); + let b_parsed = parse_dat_symbol(&b); Ok(Self { id, @@ -270,6 +262,52 @@ impl PoolPairResponse { } } +async fn map_pool_pair_response( + ctx: &Arc, + id: String, + p: PoolPairInfo, +) -> Result { + let ( + _, + TokenInfo { + name: a_token_name, .. + }, + ) = get_token_cached(ctx, &p.id_token_a) + .await? + .context(NotFoundSnafu { + kind: NotFoundKind::Token { + id: p.id_token_a.clone(), + }, + })?; + let ( + _, + TokenInfo { + name: b_token_name, .. + }, + ) = get_token_cached(ctx, &p.id_token_b) + .await? + .context(NotFoundSnafu { + kind: NotFoundKind::Token { + id: p.id_token_b.clone(), + }, + })?; + + let total_liquidity_usd = get_total_liquidity_usd(ctx, &p).await?; + let apr = get_apr(ctx, &id, &p).await?; + let volume = get_usd_volume(ctx, &id).await?; + let res = PoolPairResponse::from_with_id( + id, + p, + a_token_name, + b_token_name, + total_liquidity_usd, + apr, + volume, + )?; + + Ok(res) +} + #[ocean_endpoint] async fn list_pool_pairs( Query(query): Query, @@ -300,35 +338,7 @@ async fn list_pool_pairs( .into_iter() .filter(|(_, p)| !p.symbol.starts_with("BURN-")) .map(|(id, p)| async { - let ( - _, - TokenInfo { - name: a_token_name, .. - }, - ) = get_token_cached(&ctx, &p.id_token_a) - .await? - .context("None is not valid")?; - let ( - _, - TokenInfo { - name: b_token_name, .. - }, - ) = get_token_cached(&ctx, &p.id_token_b) - .await? - .context("None is not valid")?; - - let total_liquidity_usd = get_total_liquidity_usd(&ctx, &p).await?; - let apr = get_apr(&ctx, &id, &p).await?; - let volume = get_usd_volume(&ctx, &id).await?; - let res = PoolPairResponse::from_with_id( - id, - p, - a_token_name, - b_token_name, - total_liquidity_usd, - apr, - volume, - )?; + let res = map_pool_pair_response(&ctx, id, p).await?; Ok::(res) }) .collect::>(); @@ -345,39 +355,14 @@ async fn get_pool_pair( Path(id): Path, Extension(ctx): Extension>, ) -> Result>> { - if let Some((id, pool)) = get_pool_pair_cached(&ctx, id).await? { - let total_liquidity_usd = get_total_liquidity_usd(&ctx, &pool).await?; - let apr = get_apr(&ctx, &id, &pool).await?; - let volume = get_usd_volume(&ctx, &id).await?; - let ( - _, - TokenInfo { - name: a_token_name, .. - }, - ) = get_token_cached(&ctx, &pool.id_token_a) - .await? - .context("None is not valid")?; - let ( - _, - TokenInfo { - name: b_token_name, .. - }, - ) = get_token_cached(&ctx, &pool.id_token_b) - .await? - .context("None is not valid")?; - let res = PoolPairResponse::from_with_id( - id, - pool, - a_token_name, - b_token_name, - total_liquidity_usd, - apr, - volume, - )?; + if let Some((id, p)) = get_pool_pair_cached(&ctx, id).await? { + let res = map_pool_pair_response(&ctx, id, p).await?; return Ok(Response::new(Some(res))); }; - Err(Error::NotFound(NotFoundKind::PoolPair)) + Err(Error::NotFound { + kind: NotFoundKind::PoolPair, + }) } #[ocean_endpoint] @@ -390,15 +375,8 @@ async fn list_pool_swaps( .next .as_ref() .map(|q| { - let parts: Vec<&str> = q.split('-').collect(); - if parts.len() != 2 { - return Err("Invalid query format"); - } - - let height = parts[0].parse::().map_err(|_| "Invalid height")?; - let txno = parts[1].parse::().map_err(|_| "Invalid txno")?; - - Ok((id, height, txno)) + let (height, txno) = parse_query_height_txno(q)?; + Ok::<(u32, u32, usize), Error>((id, height, txno)) }) .transpose()? .unwrap_or(PoolSwapRepository::initial_key(id)); @@ -436,15 +414,8 @@ async fn list_pool_swaps_verbose( .next .as_ref() .map(|q| { - let parts: Vec<&str> = q.split('-').collect(); - if parts.len() != 2 { - return Err("Invalid query format"); - } - - let height = parts[0].parse::().map_err(|_| "Invalid height")?; - let txno = parts[1].parse::().map_err(|_| "Invalid txno")?; - - Ok((id, height, txno)) + let (height, txno) = parse_query_height_txno(q)?; + Ok::<(u32, u32, usize), Error>((id, height, txno)) }) .transpose()? .unwrap_or(PoolSwapRepository::initial_key(id)); diff --git a/lib/ain-ocean/src/api/pool_pair/path.rs b/lib/ain-ocean/src/api/pool_pair/path.rs index d4fcd898820..39dd5000508 100644 --- a/lib/ain-ocean/src/api/pool_pair/path.rs +++ b/lib/ain-ocean/src/api/pool_pair/path.rs @@ -1,10 +1,10 @@ use std::{collections::HashSet, str::FromStr, sync::Arc, time::Duration}; -use anyhow::{format_err, Context}; use defichain_rpc::json::poolpair::PoolPairInfo; use rust_decimal::{prelude::FromPrimitive, Decimal}; use rust_decimal_macros::dec; use serde::Serialize; +use snafu::OptionExt; use super::AppContext; use crate::{ @@ -12,7 +12,9 @@ use crate::{ cache::{get_pool_pair_cached, get_token_cached, list_pool_pairs_cached}, common::{format_number, parse_dat_symbol}, }, - error::NotFoundKind, + error::{ + ArithmeticOverflowSnafu, ArithmeticUnderflowSnafu, NotFoundKind, NotFoundSnafu, OtherSnafu, + }, network::Network, Error, Result, TokenIdentifier, }; @@ -106,9 +108,9 @@ impl StackSet { } pub async fn get_token_identifier(ctx: &Arc, id: &str) -> Result { - let (id, token) = get_token_cached(ctx, id) - .await? - .ok_or(Error::NotFound(NotFoundKind::Token))?; + let (id, token) = get_token_cached(ctx, id).await?.context(NotFoundSnafu { + kind: NotFoundKind::Token { id: id.to_string() }, + })?; Ok(TokenIdentifier { id, display_symbol: parse_dat_symbol(&token.symbol), @@ -125,7 +127,9 @@ pub async fn get_all_swap_paths( sync_token_graph_if_empty(ctx).await?; if from_token_id == to_token_id { - return Err(format_err!("Invalid tokens: fromToken must be different from toToken").into()); + return Err(Error::Other { + msg: "Invalid tokens: fromToken must be different from toToken".to_string(), + }); } let mut res = SwapPathsResponse { @@ -167,8 +171,10 @@ pub struct BestSwapPathResponse { pub from_token: TokenIdentifier, pub to_token: TokenIdentifier, pub best_path: Vec, - pub estimated_return: String, - pub estimated_return_less_dex_fees: String, + #[serde(with = "rust_decimal::serde::str")] + pub estimated_return: Decimal, + #[serde(with = "rust_decimal::serde::str")] + pub estimated_return_less_dex_fees: Decimal, } pub async fn get_best_path( @@ -198,8 +204,8 @@ pub async fn get_best_path( from_token, to_token, best_path: path, - estimated_return: format_number(estimated_return), - estimated_return_less_dex_fees: format_number(estimated_return_less_dex_fees), + estimated_return: estimated_return.round_dp(8), + estimated_return_less_dex_fees: estimated_return_less_dex_fees.round_dp(8), }); }; @@ -217,8 +223,8 @@ pub async fn get_best_path( from_token, to_token, best_path, - estimated_return: format_number(best_return), - estimated_return_less_dex_fees: format_number(best_return_less_dex_fees), + estimated_return: best_return.round_dp(8), + estimated_return_less_dex_fees: best_return_less_dex_fees.round_dp(8), }) } @@ -232,10 +238,14 @@ fn all_simple_paths( let graph = &ctx.services.token_graph; if !graph.lock().contains_node(from_token_id) { - return Err(format_err!("from_token_id not found: {:?}", from_token_id).into()); + return Err(Error::Other { + msg: format!("from_token_id not found: {:?}", from_token_id), + }); } if !graph.lock().contains_node(to_token_id) { - return Err(format_err!("to_token_id not found: {:?}", to_token_id).into()); + return Err(Error::Other { + msg: format!("to_token_id not found: {:?}", to_token_id), + }); } let is_cycle = from_token_id == to_token_id; @@ -352,8 +362,8 @@ pub async fn compute_paths_between_tokens( let pool_pair_id = graph .lock() .edge_weight(token_a, token_b) - .ok_or_else(|| { - format_err!( + .context(OtherSnafu { + msg: format!( "Unexpected error encountered during path finding - could not find edge between {} and {}", token_a, token_b @@ -363,7 +373,9 @@ pub async fn compute_paths_between_tokens( let Some((_, pool_pair_info)) = get_pool_pair_cached(ctx, pool_pair_id.clone()).await? else { - return Err(format_err!("Pool pair by id {pool_pair_id} not found").into()); + return Err(Error::Other { + msg: format!("Pool pair by id {pool_pair_id} not found"), + }); }; let estimated_dex_fees_in_pct = @@ -442,40 +454,40 @@ pub async fn compute_return_less_dex_fees_in_destination_token( estimated_return = estimated_return .checked_mul(price_ratio) - .context("estimated_return overflow")?; + .context(ArithmeticOverflowSnafu)?; // less commission fee let commission_fee_in_pct = Decimal::from_str(pool.commission_fee_in_pct.as_str())?; let commission_fee = estimated_return_less_dex_fees .checked_mul(commission_fee_in_pct) - .context("commission_fee overflow")?; + .context(ArithmeticOverflowSnafu)?; estimated_return_less_dex_fees = estimated_return_less_dex_fees .checked_sub(commission_fee) - .context("estimated_return_less_dex_fees underflow")?; + .context(ArithmeticUnderflowSnafu)?; // less dex fee from_token let from_token_estimated_dex_fee = from_token_fee_pct .unwrap_or_default() .checked_mul(estimated_return_less_dex_fees) - .context("from_token_fee_pct overflow")?; + .context(ArithmeticOverflowSnafu)?; estimated_return_less_dex_fees = estimated_return_less_dex_fees .checked_sub(from_token_estimated_dex_fee) - .context("estimated_return_less_dex_fees underflow")?; + .context(ArithmeticUnderflowSnafu)?; // convert to to_token let from_token_estimated_return_less_dex_fee = estimated_return_less_dex_fees .checked_mul(price_ratio) - .context("from_token_estimated_return_less_dex_fee overflow")?; + .context(ArithmeticOverflowSnafu)?; let to_token_estimated_dex_fee = to_token_fee_pct .unwrap_or_default() .checked_mul(from_token_estimated_return_less_dex_fee) - .context("to_token_estimated_dex_fee overflow")?; + .context(ArithmeticOverflowSnafu)?; // less dex fee to_token estimated_return_less_dex_fees = from_token_estimated_return_less_dex_fee .checked_sub(to_token_estimated_dex_fee) - .context("estimated_return_less_dex_fees underflow")?; + .context(ArithmeticUnderflowSnafu)?; } Ok(EstimatedLessDexFeeInfo { diff --git a/lib/ain-ocean/src/api/pool_pair/price.rs b/lib/ain-ocean/src/api/pool_pair/price.rs index baad1bad90c..e2e70d87e46 100644 --- a/lib/ain-ocean/src/api/pool_pair/price.rs +++ b/lib/ain-ocean/src/api/pool_pair/price.rs @@ -1,7 +1,9 @@ use std::{collections::HashMap, sync::Arc}; use defichain_rpc::json::token::TokenInfo; +use rust_decimal::Decimal; use serde::Serialize; +use snafu::OptionExt; use super::{path::get_best_path, AppContext}; use crate::{ @@ -9,7 +11,7 @@ use crate::{ cache::{get_token_cached, list_tokens_cached}, common::parse_display_symbol, }, - error::{Error, NotFoundKind}, + error::{Error, NotFoundKind, NotFoundSnafu}, Result, TokenIdentifier, }; @@ -17,7 +19,8 @@ use crate::{ #[serde(rename_all = "camelCase")] pub struct DexPrice { pub token: TokenIdentifier, - pub denomination_price: String, + #[serde(with = "rust_decimal::serde::str")] + pub denomination_price: Decimal, } #[derive(Clone, Debug, Serialize, Eq, PartialEq)] @@ -34,10 +37,17 @@ fn is_untradable_token(token: &TokenInfo) -> bool { pub async fn list_dex_prices(ctx: &Arc, symbol: String) -> Result { let (denomination_token_id, denomination_token_info) = get_token_cached(ctx, &symbol) .await? - .ok_or(Error::NotFound(NotFoundKind::Token))?; + .context(NotFoundSnafu { + kind: NotFoundKind::Token { id: symbol }, + })?; if is_untradable_token(&denomination_token_info) { - return Err(Error::UntradeableTokenError(denomination_token_info.symbol)); + return Err(Error::Other { + msg: format!( + "Token \"{}\" is invalid as it is not tradeable", + denomination_token_info.symbol + ), + }); }; let tokens = list_tokens_cached(ctx) diff --git a/lib/ain-ocean/src/api/pool_pair/service.rs b/lib/ain-ocean/src/api/pool_pair/service.rs index c7202083a5f..525d41f9d2d 100644 --- a/lib/ain-ocean/src/api/pool_pair/service.rs +++ b/lib/ain-ocean/src/api/pool_pair/service.rs @@ -1,21 +1,24 @@ use std::{collections::HashMap, str::FromStr, sync::Arc}; use ain_dftx::{deserialize, pool::CompositeSwap, DfTx, Stack}; -use anyhow::{format_err, Context}; use bitcoin::Txid; use defichain_rpc::{json::poolpair::PoolPairInfo, AccountRPC, BlockchainRPC}; use rust_decimal::{prelude::FromPrimitive, Decimal}; use rust_decimal_macros::dec; use serde::{Deserialize, Serialize}; +use snafu::OptionExt; use super::{AppContext, PoolPairAprResponse}; use crate::{ api::{ cache::{get_gov_cached, get_pool_pair_cached, get_token_cached}, - common::{from_script, parse_display_symbol}, + common::{from_script, parse_amount, parse_display_symbol, parse_pool_pair_symbol}, pool_pair::path::{get_best_path, BestSwapPathResponse}, }, - error::{Error, NotFoundKind}, + error::{ + ArithmeticOverflowSnafu, ArithmeticUnderflowSnafu, DecimalConversionSnafu, NotFoundKind, + NotFoundSnafu, OtherSnafu, + }, indexer::PoolSwapAggregatedInterval, model::{BlockContext, PoolSwapAggregatedAggregated}, storage::{RepositoryOps, SecondaryIndex, SortOrder}, @@ -69,17 +72,17 @@ pub async fn get_usd_per_dfi(ctx: &Arc) -> Result { if p.id_token_a == "0" { total_usd = total_usd .checked_add(reserve_b) - .ok_or_else(|| Error::OverflowError)?; + .context(ArithmeticOverflowSnafu)?; total_dfi = total_dfi .checked_add(reserve_a) - .ok_or_else(|| Error::OverflowError)?; + .context(ArithmeticOverflowSnafu)?; } else if p.id_token_b == "0" { total_usd = total_usd .checked_add(reserve_a) - .ok_or_else(|| Error::OverflowError)?; + .context(ArithmeticOverflowSnafu)?; total_dfi = total_dfi .checked_add(reserve_b) - .ok_or_else(|| Error::OverflowError)?; + .context(ArithmeticOverflowSnafu)?; } Ok((total_usd, total_dfi)) } @@ -95,7 +98,7 @@ pub async fn get_usd_per_dfi(ctx: &Arc) -> Result { if !total_usd.is_zero() { let res = total_usd .checked_div(total_dfi) - .ok_or_else(|| Error::UnderflowError)?; + .context(ArithmeticUnderflowSnafu)?; return Ok(res); }; @@ -117,14 +120,14 @@ async fn get_total_liquidity_usd_by_best_path( let BestSwapPathResponse { estimated_return, .. } = get_best_path(ctx, &p.id_token_a, &usdt_id).await?; - a_token_rate = Decimal::from_str(estimated_return.as_str())?; + a_token_rate = estimated_return; } if p.id_token_a != usdt_id { let BestSwapPathResponse { estimated_return, .. } = get_best_path(ctx, &p.id_token_b, &usdt_id).await?; - b_token_rate = Decimal::from_str(estimated_return.as_str())?; + b_token_rate = estimated_return; } let reserve_a = Decimal::from_f64(p.reserve_a).unwrap_or_default(); @@ -132,35 +135,33 @@ async fn get_total_liquidity_usd_by_best_path( let a = a_token_rate .checked_mul(reserve_a) - .ok_or_else(|| Error::OverflowError)?; + .context(ArithmeticOverflowSnafu)?; let b = b_token_rate .checked_mul(reserve_b) - .ok_or_else(|| Error::OverflowError)?; + .context(ArithmeticOverflowSnafu)?; - let res = a.checked_add(b).ok_or_else(|| Error::OverflowError)?; + let res = a.checked_add(b).context(ArithmeticOverflowSnafu)?; Ok(res) } pub async fn get_total_liquidity_usd(ctx: &Arc, p: &PoolPairInfo) -> Result { - let mut parts = p.symbol.split('-'); - let a = parts.next().context("Missing symbol a")?; - let b = parts.next().context("Missing symbol b")?; + let (a, b) = parse_pool_pair_symbol(&p.symbol)?; let reserve_a = Decimal::from_f64(p.reserve_a).unwrap_or_default(); let reserve_b = Decimal::from_f64(p.reserve_b).unwrap_or_default(); - if ["DUSD", "USDT", "USDC"].contains(&a) { + if ["DUSD", "USDT", "USDC"].contains(&a.as_str()) { return reserve_a .checked_mul(dec!(2)) - .ok_or_else(|| Error::OverflowError); + .context(ArithmeticOverflowSnafu); }; - if ["DUSD", "USDT", "USDC"].contains(&b) { + if ["DUSD", "USDT", "USDC"].contains(&b.as_str()) { return reserve_b .checked_mul(dec!(2)) - .ok_or_else(|| Error::OverflowError); + .context(ArithmeticOverflowSnafu); }; let usdt_per_dfi = get_usd_per_dfi(ctx).await?; @@ -171,17 +172,17 @@ pub async fn get_total_liquidity_usd(ctx: &Arc, p: &PoolPairInfo) -> if a == "DFI" { return reserve_a .checked_mul(dec!(2)) - .ok_or_else(|| Error::OverflowError)? + .context(ArithmeticOverflowSnafu)? .checked_mul(usdt_per_dfi) - .ok_or_else(|| Error::OverflowError); + .context(ArithmeticOverflowSnafu); }; if b == "DFI" { return reserve_b .checked_mul(dec!(2)) - .ok_or_else(|| Error::OverflowError)? + .context(ArithmeticOverflowSnafu)? .checked_mul(usdt_per_dfi) - .ok_or_else(|| Error::OverflowError); + .context(ArithmeticOverflowSnafu); }; let res = get_total_liquidity_usd_by_best_path(ctx, p).await?; @@ -190,23 +191,20 @@ pub async fn get_total_liquidity_usd(ctx: &Arc, p: &PoolPairInfo) -> fn calculate_rewards(accounts: &[String], dfi_price_usdt: Decimal) -> Result { let rewards = accounts.iter().try_fold(dec!(0), |accumulate, account| { - let mut parts = account.split('@'); - let amount = parts.next().context("Invalid amount structure")?; - let token = parts.next().context("Invalid amount structure")?; + let (amount, token) = parse_amount(account)?; if token != "0" && token != "DFI" { return Ok(accumulate); } - let yearly = Decimal::from_str(amount) - .context("convert numeric string to number")? + let yearly = Decimal::from_str(&amount)? .checked_mul(dec!(2880)) .and_then(|v| v.checked_mul(dec!(365))) .and_then(|v| v.checked_mul(dfi_price_usdt)) - .context("yearly reward overflow")?; + .context(ArithmeticOverflowSnafu)?; accumulate .checked_add(yearly) - .context("accumlate reward overflow") + .context(ArithmeticOverflowSnafu) })?; Ok(rewards) } @@ -234,8 +232,7 @@ async fn get_daily_dfi_reward(ctx: &Arc) -> Result { .and_then(|v| v.as_f64()) // eg: { "LP_DAILY_DFI_REWARD": 3664.80000000 } .unwrap_or_default(); - let daily_dfi_reward = - Decimal::from_f64(reward).ok_or_else(|| Error::DecimalConversionError)?; + let daily_dfi_reward = Decimal::from_f64(reward).context(DecimalConversionSnafu)?; Ok(daily_dfi_reward) } @@ -258,41 +255,40 @@ async fn get_yearly_reward_pct_usd(ctx: &Arc, p: &PoolPairInfo) -> R let reward_pct = Decimal::from_f64(p.reward_pct).unwrap_or_default(); reward_pct .checked_mul(daily_dfi_reward) - .ok_or_else(|| Error::OverflowError)? + .context(ArithmeticOverflowSnafu)? .checked_mul(dec!(365)) - .ok_or_else(|| Error::OverflowError)? + .context(ArithmeticOverflowSnafu)? .checked_mul(dfi_price_usd) - .ok_or_else(|| Error::OverflowError) + .context(ArithmeticOverflowSnafu) } async fn get_block_subsidy(eunos_height: u32, height: u32) -> Result { - let eunos_height = - Decimal::from_u32(eunos_height).ok_or_else(|| Error::DecimalConversionError)?; - let height = Decimal::from_u32(height).ok_or_else(|| Error::DecimalConversionError)?; + let eunos_height = Decimal::from_u32(eunos_height).context(DecimalConversionSnafu)?; + let height = Decimal::from_u32(height).context(DecimalConversionSnafu)?; let mut block_subsidy = dec!(405.04); if height >= eunos_height { let reduction_amount = dec!(0.01658); // 1.658% let mut reductions = height .checked_sub(eunos_height) - .ok_or_else(|| Error::UnderflowError)? + .context(ArithmeticUnderflowSnafu)? .checked_div(dec!(32690)) - .ok_or_else(|| Error::UnderflowError)? + .context(ArithmeticUnderflowSnafu)? .floor(); while reductions >= dec!(0) { let amount = reduction_amount .checked_mul(block_subsidy) - .ok_or_else(|| Error::OverflowError)?; + .context(ArithmeticOverflowSnafu)?; if amount <= dec!(0.00001) { return Ok(dec!(0)); }; block_subsidy = block_subsidy .checked_sub(amount) - .ok_or_else(|| Error::UnderflowError)?; + .context(ArithmeticUnderflowSnafu)?; reductions = reductions .checked_sub(dec!(1)) - .ok_or_else(|| Error::UnderflowError)?; + .context(ArithmeticUnderflowSnafu)?; } }; @@ -306,7 +302,9 @@ async fn get_loan_emission(ctx: &Arc) -> Result { .softforks .get("eunos") .and_then(|eunos| eunos.height) - .ok_or_else(|| format_err!("BlockchainInfo eunos height field is missing"))?; + .context(OtherSnafu { + msg: "BlockchainInfo eunos height field is missing", + })?; get_block_subsidy(eunos_height, info.blocks).await } @@ -319,7 +317,7 @@ async fn get_yearly_reward_loan_usd(ctx: &Arc, id: &String) -> Resul .and_then(|obj| obj.get(id)) .and_then(|v| v.as_f64()) .unwrap_or_default(); - let split = Decimal::from_f64(split).ok_or_else(|| Error::DecimalConversionError)?; + let split = Decimal::from_f64(split).context(DecimalConversionSnafu)?; let dfi_price_usd = get_usd_per_dfi(ctx).await?; @@ -327,13 +325,13 @@ async fn get_yearly_reward_loan_usd(ctx: &Arc, id: &String) -> Resul loan_emission .checked_mul(split) // 60 * 60 * 24 / 30, 30 seconds = 1 block - .ok_or_else(|| Error::OverflowError)? + .context(ArithmeticOverflowSnafu)? .checked_mul(dec!(2880)) // 60 * 60 * 24 / 30, 30 seconds = 1 block - .ok_or_else(|| Error::OverflowError)? + .context(ArithmeticOverflowSnafu)? .checked_mul(dec!(365)) // 60 * 60 * 24 / 30, 30 seconds = 1 block - .ok_or_else(|| Error::OverflowError)? + .context(ArithmeticOverflowSnafu)? .checked_mul(dfi_price_usd) // 60 * 60 * 24 / 30, 30 seconds = 1 block - .ok_or_else(|| Error::OverflowError) + .context(ArithmeticOverflowSnafu) } async fn gather_amount( @@ -371,7 +369,7 @@ async fn gather_amount( let amount = if let Some(amount) = aggregated.get(token_id) { amount .checked_add(from_amount) - .ok_or(Error::OverflowError)? + .context(ArithmeticOverflowSnafu)? } else { from_amount }; @@ -389,9 +387,9 @@ async fn gather_amount( .checked_add( token_price .checked_mul(amount) - .ok_or(Error::OverflowError)?, + .context(ArithmeticOverflowSnafu)?, ) - .ok_or(Error::OverflowError)?; + .context(ArithmeticOverflowSnafu)?; } Ok(volume) @@ -415,9 +413,9 @@ async fn get_yearly_commission_estimate( let commission = Decimal::from_f64(p.commission).unwrap_or_default(); commission .checked_mul(volume.h24) - .ok_or_else(|| Error::OverflowError)? + .context(ArithmeticOverflowSnafu)? .checked_mul(dec!(365)) - .ok_or_else(|| Error::OverflowError) + .context(ArithmeticOverflowSnafu) } pub async fn get_apr( @@ -432,9 +430,9 @@ pub async fn get_apr( let yearly_usd = custom_usd .checked_add(pct_usd) - .ok_or_else(|| Error::OverflowError)? + .context(ArithmeticOverflowSnafu)? .checked_add(loan_usd) - .ok_or_else(|| Error::OverflowError)?; + .context(ArithmeticOverflowSnafu)?; if yearly_usd.is_zero() { return Ok(PoolPairAprResponse::default()); @@ -443,16 +441,16 @@ pub async fn get_apr( // 1 == 100%, 0.1 = 10% let reward = yearly_usd .checked_div(total_liquidity_usd) - .ok_or_else(|| Error::UnderflowError)?; + .context(ArithmeticUnderflowSnafu)?; let yearly_commission = get_yearly_commission_estimate(ctx, id, p).await?; let commission = yearly_commission .checked_div(total_liquidity_usd) - .ok_or_else(|| Error::UnderflowError)?; + .context(ArithmeticUnderflowSnafu)?; let total = reward .checked_add(commission) - .ok_or_else(|| Error::OverflowError)?; + .context(ArithmeticOverflowSnafu)?; Ok(PoolPairAprResponse { reward, @@ -478,7 +476,11 @@ async fn get_pool_pair(ctx: &Arc, a: &str, b: &str) -> Result