diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 101b2ba32f..c1703522ea 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", @@ -212,15 +212,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]] @@ -622,7 +636,7 @@ dependencies = [ "bech32", "bitcoin-internals", "bitcoin-io", - "bitcoin_hashes", + "bitcoin_hashes 0.13.0", "hex-conservative", "hex_lit", "secp256k1 0.28.0", @@ -639,6 +653,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" @@ -1008,6 +1037,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" @@ -1089,6 +1128,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" @@ -2547,6 +2596,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" @@ -2555,8 +2610,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", ] @@ -2572,6 +2627,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" @@ -2617,6 +2687,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" @@ -2655,6 +2748,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" @@ -2668,6 +2781,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" @@ -2690,6 +2816,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" @@ -2718,6 +2867,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" @@ -2870,6 +3033,7 @@ dependencies = [ "glob", "libc", "libz-sys", + "lz4-sys", "zstd-sys", ] @@ -2978,6 +3142,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" @@ -3174,6 +3348,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" @@ -3378,6 +3563,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" @@ -4155,6 +4383,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" @@ -4417,7 +4651,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", ] @@ -4662,6 +4896,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" @@ -4979,7 +5222,7 @@ dependencies = [ "sp-std", "tracing", "tracing-core", - "tracing-subscriber", + "tracing-subscriber 0.2.25", ] [[package]] @@ -5269,6 +5512,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" @@ -5443,7 +5721,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", @@ -5480,6 +5760,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" @@ -5502,6 +5794,7 @@ dependencies = [ "futures-io", "futures-sink", "pin-project-lite", + "slab", "tokio", "tracing", ] @@ -5681,6 +5974,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" @@ -5713,6 +6019,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 0167a8398d..d25737a1d7 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 917309aa17..39e5255d6e 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 2c81ce4662..b645cdc5bd 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 00f5eda18d..d3ee93c5b9 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 ea3c5b49e1..a695e522ca 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 0000000000..e69de29bb2 diff --git a/lib/ain-ocean/src/api/block.rs b/lib/ain-ocean/src/api/block.rs index 142d379dce..80c8191b90 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 83ac978df9..24a877707f 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 0000000000..200fd033f7 --- /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 0000000000..918a51ff0c --- /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 0000000000..1ab26b4587 --- /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 0000000000..4072333a14 --- /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 0000000000..8bee24254b --- /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 0000000000..a16719eebe --- /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 0000000000..109b44ed5f --- /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 0000000000..f920f9b7d8 --- /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 0000000000..abe2f673fa --- /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 0000000000..f61078f527 --- /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 0000000000..45f756f410 --- /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 0000000000..e1987dde9b --- /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 0000000000..f859fc80f5 --- /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 0000000000..fcdc9985fd --- /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 0000000000..0b630ff016 --- /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 0000000000..e414384ac4 --- /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 0000000000..bd9b68cbdc --- /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 0000000000..234388a782 --- /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 0000000000..f835b40e3e --- /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 0000000000..e16701aa77 --- /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 0000000000..1aae77ab1f --- /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 0000000000..145e68b282 --- /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 0000000000..7d038be647 --- /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 0000000000..39d2fa1504 --- /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 0000000000..bdf9b85192 --- /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 0000000000..8131a626ed --- /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 0000000000..cec892297a --- /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 7064679280..1a037199cc 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 5d7ebdbaf2..547943eaaa 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 fc6ea91318..55517511da 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 8db6749492..27f1608dca 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 b3060c4f2a..f037629517 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 fe3b35df4c..97befdd9c7 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 c1155124f4..0bce2e20a6 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 4289fe0157..d3d7a77641 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 c948a9c7b4..57e16f7b06 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 6f9729fb41..867e0030d3 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 122b99bf97..74fd34d576 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 e4b431301d..a814083e9b 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 f6dd97ebd2..777d7e3a3f 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 90afba7ae2..3e997e3302 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 a9a334c4f2..509350976e 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 3569073e51..6219bae7c2 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 6440f457c3..bed279a82c 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 e0a6b838b1..1345920cc5 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 eecbfbdecf..1c7787247b 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 3edcb78a8a..911c2d22b8 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 14081d06ff..f3317ec5ca 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 1ba65ebf98..6e91cf07ab 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 b2f9cae2bc..614e96a41c 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/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index 077d10102b..93fae52729 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -75,6 +75,7 @@ pub mod ffi { } // ========= FFI ========== + // ========= Core ========== pub struct CrossBoundaryResult { pub ok: bool, pub reason: String, diff --git a/make.sh b/make.sh index 832873a696..3e32a94d8d 100755 --- a/make.sh +++ b/make.sh @@ -224,7 +224,7 @@ package() { local pkg_path if [[ "$target" == "x86_64-w64-mingw32" ]]; then pkg_path="$(_canonicalize "${build_dir}/${pkg_name}.zip")" - else + else pkg_path="$(_canonicalize "${build_dir}/${pkg_name}.tar.gz")" fi @@ -403,11 +403,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 } @@ -452,7 +452,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; } } @@ -491,19 +491,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 | \ @@ -1059,9 +1059,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 } @@ -1193,11 +1193,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 bdf2543634..5416154d2f 100644 --- a/src/dfi/validation.cpp +++ b/src/dfi/validation.cpp @@ -2857,7 +2857,6 @@ void ProcessDeFiEvent(const CBlock &block, // construct undo FlushCacheCreateUndo(pindex, mnview, cache, uint256()); - // Ocean archive const auto oceanArchive{true}; if (oceanArchive) {